summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Markuze <amarkuze@redhat.com>2026-08-24 18:50:03 +0000
committerIlya Dryomov <idryomov@gmail.com>2026-10-26 14:15:47 +0100
commit00a0d7f377f6af59bc559b2e07dffff63eaa5544 (patch)
tree8b3053a7a9e75f3a18afb2382ecf770bd1f63a98
parent6ce5143eea0566512923591a4a3cb0872ee42e4d (diff)
downloadlinux-00a0d7f377f6af59bc559b2e07dffff63eaa5544.tar.gz
linux-00a0d7f377f6af59bc559b2e07dffff63eaa5544.zip
ceph: fix page vector leak on encrypted netfs read EIO path
ceph_netfs_issue_read() pins pages with iov_iter_get_pages_alloc2() for encrypted inodes and attaches them with own_pages=false. If ceph_inc_osd_stopping_blocker() then fails, the request is dropped without calling finish_netfs_read(), so the page array and the references taken on those pages leak: ceph_osd_data_release() only frees pages when own_pages is true, and __free_pages() would be the wrong destructor for GUP-pinned pages. Release the vector with put_page() and kvfree() on that error path, matching finish_netfs_read(). Unencrypted ITER reads are unaffected. Fixes: 1464de9f813e ("ceph: wait for OSD requests' callbacks to finish when unmounting") Signed-off-by: Alex Markuze <amarkuze@redhat.com> Reviewed-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r--fs/ceph/addr.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 31a3175fdd7a..cd6f0f578ead 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -450,6 +450,17 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
osd_req_op_extent_osd_iter(req, 0, &subreq->io_iter);
}
if (!ceph_inc_osd_stopping_blocker(fsc->mdsc)) {
+ struct ceph_osd_data *osd_data =
+ osd_req_op_extent_osd_data(req, 0);
+
+ if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGES) {
+ int num_pages = calc_pages_for(osd_data->alignment,
+ osd_data->length);
+
+ for (int i = 0; i < num_pages; i++)
+ put_page(osd_data->pages[i]);
+ kvfree(osd_data->pages);
+ }
err = -EIO;
goto out;
}