Re: [PATCH v1 6/7] nfs: Optimize direct I/O to use folios for requests
From: Anna Schumaker
Date: Wed Jun 03 2026 - 15:15:02 EST
Hi Pranjal,
On Wed, Jun 3, 2026, at 1:30 AM, Pranjal Shrivastava wrote:
> Optimize nfs_direct_extract_pages() to group contiguous pages from the
> same folio into single nfs_page structures. This effectively migrates
> NFS Direct I/O from being page-based to being folio-based.
>
> Reduce the number of nfs_page allocations and subsequent iterations
> by utilizing nfs_page_create_from_folio() to create aggregated
> requests.
I am seeing a LOT of failing xfstests after applying this patch (testing
against various NFS versions over TCP with AUTH_SYS):
+-------------+-----------+-------------+-------------+-------------+
| testcase | tcp-sys-3 | tcp-sys-4.0 | tcp-sys-4.1 | tcp-sys-4.2 |
+-------------+-----------+-------------+-------------+-------------+
| generic/091 | failure | failure | failure | failure |
| generic/130 | failure | failure | failure | failure |
| generic/139 | skipped | skipped | skipped | failure |
| generic/143 | skipped | skipped | skipped | failure |
| generic/154 | skipped | skipped | skipped | failure |
| generic/155 | skipped | skipped | skipped | failure |
| generic/183 | skipped | skipped | skipped | failure |
| generic/188 | skipped | skipped | skipped | failure |
| generic/190 | skipped | skipped | skipped | failure |
| generic/196 | skipped | skipped | skipped | failure |
| generic/198 | failure | failure | failure | failure |
| generic/203 | skipped | skipped | skipped | failure |
| generic/214 | skipped | skipped | skipped | failure |
| generic/240 | failure | failure | failure | failure |
| generic/263 | failure | failure | failure | failure |
| generic/287 | skipped | skipped | skipped | failure |
| generic/290 | skipped | skipped | skipped | failure |
| generic/292 | skipped | skipped | skipped | failure |
| generic/330 | skipped | skipped | skipped | failure |
| generic/444 | failure | skipped | skipped | skipped |
| generic/450 | failure | failure | failure | failure |
| generic/451 | failure | failure | failure | failure |
| generic/586 | skipped | skipped | skipped | failure |
| generic/647 | failure | failure | failure | failure |
| generic/708 | failure | failure | failure | failure |
| generic/729 | failure | failure | failure | failure |
| generic/760 | failure | failure | failure | failure |
+-------------+-----------+-------------+-------------+-------------+
I'm curious if you've run xfstests against your changes, and if you
see the same failures?
Thanks,
Anna
>
> Signed-off-by: Pranjal Shrivastava <praan@xxxxxxxxxx>
> ---
> fs/nfs/direct.c | 36 +++++++++++++++++++++++++++++-------
> 1 file changed, 29 insertions(+), 7 deletions(-)
>
> diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
> index 59002c150f23..93e1af9ec36b 100644
> --- a/fs/nfs/direct.c
> +++ b/fs/nfs/direct.c
> @@ -194,23 +194,45 @@ static ssize_t nfs_direct_extract_pages(struct
> nfs_direct_req *dreq,
> return result;
>
> npages = (result + pgbase + PAGE_SIZE - 1) >> PAGE_SHIFT;
> - for (i = 0; i < npages; i++) {
> + for (i = 0; i < npages; ) {
> + unsigned int chunk_len, folio_offset;
> + unsigned int nr_to_add = 1;
> struct nfs_page *req;
> - unsigned int req_len = min_t(size_t, result - bytes, PAGE_SIZE - pgbase);
> + struct folio *folio;
>
> - req = nfs_page_create_from_page(dreq->ctx, pagevec[i],
> - pinned, pgbase, *pos,
> - req_len);
> + folio = page_folio(pagevec[i]);
> + folio_offset = (folio_page_idx(folio, pagevec[i]) << PAGE_SHIFT) + pgbase;
> + chunk_len = min_t(size_t, result - bytes, PAGE_SIZE - pgbase);
> +
> + while (i + nr_to_add < npages) {
> + struct page *next_page = pagevec[i + nr_to_add];
> + struct page *prev_page = pagevec[i + nr_to_add - 1];
> +
> + if (page_folio(next_page) != folio ||
> + next_page != prev_page + 1)
> + break;
> +
> + chunk_len += min_t(size_t, result - bytes - chunk_len, PAGE_SIZE);
> + nr_to_add++;
> + }
> +
> + req = nfs_page_create_from_folio(dreq->ctx, folio,
> + pinned, folio_offset,
> + chunk_len);
> if (IS_ERR(req)) {
> if (!bytes)
> bytes = PTR_ERR(req);
> break;
> }
>
> + req->wb_index = *pos >> PAGE_SHIFT;
> + req->wb_offset = *pos;
> +
> list_add_tail(&req->wb_list, list);
> pgbase = 0;
> - bytes += req_len;
> - *pos += req_len;
> + bytes += chunk_len;
> + *pos += chunk_len;
> + i += nr_to_add;
> }
>
> if (i < npages) {
> --
> 2.54.0.1013.g208068f2d8-goog