From 7ff329ac2e2d6a3061d1eff9bec5017303f277b2 Mon Sep 17 00:00:00 2001 From: Mark Maybee Date: Thu, 18 Dec 2025 10:23:38 -0700 Subject: [PATCH] Fix rangelock test for growing block size If the file already has more than one block, then the current block size cannot change. But if the file block size is less than the maximum block size supported by the file system, and there are multiple blocks in the file, the current code will almost always extend the rangelock to its maximum size. This means that all writes become serialized and even reads are slowed as they will more often contend with writes. This commit adjusts the test so that we will not lock the entire range if there is more than one block in the file already. Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Signed-off-by: Mark Maybee Closes #18046 Closes #18064 --- module/os/freebsd/zfs/zfs_znode_os.c | 7 ++++--- module/os/linux/zfs/zfs_znode_os.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/module/os/freebsd/zfs/zfs_znode_os.c b/module/os/freebsd/zfs/zfs_znode_os.c index 649022ab5..b9f427b39 100644 --- a/module/os/freebsd/zfs/zfs_znode_os.c +++ b/module/os/freebsd/zfs/zfs_znode_os.c @@ -121,11 +121,12 @@ zfs_rangelock_cb(zfs_locked_range_t *new, void *arg) } /* - * If we need to grow the block size then lock the whole file range. + * If we might grow the block size then lock the whole file range. + * NB: this test should match the check in zfs_grow_blocksize */ uint64_t end_size = MAX(zp->z_size, new->lr_offset + new->lr_length); - if (end_size > zp->z_blksz && (!ISP2(zp->z_blksz) || - zp->z_blksz < ZTOZSB(zp)->z_max_blksz)) { + if (zp->z_size <= zp->z_blksz && end_size > zp->z_blksz && + (!ISP2(zp->z_blksz) || zp->z_blksz < ZTOZSB(zp)->z_max_blksz)) { new->lr_offset = 0; new->lr_length = UINT64_MAX; } diff --git a/module/os/linux/zfs/zfs_znode_os.c b/module/os/linux/zfs/zfs_znode_os.c index bcaabeb32..03976d01a 100644 --- a/module/os/linux/zfs/zfs_znode_os.c +++ b/module/os/linux/zfs/zfs_znode_os.c @@ -95,11 +95,12 @@ zfs_rangelock_cb(zfs_locked_range_t *new, void *arg) } /* - * If we need to grow the block size then lock the whole file range. + * If we might grow the block size then lock the whole file range. + * NB: this test should match the check in zfs_grow_blocksize */ uint64_t end_size = MAX(zp->z_size, new->lr_offset + new->lr_length); - if (end_size > zp->z_blksz && (!ISP2(zp->z_blksz) || - zp->z_blksz < ZTOZSB(zp)->z_max_blksz)) { + if (zp->z_size <= zp->z_blksz && end_size > zp->z_blksz && + (!ISP2(zp->z_blksz) || zp->z_blksz < ZTOZSB(zp)->z_max_blksz)) { new->lr_offset = 0; new->lr_length = UINT64_MAX; }