nfs: track number of pinned pages in nfs_page

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@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
Pranjal Shrivastava 2026-08-14 14:32:52 +00:00 committed by Anna Schumaker
parent d91ae903f4
commit 00ba5f7320
2 changed files with 10 additions and 4 deletions

View File

@ -457,6 +457,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);
@ -489,6 +491,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);
@ -567,8 +572,8 @@ static void nfs_clear_request(struct nfs_page *req)
if (folio != NULL) {
if (test_and_clear_bit(PG_PINNED, &req->wb_flags)) {
if (req == req->wb_head)
unpin_user_folio(folio, 1);
if (req->wb_nr_pinned > 0)
unpin_user_folio(folio, req->wb_nr_pinned);
} else {
folio_put(folio);
}
@ -576,8 +581,8 @@ static void nfs_clear_request(struct nfs_page *req)
clear_bit(PG_FOLIO, &req->wb_flags);
} else if (page != NULL) {
if (test_and_clear_bit(PG_PINNED, &req->wb_flags)) {
if (req == req->wb_head)
unpin_user_page(page);
if (req->wb_nr_pinned > 0)
unpin_user_pages(&page, req->wb_nr_pinned);
} else {
put_page(page);
}

View File

@ -59,6 +59,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;