mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-03-10 04:16:18 +03:00
6844 dnode_next_offset can detect fictional holes Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> 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 <behlendorf1@llnl.gov> Closes #4548 |
||
|---|---|---|
| .. | ||
| arc.c | ||
| blkptr.c | ||
| bplist.c | ||
| bpobj.c | ||
| bptree.c | ||
| bqueue.c | ||
| dbuf_stats.c | ||
| dbuf.c | ||
| ddt_zap.c | ||
| ddt.c | ||
| dmu_diff.c | ||
| dmu_object.c | ||
| dmu_objset.c | ||
| dmu_send.c | ||
| dmu_traverse.c | ||
| dmu_tx.c | ||
| dmu_zfetch.c | ||
| dmu.c | ||
| dnode_sync.c | ||
| dnode.c | ||
| dsl_bookmark.c | ||
| dsl_dataset.c | ||
| dsl_deadlist.c | ||
| dsl_deleg.c | ||
| dsl_destroy.c | ||
| dsl_dir.c | ||
| dsl_pool.c | ||
| dsl_prop.c | ||
| dsl_scan.c | ||
| dsl_synctask.c | ||
| dsl_userhold.c | ||
| fm.c | ||
| gzip.c | ||
| lz4.c | ||
| lzjb.c | ||
| Makefile.in | ||
| metaslab.c | ||
| multilist.c | ||
| pathname.c | ||
| range_tree.c | ||
| refcount.c | ||
| rrwlock.c | ||
| sa.c | ||
| sha256.c | ||
| spa_boot.c | ||
| spa_config.c | ||
| spa_errlog.c | ||
| spa_history.c | ||
| spa_misc.c | ||
| spa_stats.c | ||
| spa.c | ||
| space_map.c | ||
| space_reftree.c | ||
| trace.c | ||
| txg.c | ||
| uberblock.c | ||
| unique.c | ||
| vdev_cache.c | ||
| vdev_disk.c | ||
| vdev_file.c | ||
| vdev_label.c | ||
| vdev_mirror.c | ||
| vdev_missing.c | ||
| vdev_queue.c | ||
| vdev_raidz.c | ||
| vdev_root.c | ||
| vdev.c | ||
| zap_leaf.c | ||
| zap_micro.c | ||
| zap.c | ||
| zfeature_common.c | ||
| zfeature.c | ||
| zfs_acl.c | ||
| zfs_byteswap.c | ||
| zfs_ctldir.c | ||
| zfs_debug.c | ||
| zfs_dir.c | ||
| zfs_fm.c | ||
| zfs_fuid.c | ||
| zfs_ioctl.c | ||
| zfs_log.c | ||
| zfs_onexit.c | ||
| zfs_replay.c | ||
| zfs_rlock.c | ||
| zfs_sa.c | ||
| zfs_vfsops.c | ||
| zfs_vnops.c | ||
| zfs_znode.c | ||
| zil.c | ||
| zio_checksum.c | ||
| zio_compress.c | ||
| zio_inject.c | ||
| zio.c | ||
| zle.c | ||
| zpl_ctldir.c | ||
| zpl_export.c | ||
| zpl_file.c | ||
| zpl_inode.c | ||
| zpl_super.c | ||
| zpl_xattr.c | ||
| zrlock.c | ||
| zvol.c | ||