summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorAlex Reece <[email protected]>2016-04-21 11:23:37 -0700
committerBrian Behlendorf <[email protected]>2016-04-27 16:24:15 -0700
commit463a8cfe2b293934edd2ee79115b20c4598353d6 (patch)
treecac82326668d5f9b7135234b0d3962228e5f4568 /include
parent8a5fc74880251aa651306d1dbcc60715698996f0 (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.h3
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 {