Print this page
4374 dn_free_ranges should use range_tree_t
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Max Grossman <max.grossman@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Approved by: Dan McDonald <danmcd@omniti.com>

@@ -19,11 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
 #include <sys/dbuf.h>
 #include <sys/dnode.h>

@@ -30,10 +30,11 @@
 #include <sys/dmu.h>
 #include <sys/dmu_tx.h>
 #include <sys/dmu_objset.h>
 #include <sys/dsl_dataset.h>
 #include <sys/spa.h>
+#include <sys/range_tree.h>
 #include <sys/zfeature.h>
 
 static void
 dnode_increase_indirection(dnode_t *dn, dmu_tx_t *tx)
 {

@@ -316,11 +317,11 @@
 /*
  * Traverse the indicated range of the provided file
  * and "free" all the blocks contained there.
  */
 static void
-dnode_sync_free_range(dnode_t *dn, uint64_t blkid, uint64_t nblks,
+dnode_sync_free_range_impl(dnode_t *dn, uint64_t blkid, uint64_t nblks,
     dmu_tx_t *tx)
 {
         blkptr_t *bp = dn->dn_phys->dn_blkptr;
         int dnlevel = dn->dn_phys->dn_nlevels;
         boolean_t trunc = B_FALSE;

@@ -374,10 +375,26 @@
                     dn->dn_phys->dn_maxblkid == 0 ||
                     dnode_next_offset(dn, 0, &off, 1, 1, 0) != 0);
         }
 }
 
+typedef struct dnode_sync_free_range_arg {
+        dnode_t *dsfra_dnode;
+        dmu_tx_t *dsfra_tx;
+} dnode_sync_free_range_arg_t;
+
+static void
+dnode_sync_free_range(void *arg, uint64_t blkid, uint64_t nblks)
+{
+        dnode_sync_free_range_arg_t *dsfra = arg;
+        dnode_t *dn = dsfra->dsfra_dnode;
+
+        mutex_exit(&dn->dn_mtx);
+        dnode_sync_free_range_impl(dn, blkid, nblks, dsfra->dsfra_tx);
+        mutex_enter(&dn->dn_mtx);
+}
+
 /*
  * Try to kick all the dnode's dbufs out of the cache...
  */
 void
 dnode_evict_dbufs(dnode_t *dn)

@@ -531,11 +548,10 @@
  * Write out the dnode's dirty buffers.
  */
 void
 dnode_sync(dnode_t *dn, dmu_tx_t *tx)
 {
-        free_range_t *rp;
         dnode_phys_t *dnp = dn->dn_phys;
         int txgoff = tx->tx_txg & TXG_MASK;
         list_t *list = &dn->dn_dirty_records[txgoff];
         static const dnode_phys_t zerodn = { 0 };
         boolean_t kill_spill = B_FALSE;

@@ -589,13 +605,13 @@
         if (dn->dn_next_blksz[txgoff] != 0) {
                 ASSERT(P2PHASE(dn->dn_next_blksz[txgoff],
                     SPA_MINBLOCKSIZE) == 0);
                 ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
                     dn->dn_maxblkid == 0 || list_head(list) != NULL ||
-                    avl_last(&dn->dn_ranges[txgoff]) ||
                     dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT ==
-                    dnp->dn_datablkszsec);
+                    dnp->dn_datablkszsec ||
+                    range_tree_space(dn->dn_free_ranges[txgoff]) != 0);
                 dnp->dn_datablkszsec =
                     dn->dn_next_blksz[txgoff] >> SPA_MINBLOCKSHIFT;
                 dn->dn_next_blksz[txgoff] = 0;
         }
 

@@ -650,17 +666,20 @@
                 dnp->dn_flags &= ~DNODE_FLAG_SPILL_BLKPTR;
                 mutex_exit(&dn->dn_mtx);
         }
 
         /* process all the "freed" ranges in the file */
-        while (rp = avl_last(&dn->dn_ranges[txgoff])) {
-                dnode_sync_free_range(dn, rp->fr_blkid, rp->fr_nblks, tx);
-                /* grab the mutex so we don't race with dnode_block_freed() */
+        if (dn->dn_free_ranges[txgoff] != NULL) {
+                dnode_sync_free_range_arg_t dsfra;
+                dsfra.dsfra_dnode = dn;
+                dsfra.dsfra_tx = tx;
                 mutex_enter(&dn->dn_mtx);
-                avl_remove(&dn->dn_ranges[txgoff], rp);
+                range_tree_vacate(dn->dn_free_ranges[txgoff],
+                    dnode_sync_free_range, &dsfra);
+                range_tree_destroy(dn->dn_free_ranges[txgoff]);
+                dn->dn_free_ranges[txgoff] = NULL;
                 mutex_exit(&dn->dn_mtx);
-                kmem_free(rp, sizeof (free_range_t));
         }
 
         if (freeing_dnode) {
                 dnode_sync_free(dn, tx);
                 return;