Illumos #3104: eliminate empty bpobjs
[zfs.git] / module / zfs / dsl_deadlist.c
index 1e89a68..909b5f8 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <sys/dsl_dataset.h>
@@ -165,12 +165,49 @@ dsl_deadlist_free(objset_t *os, uint64_t dlobj, dmu_tx_t *tx)
 
        for (zap_cursor_init(&zc, os, dlobj);
            zap_cursor_retrieve(&zc, &za) == 0;
-           zap_cursor_advance(&zc))
-               bpobj_free(os, za.za_first_integer, tx);
+           zap_cursor_advance(&zc)) {
+               uint64_t obj = za.za_first_integer;
+               if (obj == dmu_objset_pool(os)->dp_empty_bpobj)
+                       bpobj_decr_empty(os, tx);
+               else
+                       bpobj_free(os, obj, tx);
+       }
        zap_cursor_fini(&zc);
        VERIFY3U(0, ==, dmu_object_free(os, dlobj, tx));
 }
 
+static void
+dle_enqueue(dsl_deadlist_t *dl, dsl_deadlist_entry_t *dle,
+    const blkptr_t *bp, dmu_tx_t *tx)
+{
+       if (dle->dle_bpobj.bpo_object ==
+           dmu_objset_pool(dl->dl_os)->dp_empty_bpobj) {
+               uint64_t obj = bpobj_alloc(dl->dl_os, SPA_MAXBLOCKSIZE, tx);
+               bpobj_close(&dle->dle_bpobj);
+               bpobj_decr_empty(dl->dl_os, tx);
+               VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
+               VERIFY3U(0, ==, zap_update_int_key(dl->dl_os, dl->dl_object,
+                   dle->dle_mintxg, obj, tx));
+       }
+       bpobj_enqueue(&dle->dle_bpobj, bp, tx);
+}
+
+static void
+dle_enqueue_subobj(dsl_deadlist_t *dl, dsl_deadlist_entry_t *dle,
+    uint64_t obj, dmu_tx_t *tx)
+{
+       if (dle->dle_bpobj.bpo_object !=
+           dmu_objset_pool(dl->dl_os)->dp_empty_bpobj) {
+               bpobj_enqueue_subobj(&dle->dle_bpobj, obj, tx);
+       } else {
+               bpobj_close(&dle->dle_bpobj);
+               bpobj_decr_empty(dl->dl_os, tx);
+               VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
+               VERIFY3U(0, ==, zap_update_int_key(dl->dl_os, dl->dl_object,
+                   dle->dle_mintxg, obj, tx));
+       }
+}
+
 void
 dsl_deadlist_insert(dsl_deadlist_t *dl, const blkptr_t *bp, dmu_tx_t *tx)
 {
@@ -199,7 +236,7 @@ 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);
-       bpobj_enqueue(&dle->dle_bpobj, bp, tx);
+       dle_enqueue(dl, dle, bp, tx);
 }
 
 /*
@@ -219,7 +256,7 @@ dsl_deadlist_add_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx)
 
        dle = kmem_alloc(sizeof (*dle), KM_PUSHPAGE);
        dle->dle_mintxg = mintxg;
-       obj = bpobj_alloc(dl->dl_os, SPA_MAXBLOCKSIZE, tx);
+       obj = bpobj_alloc_empty(dl->dl_os, SPA_MAXBLOCKSIZE, tx);
        VERIFY3U(0, ==, bpobj_open(&dle->dle_bpobj, dl->dl_os, obj));
        avl_add(&dl->dl_tree, dle);
 
@@ -245,8 +282,7 @@ dsl_deadlist_remove_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx)
        dle = avl_find(&dl->dl_tree, &dle_tofind, NULL);
        dle_prev = AVL_PREV(&dl->dl_tree, dle);
 
-       bpobj_enqueue_subobj(&dle_prev->dle_bpobj,
-           dle->dle_bpobj.bpo_object, tx);
+       dle_enqueue_subobj(dl, dle_prev, dle->dle_bpobj.bpo_object, tx);
 
        avl_remove(&dl->dl_tree, dle);
        bpobj_close(&dle->dle_bpobj);
@@ -304,7 +340,7 @@ dsl_deadlist_clone(dsl_deadlist_t *dl, uint64_t maxtxg,
                if (dle->dle_mintxg >= maxtxg)
                        break;
 
-               obj = bpobj_alloc(dl->dl_os, SPA_MAXBLOCKSIZE, tx);
+               obj = bpobj_alloc_empty(dl->dl_os, SPA_MAXBLOCKSIZE, tx);
                VERIFY3U(0, ==, zap_add_int_key(dl->dl_os, newobj,
                    dle->dle_mintxg, obj, tx));
        }
@@ -402,7 +438,7 @@ dsl_deadlist_insert_bpobj(dsl_deadlist_t *dl, uint64_t obj, uint64_t birth,
        dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
        if (dle == NULL)
                dle = avl_nearest(&dl->dl_tree, where, AVL_BEFORE);
-       bpobj_enqueue_subobj(&dle->dle_bpobj, obj, tx);
+       dle_enqueue_subobj(dl, dle, obj, tx);
 }
 
 static int