Fix 'zpool remap' freeing race

The dmu_objset_remap_indirects_impl() logic depends on dnode_hold()
returning ENOENT for dnodes which will be freed and should be skipped.

This behavior can only be relied upon when taking a new hold and
while the caller has an open transaction.  This ensures that the
open txg cannot advance and that a concurrent free will end up
in the same txg (which is critical).  Relying on an existing hold
will not prevent dnode_free() from succeeding.

The solution is to take an additional dnode_hold() after assigning
the transaction.  This ensures the remap will never dirty the dnode
if it was freed while we were waiting in dmu_tx_assign(, TXG_WAIT).

Randomly set zfs_object_remap_one_indirect_delay_ms in ztest.  This
increases the likelihood of an operation racing with the remap.
Converted from ticks to milliseconds.

Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: Tom Caputi <tcaputi@datto.com>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #8215
This commit is contained in:
Brian Behlendorf
2019-01-02 11:46:04 -08:00
committed by GitHub
parent 06f3fc2a4b
commit 65ca2c1eb9
2 changed files with 32 additions and 10 deletions
+8
View File
@@ -215,6 +215,8 @@ extern int dmu_object_alloc_chunk_shift;
extern boolean_t zfs_force_some_double_word_sm_entries;
extern unsigned long zio_decompress_fail_fraction;
extern unsigned long zfs_reconstruct_indirect_damage_fraction;
extern int zfs_object_remap_one_indirect_delay_ms;
static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
@@ -6526,6 +6528,12 @@ ztest_resume_thread(void *arg)
*/
if (ztest_random(10) == 0)
zfs_abd_scatter_enabled = ztest_random(2);
/*
* Periodically inject remapping delays (10% of the time).
*/
zfs_object_remap_one_indirect_delay_ms =
ztest_random(10) == 0 ? ztest_random(1000) + 1 : 0;
}
thread_exit();