]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix two abd_gang_add_gang() issues.
authorAlexander Motin <mav@FreeBSD.org>
Fri, 5 May 2023 16:17:55 +0000 (12:17 -0400)
committerGitHub <noreply@github.com>
Fri, 5 May 2023 16:17:55 +0000 (09:17 -0700)
- There is no reason to assert that added gang is not empty.  It
may be weird to add an empty gang, but it is legal.
 - When moving chain list from the added gang clear its size, or it
will trigger assertion in abd_verify() when that gang is freed.

Reviewed-by: Brian Atkinson <batkinson@lanl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored by: iXsystems, Inc.
Closes #14816

module/zfs/abd.c

index 26222d2efe3f5ec702cab7d9e361f223be844555..745ee8f02ed401dda4cfbeb94ef7acb791146617 100644 (file)
@@ -370,7 +370,20 @@ abd_gang_add_gang(abd_t *pabd, abd_t *cabd, boolean_t free_on_free)
                 * will retain all the free_on_free settings after being
                 * added to the parents list.
                 */
+#ifdef ZFS_DEBUG
+               /*
+                * If cabd had abd_parent, we have to drop it here.  We can't
+                * transfer it to pabd, nor we can clear abd_size leaving it.
+                */
+               if (cabd->abd_parent != NULL) {
+                       (void) zfs_refcount_remove_many(
+                           &cabd->abd_parent->abd_children,
+                           cabd->abd_size, cabd);
+                       cabd->abd_parent = NULL;
+               }
+#endif
                pabd->abd_size += cabd->abd_size;
+               cabd->abd_size = 0;
                list_move_tail(&ABD_GANG(pabd).abd_gang_chain,
                    &ABD_GANG(cabd).abd_gang_chain);
                ASSERT(list_is_empty(&ABD_GANG(cabd).abd_gang_chain));
@@ -408,7 +421,6 @@ abd_gang_add(abd_t *pabd, abd_t *cabd, boolean_t free_on_free)
         */
        if (abd_is_gang(cabd)) {
                ASSERT(!list_link_active(&cabd->abd_gang_link));
-               ASSERT(!list_is_empty(&ABD_GANG(cabd).abd_gang_chain));
                return (abd_gang_add_gang(pabd, cabd, free_on_free));
        }
        ASSERT(!abd_is_gang(cabd));