summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/zfs/dnode.c9
-rw-r--r--module/zfs/zfs_vnops.c21
2 files changed, 21 insertions, 9 deletions
diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c
index 436816497..20fce9a2d 100644
--- a/module/zfs/dnode.c
+++ b/module/zfs/dnode.c
@@ -1902,6 +1902,15 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset,
flags, offset, lvl, blkfill, txg);
}
+ /*
+ * There's always a "virtual hole" at the end of the object, even
+ * if all BP's which physically exist are non-holes.
+ */
+ if ((flags & DNODE_FIND_HOLE) && error == ESRCH && txg == 0 &&
+ minlvl == 1 && blkfill == 1 && !(flags & DNODE_FIND_BACKWARDS)) {
+ error = 0;
+ }
+
if (error == 0 && (flags & DNODE_FIND_BACKWARDS ?
initial_offset < *offset : initial_offset > *offset))
error = SET_ERROR(ESRCH);
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
index ddd997fae..33f9e0ec9 100644
--- a/module/zfs/zfs_vnops.c
+++ b/module/zfs/zfs_vnops.c
@@ -274,16 +274,19 @@ zfs_holey_common(struct inode *ip, int cmd, loff_t *off)
error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff);
- /* end of file? */
- if ((error == ESRCH) || (noff > file_sz)) {
- /*
- * Handle the virtual hole at the end of file.
- */
- if (hole) {
- *off = file_sz;
- return (0);
- }
+ if (error == ESRCH)
return (SET_ERROR(ENXIO));
+
+ /*
+ * We could find a hole that begins after the logical end-of-file,
+ * because dmu_offset_next() only works on whole blocks. If the
+ * EOF falls mid-block, then indicate that the "virtual hole"
+ * at the end of the file begins at the logical EOF, rather than
+ * at the end of the last block.
+ */
+ if (noff > file_sz) {
+ ASSERT(hole);
+ noff = file_sz;
}
if (noff < *off)