From: Pranjal Shrivastava <praan@google.com>
To: trond.myklebust@hammerspace.com, anna@kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
pabeni@redhat.com, chuck.lever@oracle.com, jlayton@kernel.org,
tom@talpey.com, okorniev@redhat.com, neil@brown.name,
dai.ngo@oracle.com, linux-nfs@vger.kernel.org,
netdev@vger.kernel.org, Pranjal Shrivastava <praan@google.com>
Subject: [RFC PATCH 3/4] nfs: make nfs_page pin-aware
Date: Wed, 1 Apr 2026 19:44:59 +0000 [thread overview]
Message-ID: <20260401194501.2269200-4-praan@google.com> (raw)
In-Reply-To: <20260401194501.2269200-1-praan@google.com>
The migration to iov_iter_extract_pages() for Direct I/O introduces
page pinning (GUP) instead of standard page referencing. To handle this
correctly, nfs_page must track whether it holds a pin or a standard
reference.
Add a new flag, PG_PINNED, to struct nfs_page. Update the creation
path (nfs_page_create_from_page) to accept a 'pinned' boolean and
set the flag accordingly. If the page is pinned, we skip the standard
get_page() as the pin itself acts as a reference.
Update nfs_clear_request() to use unpin_user_page() instead of
put_page() when the PG_PINNED flag is set. This ensures that memory
remains safely locked for DMA and that kernel page accounting stays
consistent. Ensure subrequests inherit the pin status from their
parent request.
Signed-off-by: Pranjal Shrivastava <praan@google.com>
---
fs/nfs/direct.c | 4 ++--
fs/nfs/pagelist.c | 18 +++++++++++++-----
include/linux/nfs_page.h | 2 ++
3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 48d89716193a..c8429b430181 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -370,7 +370,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
struct nfs_page *req;
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
/* XXX do we need to do the eof zeroing found in async_filler? */
- req = nfs_page_create_from_page(dreq->ctx, pagevec[i],
+ req = nfs_page_create_from_page(dreq->ctx, pagevec[i], false,
pgbase, pos, req_len);
if (IS_ERR(req)) {
result = PTR_ERR(req);
@@ -898,7 +898,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
struct nfs_page *req;
unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
- req = nfs_page_create_from_page(dreq->ctx, pagevec[i],
+ req = nfs_page_create_from_page(dreq->ctx, pagevec[i], false,
pgbase, pos, req_len);
if (IS_ERR(req)) {
result = PTR_ERR(req);
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index a9373de891c9..72d3da0fb654 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -413,11 +413,14 @@ static void nfs_page_assign_folio(struct nfs_page *req, struct folio *folio)
}
}
-static void nfs_page_assign_page(struct nfs_page *req, struct page *page)
+static void nfs_page_assign_page(struct nfs_page *req, struct page *page, bool pinned)
{
if (page != NULL) {
req->wb_page = page;
- get_page(page);
+ if (pinned)
+ set_bit(PG_PINNED, &req->wb_flags);
+ else
+ get_page(page);
}
}
@@ -435,6 +438,7 @@ static void nfs_page_assign_page(struct nfs_page *req, struct page *page)
*/
struct nfs_page *nfs_page_create_from_page(struct nfs_open_context *ctx,
struct page *page,
+ bool pinned,
unsigned int pgbase, loff_t offset,
unsigned int count)
{
@@ -446,7 +450,7 @@ struct nfs_page *nfs_page_create_from_page(struct nfs_open_context *ctx,
ret = nfs_page_create(l_ctx, pgbase, offset >> PAGE_SHIFT,
offset_in_page(offset), count);
if (!IS_ERR(ret)) {
- nfs_page_assign_page(ret, page);
+ nfs_page_assign_page(ret, page, pinned);
nfs_page_group_init(ret, NULL);
}
nfs_put_lock_context(l_ctx);
@@ -500,7 +504,8 @@ nfs_create_subreq(struct nfs_page *req,
if (folio)
nfs_page_assign_folio(ret, folio);
else
- nfs_page_assign_page(ret, page);
+ nfs_page_assign_page(ret, page,
+ test_bit(PG_PINNED, &req->wb_flags));
/* find the last request */
for (last = req->wb_head;
last->wb_this_page != req->wb_head;
@@ -556,7 +561,10 @@ static void nfs_clear_request(struct nfs_page *req)
req->wb_folio = NULL;
clear_bit(PG_FOLIO, &req->wb_flags);
} else if (page != NULL) {
- put_page(page);
+ if (test_and_clear_bit(PG_PINNED, &req->wb_flags))
+ unpin_user_page(page);
+ else
+ put_page(page);
req->wb_page = NULL;
}
if (l_ctx != NULL) {
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index afe1d8f09d89..cae67540a2ae 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -37,6 +37,7 @@ enum {
PG_REMOVE, /* page group sync bit in write path */
PG_CONTENDED1, /* Is someone waiting for a lock? */
PG_CONTENDED2, /* Is someone waiting for a lock? */
+ PG_PINNED, /* page is pinned by GUP */
};
struct nfs_inode;
@@ -124,6 +125,7 @@ struct nfs_pageio_descriptor {
extern struct nfs_page *nfs_page_create_from_page(struct nfs_open_context *ctx,
struct page *page,
+ bool pinned,
unsigned int pgbase,
loff_t offset,
unsigned int count);
--
2.53.0.1185.g05d4b7b318-goog
next prev parent reply other threads:[~2026-04-01 19:45 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-01 19:44 [RFC PATCH 0/4] nfs: Enable PCI Peer-to-Peer DMA (P2PDMA) support Pranjal Shrivastava
2026-04-01 19:44 ` [RFC PATCH 1/4] sunrpc: add supports_p2pdma to rpc_xprt_ops Pranjal Shrivastava
2026-04-01 19:44 ` [RFC PATCH 2/4] nfs: add NFS_CAP_P2PDMA and detect transport support Pranjal Shrivastava
2026-04-02 13:11 ` Chuck Lever
2026-04-01 19:44 ` Pranjal Shrivastava [this message]
2026-04-02 5:04 ` [RFC PATCH 3/4] nfs: make nfs_page pin-aware Christoph Hellwig
2026-04-01 19:45 ` [RFC PATCH 4/4] nfs: allow P2PDMA in direct I/O path Pranjal Shrivastava
2026-04-02 5:05 ` Christoph Hellwig
2026-04-02 5:07 ` [RFC PATCH 0/4] nfs: Enable PCI Peer-to-Peer DMA (P2PDMA) support Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260401194501.2269200-4-praan@google.com \
--to=praan@google.com \
--cc=anna@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=dai.ngo@oracle.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=jlayton@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=netdev@vger.kernel.org \
--cc=okorniev@redhat.com \
--cc=pabeni@redhat.com \
--cc=tom@talpey.com \
--cc=trond.myklebust@hammerspace.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox