* [PATCH] nfsd: do not allocate blocks for an RW layout with a minlength of zero
@ 2026-10-12 4:40 Daejun Park via B4 Relay
2026-10-12 12:41 ` Christoph Hellwig
0 siblings, 1 reply; 2+ messages in thread
From: Daejun Park via B4 Relay @ 2026-10-12 4:40 UTC (permalink / raw)
To: Chuck Lever, Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Christoph Hellwig
Cc: Darrick J. Wong, Carlos Maiolino, Sergey Bashirov, linux-nfs,
linux-xfs, linux-kernel, Daejun Park
From: Daejun Park <daejun7.park@samsung.com>
RFC 5663 section 2.3.1 says that for a LAYOUTGET with a loga_minlength
of zero, a writable layout is readily available only if its extents can
be returned in the READ_WRITE_DATA state. nfsd4_block_map_extent()
follows it by refusing an RW layout with a minlength of zero on an
unwritten extent, with NFS4ERR_LAYOUTUNAVAILABLE.
But it asks ->map_blocks for a write mapping before it looks at the
minlength. For a hole, XFS allocates blocks, updates the inode and forces
the log, and the mapping it returns is unwritten, so the layout is
refused. The client gets no layout, and the blocks stay allocated: XFS
marks the inode XFS_DIFLAG_PREALLOC for them, so xfs_free_eofblocks()
does not free them past EOF either. This is possible since commit
8c3ad9cb7343 ("nfsd/blocklayout: accept any minlength"), which removed
the check that refused a minlength below the block size before
->map_blocks was called.
Ask for a write mapping only when the minlength is not zero, and refuse
a hole in an RW layout with a minlength of zero, as an unwritten extent
is refused. The client gets the same answer, and nothing is allocated.
Written extents are still granted as READ_WRITE_DATA.
With pynfs as the client, an RW LAYOUTGET for 0+1 MiB with a minlength
of zero got NFS4ERR_LAYOUTUNAVAILABLE and left 1 MiB allocated on an
empty file, and 960 KiB allocated past the first 64 KiB on a file whose
first 64 KiB were written. With this patch both get the same error and
nothing is allocated. An RW LAYOUTGET with a minlength of zero for the
64 KiB that were written, and one with a minlength of 4 KiB on an empty
file, are granted as before.
The Linux client does not send an RW LAYOUTGET with a minlength of zero
(pnfs_alloc_init_layoutget_args()), so it is not affected.
Fixes: 8c3ad9cb7343 ("nfsd/blocklayout: accept any minlength")
Suggested-by: Chuck Lever <cel@kernel.org>
Link: https://lore.kernel.org/r/235ae19b-fd63-4d01-9fe0-d047a33b55ed@slotpi15m67
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
---
Tested on nfsd-testing (d918c664efd5) with KASAN and lockdep, XFS on an
NVMe/TCP namespace shared by the server and the client:
- pynfs block and blockextent tests, and the LAYOUTGETs above (a local
test, not posted), 1 run without and 2 with this patch: the same
results apart from the allocations above. BLOCK3 fails with
NFS4ERR_BADXDR for its empty layoutupdate with and without this patch.
The same on the earlier heads f27ad2d54411 and 3af417ce0f30, which
differ only in fs/nfsd/nfsctl.c and net/sunrpc/svcsock.c.
- fstests generic/075, 091 and 263 with the Linux client over the block
layout, on 3af417ce0f30: only 075 fails, as without this patch.
This is meant to go in before the ->map_blocks series, which will take
the same change into nfsd4_block_proc_layoutget():
https://lore.kernel.org/r/235ae19b-fd63-4d01-9fe0-d047a33b55ed@slotpi15m67
---
fs/nfsd/blocklayout.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 6fefcb2072..b3bb2831cf 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -31,10 +31,17 @@ nfsd4_block_map_extent(struct inode *inode, const struct svc_fh *fhp,
struct super_block *sb = inode->i_sb;
struct iomap iomap;
u32 device_generation = 0;
+ bool write;
int error;
+ /*
+ * An RW layout with a minlength of zero only gets extents that can
+ * be returned as READ_WRITE_DATA (RFC 5663, section 2.3.1), so do
+ * not have the filesystem allocate blocks that would be refused.
+ */
+ write = iomode != IOMODE_READ && minlength != 0;
error = sb->s_export_op->block_ops->map_blocks(inode, offset, length,
- &iomap, iomode != IOMODE_READ, &device_generation);
+ &iomap, write, &device_generation);
if (error) {
if (error == -ENXIO)
return nfserr_layoutunavailable;
@@ -76,6 +83,9 @@ nfsd4_block_map_extent(struct inode *inode, const struct svc_fh *fhp,
bex->es = PNFS_BLOCK_NONE_DATA;
break;
}
+ /* Not allocated for a minlength of zero, see above. */
+ if (minlength == 0)
+ return nfserr_layoutunavailable;
fallthrough;
case IOMAP_DELALLOC:
default:
---
base-commit: d918c664efd5ec6a7309e98f567fb018bcde0e11
change-id: 20261009-nfsd-block-minlength0-0314a782cba3
Best regards,
--
Daejun Park <daejun7.park@samsung.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] nfsd: do not allocate blocks for an RW layout with a minlength of zero
2026-10-12 4:40 [PATCH] nfsd: do not allocate blocks for an RW layout with a minlength of zero Daejun Park via B4 Relay
@ 2026-10-12 12:41 ` Christoph Hellwig
0 siblings, 0 replies; 2+ messages in thread
From: Christoph Hellwig @ 2026-10-12 12:41 UTC (permalink / raw)
To: daejun7.park
Cc: Chuck Lever, Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey, Christoph Hellwig, Darrick J. Wong, Carlos Maiolino,
Sergey Bashirov, linux-nfs, linux-xfs, linux-kernel
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-12 12:41 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 4:40 [PATCH] nfsd: do not allocate blocks for an RW layout with a minlength of zero Daejun Park via B4 Relay
2026-10-12 12:41 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®