From 416015ef544183aa1310d7353f28b369f8b89928 Mon Sep 17 00:00:00 2001 From: Brian Atkinson Date: Thu, 28 Jan 2021 10:15:17 -0700 Subject: Removing ABD Parent Child Reference Before Freeing ABD Moving the call to zfs_refcount_remove_many() in abd_free() to be called before any of the ABD free variants are called. This is necessary because abd_free_gang() adjusts the abd_size for the gang ABD. If the parent's child references are removed after free'ing the gang ABD the refcount is not adjusted correctly for the parent's children. I also removed some stray abd_put() in comments and changed abd_free_gang_abd() -> abd_free_gang(). Reviewed-by: Mark Maybee Reviewed-by: Matthew Ahrens Reviewed-by: Brian Behlendorf Signed-off-by: Brian Atkinson Closes #11539 --- module/zfs/abd.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'module') diff --git a/module/zfs/abd.c b/module/zfs/abd.c index 666c3316c..34bf9100b 100644 --- a/module/zfs/abd.c +++ b/module/zfs/abd.c @@ -241,7 +241,7 @@ abd_free_linear(abd_t *abd) } static void -abd_free_gang_abd(abd_t *abd) +abd_free_gang(abd_t *abd) { ASSERT(abd_is_gang(abd)); abd_t *cabd; @@ -292,8 +292,13 @@ abd_free(abd_t *abd) abd_verify(abd); 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)) { - abd_free_gang_abd(abd); + abd_free_gang(abd); } else if (abd_is_linear(abd)) { if (abd->abd_flags & ABD_FLAG_OWNER) abd_free_linear(abd); @@ -302,11 +307,6 @@ abd_free(abd_t *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); if (abd->abd_flags & ABD_FLAG_ALLOCD) abd_free_struct_impl(abd); @@ -421,7 +421,7 @@ abd_gang_add(abd_t *pabd, abd_t *cabd, boolean_t free_on_free) * allocated ABD with ABD_FLAG_GANG_FREE, before * adding it to the gang ABD's list, to make the * gang ABD aware that it is responsible to call - * abd_put(). We use abd_get_offset() in order + * abd_free(). We use abd_get_offset() in order * to just allocate a new ABD but avoid copying the * data over into the newly allocated ABD. * @@ -565,8 +565,7 @@ abd_get_offset_size(abd_t *sabd, size_t off, size_t size) } /* - * Return a size scatter ABD. In order to free the returned - * ABD abd_put() must be called. + * Return a size scatter ABD containing only zeros. */ abd_t * abd_get_zeros(size_t size) @@ -577,8 +576,7 @@ abd_get_zeros(size_t size) } /* - * Allocate a linear ABD structure for buf. You must free this with abd_put() - * since the resulting ABD doesn't own its own buffer. + * Allocate a linear ABD structure for buf. */ abd_t * abd_get_from_buf(void *buf, size_t size) -- cgit v1.2.3