]> granicus.if.org Git - zfs/commitdiff
Handle damaged blk_birth in dsl_deadlist_insert()
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 11 Dec 2015 19:09:41 +0000 (11:09 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 16 Dec 2015 00:12:31 +0000 (16:12 -0800)
If a bit were cleared in `bp->blk_birth` such that the txg birth
was now lower than any other txg_birth in the deadlist, then there
will be no entry before this in the tree.

This should be impossible but regardless error handling code has
been added for this case.  By default this is left as a fatal case
and the blk_birth is logged.  However, setting `zfs_recover=1` will
cause the bp to be placed at the start of the deadlist even though
it contains an invalid blk_birth.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #4086
Closes #4089

module/zfs/dsl_deadlist.c

index 8da77ebd7b6e12208e1db7a3ecbf378315efc298..fa83a10a5da3b6896387e9ae92c90a2ac0ec140c 100644 (file)
@@ -239,6 +239,14 @@ dsl_deadlist_insert(dsl_deadlist_t *dl, const blkptr_t *bp, dmu_tx_t *tx)
                dle = avl_nearest(&dl->dl_tree, where, AVL_BEFORE);
        else
                dle = AVL_PREV(&dl->dl_tree, dle);
+
+       if (dle == NULL) {
+               zfs_panic_recover("blkptr at %p has invalid BLK_BIRTH %llu",
+                   bp, (longlong_t)bp->blk_birth);
+               dle = avl_first(&dl->dl_tree);
+       }
+
+       ASSERT3P(dle, !=, NULL);
        dle_enqueue(dl, dle, bp, tx);
 }