[PATCH v1 2/7] nfs: Track number of pinned pages in nfs_page
From: Pranjal Shrivastava
Date: Wed Jun 03 2026 - 01:32:00 EST
Track the number of pinned pages in nfs_page to handle unpinning
correctly, ensuring that only primary requests perform the final
unpinning operation, preventing subrequests from incorrectly
performing unpinning on behalf of their parent requests.
Add wb_nr_pinned to struct nfs_page to store the count of pinned pages
owned by the request. Update request creation and cleanup helpers to
initialize and use wb_nr_pinned for primary requests. Use the
nfs_page_array_len() helper to calculate the number of pages spanned
by a request's offset and length.
Signed-off-by: Pranjal Shrivastava <praan@xxxxxxxxxx>
---
fs/nfs/pagelist.c | 9 +++++++--
include/linux/nfs_page.h | 1 +
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 5c5601a27663..f59449918be7 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -454,6 +454,8 @@ struct nfs_page *nfs_page_create_from_page(struct nfs_open_context *ctx,
offset_in_page(offset), count);
if (!IS_ERR(ret)) {
nfs_page_assign_page(ret, page, pinned);
+ if (pinned)
+ ret->wb_nr_pinned = 1;
nfs_page_group_init(ret, NULL);
}
nfs_put_lock_context(l_ctx);
@@ -485,6 +487,9 @@ struct nfs_page *nfs_page_create_from_folio(struct nfs_open_context *ctx,
ret = nfs_page_create(l_ctx, offset, folio->index, offset, count);
if (!IS_ERR(ret)) {
nfs_page_assign_folio(ret, folio, pinned);
+ if (pinned)
+ ret->wb_nr_pinned = nfs_page_array_len(offset_in_page(offset),
+ count);
nfs_page_group_init(ret, NULL);
}
nfs_put_lock_context(l_ctx);
@@ -563,14 +568,14 @@ static void nfs_clear_request(struct nfs_page *req)
if (folio != NULL) {
if (test_and_clear_bit(PG_PINNED, &req->wb_flags))
- unpin_user_folio(folio, 1);
+ unpin_user_folio(folio, req->wb_nr_pinned);
else
folio_put(folio);
req->wb_folio = NULL;
clear_bit(PG_FOLIO, &req->wb_flags);
} else if (page != NULL) {
if (test_and_clear_bit(PG_PINNED, &req->wb_flags))
- unpin_user_page(page);
+ unpin_user_pages(&page, req->wb_nr_pinned);
else
put_page(page);
req->wb_page = NULL;
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 9ece78f1b788..295280fe9571 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -58,6 +58,7 @@ struct nfs_page {
struct nfs_page *wb_this_page; /* list of reqs for this page */
struct nfs_page *wb_head; /* head pointer for req list */
unsigned short wb_nio; /* Number of I/O attempts */
+ unsigned int wb_nr_pinned; /* Number of pinned pages */
};
struct nfs_pgio_mirror;
--
2.54.0.1013.g208068f2d8-goog