Fixing gang ABD when adding another gang

I originally applied a fix in #11539 to fix a parent's child references
when a gang ABD is free'd. However, I did not take into account
abd_gang_add_gang(). We still need to make sure to update the child
references in this function as well. In order to resolve this I removed
decreasing the gang ABD's size in abd_free_gang() as well as moved back
the original placeent of zfs_refcount_remove_many() in abd_free().

Reviewed-by: Mark Maybee <mark.maybee@delphix.com>
Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Brian Atkinson <batkinson@lanl.gov>
Closes #11542
This commit is contained in:
Brian Atkinson 2021-01-28 17:54:12 -07:00 committed by GitHub
parent 9f8c7e6a76
commit 2993698eb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -257,11 +257,9 @@ abd_free_gang(abd_t *abd)
ASSERT(list_link_active(&cabd->abd_gang_link)); ASSERT(list_link_active(&cabd->abd_gang_link));
list_remove(&ABD_GANG(abd).abd_gang_chain, cabd); list_remove(&ABD_GANG(abd).abd_gang_chain, cabd);
mutex_exit(&cabd->abd_mtx); mutex_exit(&cabd->abd_mtx);
abd->abd_size -= cabd->abd_size;
if (cabd->abd_flags & ABD_FLAG_GANG_FREE) if (cabd->abd_flags & ABD_FLAG_GANG_FREE)
abd_free(cabd); abd_free(cabd);
} }
ASSERT0(abd->abd_size);
list_destroy(&ABD_GANG(abd).abd_gang_chain); list_destroy(&ABD_GANG(abd).abd_gang_chain);
} }
@ -292,11 +290,6 @@ abd_free(abd_t *abd)
abd_verify(abd); abd_verify(abd);
IMPLY(abd->abd_flags & ABD_FLAG_OWNER, abd->abd_parent == NULL); IMPLY(abd->abd_flags & ABD_FLAG_OWNER, abd->abd_parent == NULL);
if (abd->abd_parent != NULL) {
(void) zfs_refcount_remove_many(&abd->abd_parent->abd_children,
abd->abd_size, abd);
}
if (abd_is_gang(abd)) { if (abd_is_gang(abd)) {
abd_free_gang(abd); abd_free_gang(abd);
} else if (abd_is_linear(abd)) { } else if (abd_is_linear(abd)) {
@ -307,6 +300,11 @@ abd_free(abd_t *abd)
abd_free_scatter(abd); abd_free_scatter(abd);
} }
if (abd->abd_parent != NULL) {
(void) zfs_refcount_remove_many(&abd->abd_parent->abd_children,
abd->abd_size, abd);
}
abd_fini_struct(abd); abd_fini_struct(abd);
if (abd->abd_flags & ABD_FLAG_ALLOCD) if (abd->abd_flags & ABD_FLAG_ALLOCD)
abd_free_struct_impl(abd); abd_free_struct_impl(abd);
@ -366,7 +364,7 @@ abd_gang_add_gang(abd_t *pabd, abd_t *cabd, boolean_t free_on_free)
&ABD_GANG(cabd).abd_gang_chain); &ABD_GANG(cabd).abd_gang_chain);
ASSERT(list_is_empty(&ABD_GANG(cabd).abd_gang_chain)); ASSERT(list_is_empty(&ABD_GANG(cabd).abd_gang_chain));
abd_verify(pabd); abd_verify(pabd);
abd_free_struct(cabd); abd_free(cabd);
} else { } else {
for (abd_t *child = list_head(&ABD_GANG(cabd).abd_gang_chain); for (abd_t *child = list_head(&ABD_GANG(cabd).abd_gang_chain);
child != NULL; child != NULL;