Skip to content

Commit 5c85519

Browse files
committed
Additional limits on hole reporting
Holding the zp->z_rangelock is insufficient to prevent the dnode from being re-dirtied in all cases. To avoid looping indefinately in dmu_offset_next() on files being actively written only wait once for a dirty dnode to be synced. If after waiting it's still dirty don't report the hole. This is always safe. Signed-off-by: Brian Behlendorf <[email protected]> Issue #14512
1 parent fa46802 commit 5c85519

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

module/zfs/dmu.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,7 +2127,7 @@ int
21272127
dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
21282128
{
21292129
dnode_t *dn;
2130-
int err;
2130+
int restarted = 0, err;
21312131

21322132
restart:
21332133
err = dnode_hold(os, object, FTAG, &dn);
@@ -2139,19 +2139,23 @@ dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
21392139
if (dnode_is_dirty(dn)) {
21402140
/*
21412141
* If the zfs_dmu_offset_next_sync module option is enabled
2142-
* then strict hole reporting has been requested. Dirty
2143-
* dnodes must be synced to disk to accurately report all
2144-
* holes. When disabled dirty dnodes are reported to not
2145-
* have any holes which is always safe.
2146-
*
2147-
* When called by zfs_holey_common() the zp->z_rangelock
2148-
* is held to prevent zfs_write() and mmap writeback from
2149-
* re-dirtying the dnode after txg_wait_synced().
2142+
* then hole reporting has been requested. Dirty dnodes must
2143+
* be synced to disk to accurately report holes. When called
2144+
* by zfs_holey_common() the zp->z_rangelock is held to prevent
2145+
* zfs_write() and mmap writeback from re-dirtying the dnode
2146+
* after txg_wait_synced(). Regardless, if a dnode has been
2147+
* dirtied in consecutive txgs by another caller not holding
2148+
* the range lock disable hole reporting to avoid looping.
21502149
*/
21512150
if (zfs_dmu_offset_next_sync) {
21522151
rw_exit(&dn->dn_struct_rwlock);
21532152
dnode_rele(dn, FTAG);
2153+
2154+
if (restarted)
2155+
return (SET_ERROR(EBUSY));
2156+
21542157
txg_wait_synced(dmu_objset_pool(os), 0);
2158+
restarted = 1;
21552159
goto restart;
21562160
}
21572161

0 commit comments

Comments
 (0)