diff options
author | Alex Reece <[email protected]> | 2016-04-21 11:23:37 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-04-27 16:24:15 -0700 |
commit | 463a8cfe2b293934edd2ee79115b20c4598353d6 (patch) | |
tree | cac82326668d5f9b7135234b0d3962228e5f4568 /include | |
parent | 8a5fc74880251aa651306d1dbcc60715698996f0 (diff) |
Illumos 6844 - dnode_next_offset can detect fictional holes
6844 dnode_next_offset can detect fictional holes
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: Brian Behlendorf <[email protected]>
dnode_next_offset is used in a variety of places to iterate over the
holes or allocated blocks in a dnode. It operates under the premise that
it can iterate over the blockpointers of a dnode in open context while
holding only the dn_struct_rwlock as reader. Unfortunately, this premise
does not hold.
When we create the zio for a dbuf, we pass in the actual block pointer
in the indirect block above that dbuf. When we later zero the bp in
zio_write_compress, we are directly modifying the bp. The state of the
bp is now inconsistent from the perspective of dnode_next_offset: the bp
will appear to be a hole until zio_dva_allocate finally finishes filling
it in. In the meantime, dnode_next_offset can detect a hole in the dnode
when none exists.
I was able to experimentally demonstrate this behavior with the
following setup:
1. Create a file with 1 million dbufs.
2. Create a thread that randomly dirties L2 blocks by writing to the
first L0 block under them.
3. Observe dnode_next_offset, waiting for it to skip over a hole in the
middle of a file.
4. Do dnode_next_offset in a loop until we skip over such a non-existent
hole.
The fix is to ensure that it is valid to iterate over the indirect
blocks in a dnode while holding the dn_struct_rwlock by passing the zio
a copy of the BP and updating the actual BP in dbuf_write_ready while
holding the lock.
References:
https://www.illumos.org/issues/6844
https://github.com/openzfs/openzfs/pull/82
DLPX-35372
Ported-by: Brian Behlendorf <[email protected]>
Closes #4548
Diffstat (limited to 'include')
-rw-r--r-- | include/sys/dbuf.h | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index 9147c9d4d..079358911 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -121,6 +121,9 @@ typedef struct dbuf_dirty_record { /* How much space was changed to dsl_pool_dirty_space() for this? */ unsigned int dr_accounted; + /* A copy of the bp that points to us */ + blkptr_t dr_bp_copy; + union dirty_types { struct dirty_indirect { |