#19047·zfs

zfs_dedupe_range_copy_memcmp() livelocks if zfs_vnops_read_chunk_size is set to 0

Author: xfcyhuangCreated Sep 4, 2026Updated Sep 11, 2026

System information

Type Version
Operating System any
ZFS Version master @ aa26ca67b

Describe the problem

zfs_dedupe_range_copy_memcmp() in module/zfs/zfs_vnops.c computes its copy chunk size without a lower bound (line ~2128):

c
uint64_t chunk = MIN(len, (uint64_t)zfs_vnops_read_chunk_size);

zfs_vnops_read_chunk_size is registered as a ZMOD_RW U64 tunable (zfs_vnops.c:2945) with no param_set validation, so it can be set to 0 at runtime via /sys/module/zfs/parameters/zfs_vnops_read_chunk_size. With chunk == 0 the compare loop cannot make progress:

  • n = MIN(len, chunk) is always 0,
  • dmu_read() of 0 bytes succeeds,
  • memcmp() of 0 bytes reports equality,
  • len -= 0 never advances,

so the calling kernel thread spins forever (only issig() can break it out). This is a livelock on the FIDEDUPERANGE / dedupe path.

The two sibling users of the same tunable in the same file both clamp it:

  • zfs_read() (line ~429): chunk_size = MIN(MAX(zfs_vnops_read_chunk_size, blksz), DMU_MAX_ACCESS / 2);
  • zfs_dedupe_range_memcmp() (line ~2242): chunk = MAX(1, MIN(zfs_vnops_read_chunk_size, DMU_MAX_ACCESS / 2) / blksz) * blksz;

zfs_dedupe_range_copy_memcmp() is the fallback taken for files with a non-power-of-2 recordsize (dn_datablkshift == 0) whose compare range extends past the last (partial) block, so it is rare but reachable.

Describe how to reproduce

  1. echo 0 > /sys/module/zfs/parameters/zfs_vnops_read_chunk_size
  2. Create a dataset with a non-power-of-2 recordsize and a file whose compare range extends beyond the end of the last (partial) block, so the dbuf-based zfs_dedupe_range_memcmp() path cannot be used
  3. Issue FIDEDUPERANGE on that range; the calling thread livelocks

Suggested fix

Clamp the tunable the same way the siblings do:

c
uint64_t chunk = MAX(1, MIN(len, (uint64_t)zfs_vnops_read_chunk_size));

Found while reviewing the FIDEDUPERANGE work (afb401032 and follow-ups). Happy to send a PR.