diff options
author | Brian Atkinson <[email protected]> | 2021-01-28 10:15:17 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2021-01-28 09:15:17 -0800 |
commit | 416015ef544183aa1310d7353f28b369f8b89928 (patch) | |
tree | c7a487bcb648f25dc377d1cebfc34271a9c119fa /module/zfs | |
parent | 393e69241eea8b5f7f817200ad283b7d5b5ceb70 (diff) |
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 <[email protected]>
Reviewed-by: Matthew Ahrens <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Brian Atkinson <[email protected]>
Closes #11539
Diffstat (limited to 'module/zfs')
-rw-r--r-- | module/zfs/abd.c | 22 |
1 files changed, 10 insertions, 12 deletions
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) |