mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-27 11:29:36 +03:00
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 <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 #11539
This commit is contained in:
parent
393e69241e
commit
416015ef54
@ -241,7 +241,7 @@ abd_free_linear(abd_t *abd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
abd_free_gang_abd(abd_t *abd)
|
abd_free_gang(abd_t *abd)
|
||||||
{
|
{
|
||||||
ASSERT(abd_is_gang(abd));
|
ASSERT(abd_is_gang(abd));
|
||||||
abd_t *cabd;
|
abd_t *cabd;
|
||||||
@ -292,8 +292,13 @@ 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);
|
abd_free_gang(abd);
|
||||||
} else if (abd_is_linear(abd)) {
|
} else if (abd_is_linear(abd)) {
|
||||||
if (abd->abd_flags & ABD_FLAG_OWNER)
|
if (abd->abd_flags & ABD_FLAG_OWNER)
|
||||||
abd_free_linear(abd);
|
abd_free_linear(abd);
|
||||||
@ -302,11 +307,6 @@ 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);
|
||||||
@ -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
|
* allocated ABD with ABD_FLAG_GANG_FREE, before
|
||||||
* adding it to the gang ABD's list, to make the
|
* adding it to the gang ABD's list, to make the
|
||||||
* gang ABD aware that it is responsible to call
|
* 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
|
* to just allocate a new ABD but avoid copying the
|
||||||
* data over into the newly allocated ABD.
|
* 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
|
* Return a size scatter ABD containing only zeros.
|
||||||
* ABD abd_put() must be called.
|
|
||||||
*/
|
*/
|
||||||
abd_t *
|
abd_t *
|
||||||
abd_get_zeros(size_t size)
|
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()
|
* Allocate a linear ABD structure for buf.
|
||||||
* since the resulting ABD doesn't own its own buffer.
|
|
||||||
*/
|
*/
|
||||||
abd_t *
|
abd_t *
|
||||||
abd_get_from_buf(void *buf, size_t size)
|
abd_get_from_buf(void *buf, size_t size)
|
||||||
|
Loading…
Reference in New Issue
Block a user