aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorBrian Atkinson <[email protected]>2021-01-28 10:15:17 -0700
committerGitHub <[email protected]>2021-01-28 09:15:17 -0800
commit416015ef544183aa1310d7353f28b369f8b89928 (patch)
treec7a487bcb648f25dc377d1cebfc34271a9c119fa /module/zfs
parent393e69241eea8b5f7f817200ad283b7d5b5ceb70 (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.c22
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)