diff options
author | Matthew Ahrens <[email protected]> | 2020-07-31 08:59:00 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-31 08:59:00 -0700 |
commit | 948423a3d1b6b396b46c8edbee9d77515a62589b (patch) | |
tree | 321e3fa0a45704d46aed87d5d3225eca64d55c48 /module | |
parent | a15c6f33104a0ef12f36688e5dcca2f16fff8e05 (diff) |
zfs promote does not delete livelist of origin
When a clone is promoted, its livelist is no longer accurate, so it is
discarded. If the clone's origin is also a clone (i.e. we are promoting
a clone of a clone), then the origin's livelist is also no longer
accurate, so it should be discarded, but the code doesn't actually do
that.
Consider a pool with:
* Filesystem A
* Clone B, a clone of A
* Clone C, a clone of B
If we promote C, it discards C's livelist. It should discard B's
livelist, but that is not happening. The impact is that when B is
destroyed, we use the livelist to find the blocks to free, but the
livelist is no longer correct so we end up freeing blocks that are still
in use by C. The incorrectly-freed blocks can be reallocated causing
checksum errors. And when C is destroyed it can double-free the
incorrectly-freed blocks.
The problem is that we remove the livelist of `origin_ds->ds_dir`, but
the origin snapshot has already been moved to the promoted dsl_dir. So
this is actually trying to remove the livelist of the promoted dsl_dir,
which was already removed. As explained in a comment in the beginning
of `dsl_dataset_promote_sync()`, we need to use the saved `odd` for the
origin's dsl_dir.
Reviewed-by: Pavel Zakharov <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: George Wilson <[email protected]>
Reviewed by: Sara Hartse <[email protected]>
Signed-off-by: Matthew Ahrens <[email protected]>
Closes #10652
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/dsl_dataset.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index c04f47d36..aac8bf76e 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2018 by Delphix. All rights reserved. + * Copyright (c) 2011, 2020 by Delphix. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright (c) 2014 RackTop Systems. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. @@ -3735,7 +3735,7 @@ dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx) * as well. */ dsl_dir_remove_livelist(dd, tx, B_TRUE); - dsl_dir_remove_livelist(origin_ds->ds_dir, tx, B_TRUE); + dsl_dir_remove_livelist(odd, tx, B_TRUE); /* log history record */ spa_history_log_internal_ds(hds, "promote", tx, " "); |