From 38501e1821316fdf4085d2746bfe531d34ae4478 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 4 May 2026 13:22:47 -0400 Subject: [PATCH] Fix long POSIX_FADV_DONTNEED for single block files dbuf_whichblock() is not made to handle offsets beyond the block end for single-block objects. Handle it in dmu_evict_range(), similar to dmu_prefetch_by_dnode(). Reviewed-by: Brian Behlendorf Reviewed-by: Reviewed-by: Tony Hutter Signed-off-by: Alexander Motin Closes #18399 Closes #18489 --- module/zfs/dmu.c | 10 ++++++++-- .../tests/functional/fadvise/fadvise_dontneed.ksh | 13 ++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 19b8b0594..ad654b163 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -918,8 +918,14 @@ dmu_evict_range(objset_t *os, uint64_t object, uint64_t offset, uint64_t len) * access patterns are rare. */ rw_enter(&dn->dn_struct_rwlock, RW_READER); - uint64_t start = dbuf_whichblock(dn, 0, offset); - uint64_t end = dbuf_whichblock(dn, 0, offset + len); + uint64_t start, end; + if (dn->dn_datablkshift != 0) { + start = dbuf_whichblock(dn, 0, offset); + end = dbuf_whichblock(dn, 0, offset + len); + } else { + start = (offset >= dn->dn_datablksz); + end = (offset + len >= dn->dn_datablksz); + } if (end > start) dbuf_evict_range(dn, start, end - 1); rw_exit(&dn->dn_struct_rwlock); diff --git a/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh b/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh index b19f576ad..53f3ad999 100755 --- a/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh +++ b/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh @@ -32,11 +32,13 @@ # 2. Record cache_count from dbufstats # 3. Call file_fadvise with POSIX_FADV_DONTNEED on the file # 4. Verify that cache_count decreased +# 5. Sanity-check eviction for single-block files. # verify_runnable "global" -FILE=$TESTDIR/$TESTFILE0 +FILE0=$TESTDIR/$TESTFILE0 +FILE1=$TESTDIR/$TESTFILE1 BLKSZ=$(get_prop recordsize $TESTPOOL) function cleanup @@ -48,16 +50,21 @@ log_assert "Ensure POSIX_FADV_DONTNEED evicts data from the dbuf cache" log_onexit cleanup -log_must file_write -o create -f $FILE -b $BLKSZ -c 100 +log_must file_write -o create -f $FILE0 -b $BLKSZ -c 100 sync_pool $TESTPOOL evicts1=$(kstat dbufstats.cache_count) -log_must file_fadvise -f $FILE -a POSIX_FADV_DONTNEED +log_must file_fadvise -f $FILE0 -a POSIX_FADV_DONTNEED evicts2=$(kstat dbufstats.cache_count) log_note "cache_count before=$evicts1 after=$evicts2" log_must [ $evicts1 -gt $evicts2 ] +log_must file_write -o create -f $FILE1 -b 12000 -c 1 +sync_pool $TESTPOOL + +log_must file_fadvise -f $FILE1 -a POSIX_FADV_DONTNEED + log_pass "POSIX_FADV_DONTNEED evicts data from the dbuf cache"