Illumos #3006
[zfs.git] / module / zfs / dsl_dir.c
index 2e52f9c..69f68c2 100644 (file)
@@ -47,7 +47,7 @@ static void
 dsl_dir_evict(dmu_buf_t *db, void *arg)
 {
        dsl_dir_t *dd = arg;
-       dsl_pool_t *dp = dd->dd_pool;
+       ASSERTV(dsl_pool_t *dp = dd->dd_pool;)
        int t;
 
        for (t = 0; t < TXG_SIZE; t++) {
@@ -96,7 +96,7 @@ dsl_dir_open_obj(dsl_pool_t *dp, uint64_t ddobj,
        if (dd == NULL) {
                dsl_dir_t *winner;
 
-               dd = kmem_zalloc(sizeof (dsl_dir_t), KM_SLEEP);
+               dd = kmem_zalloc(sizeof (dsl_dir_t), KM_PUSHPAGE);
                dd->dd_object = ddobj;
                dd->dd_dbuf = dbuf;
                dd->dd_pool = dp;
@@ -189,7 +189,6 @@ errout:
        kmem_free(dd, sizeof (dsl_dir_t));
        dmu_buf_rele(dbuf, tag);
        return (err);
-
 }
 
 void
@@ -223,7 +222,7 @@ dsl_dir_name(dsl_dir_t *dd, char *buf)
        }
 }
 
-/* Calculate name legnth, avoiding all the strcat calls of dsl_dir_name */
+/* Calculate name length, avoiding all the strcat calls of dsl_dir_name */
 int
 dsl_dir_namelen(dsl_dir_t *dd)
 {
@@ -296,14 +295,14 @@ getcomponent(const char *path, char *component, const char **nextp)
 }
 
 /*
- * same as dsl_open_dir, ignore the first component of name and use the
+ * same as dsl_dir_open, ignore the first component of name and use the
  * spa instead
  */
 int
 dsl_dir_open_spa(spa_t *spa, const char *name, void *tag,
     dsl_dir_t **ddp, const char **tailp)
 {
-       char buf[MAXNAMELEN];
+       char *buf;
        const char *next, *nextnext = NULL;
        int err;
        dsl_dir_t *dd;
@@ -313,14 +312,15 @@ dsl_dir_open_spa(spa_t *spa, const char *name, void *tag,
 
        dprintf("%s\n", name);
 
+       buf = kmem_alloc(MAXNAMELEN, KM_PUSHPAGE);
        err = getcomponent(name, buf, &next);
        if (err)
-               return (err);
+               goto error;
        if (spa == NULL) {
                err = spa_open(buf, &spa, FTAG);
                if (err) {
                        dprintf("spa_open(%s) failed\n", buf);
-                       return (err);
+                       goto error;
                }
                openedspa = TRUE;
 
@@ -336,7 +336,7 @@ dsl_dir_open_spa(spa_t *spa, const char *name, void *tag,
                rw_exit(&dp->dp_config_rwlock);
                if (openedspa)
                        spa_close(spa, FTAG);
-               return (err);
+               goto error;
        }
 
        while (next != NULL) {
@@ -372,7 +372,7 @@ dsl_dir_open_spa(spa_t *spa, const char *name, void *tag,
                dsl_dir_close(dd, tag);
                if (openedspa)
                        spa_close(spa, FTAG);
-               return (err);
+               goto error;
        }
 
        /*
@@ -391,6 +391,8 @@ dsl_dir_open_spa(spa_t *spa, const char *name, void *tag,
        if (openedspa)
                spa_close(spa, FTAG);
        *ddp = dd;
+error:
+       kmem_free(buf, MAXNAMELEN);
        return (err);
 }
 
@@ -457,12 +459,14 @@ dsl_dir_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx)
        /*
         * There should be exactly two holds, both from
         * dsl_dataset_destroy: one on the dd directory, and one on its
-        * head ds.  Otherwise, someone is trying to lookup something
-        * inside this dir while we want to destroy it.  The
-        * config_rwlock ensures that nobody else opens it after we
-        * check.
+        * head ds.  If there are more holds, then a concurrent thread is
+        * performing a lookup inside this dir while we're trying to destroy
+        * it.  To minimize this possibility, we perform this check only
+        * in syncing context and fail the operation if we encounter
+        * additional holds.  The dp_config_rwlock ensures that nobody else
+        * opens it after we check.
         */
-       if (dmu_buf_refcount(dd->dd_dbuf) > 2)
+       if (dmu_tx_is_syncing(tx) && dmu_buf_refcount(dd->dd_dbuf) > 2)
                return (EBUSY);
 
        err = zap_count(mos, dd->dd_phys->dd_child_dir_zapobj, &count);
@@ -496,10 +500,10 @@ dsl_dir_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx)
 
        dsl_dir_set_reservation_sync(ds, &psa, tx);
 
-       ASSERT3U(dd->dd_phys->dd_used_bytes, ==, 0);
-       ASSERT3U(dd->dd_phys->dd_reserved, ==, 0);
+       ASSERT0(dd->dd_phys->dd_used_bytes);
+       ASSERT0(dd->dd_phys->dd_reserved);
        for (t = 0; t < DD_USED_NUM; t++)
-               ASSERT3U(dd->dd_phys->dd_used_breakdown[t], ==, 0);
+               ASSERT0(dd->dd_phys->dd_used_breakdown[t]);
 
        VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_child_dir_zapobj, tx));
        VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_props_zapobj, tx));
@@ -587,10 +591,8 @@ dsl_dir_sync(dsl_dir_t *dd, dmu_tx_t *tx)
 {
        ASSERT(dmu_tx_is_syncing(tx));
 
-       dmu_buf_will_dirty(dd->dd_dbuf, tx);
-
        mutex_enter(&dd->dd_lock);
-       ASSERT3U(dd->dd_tempreserved[tx->tx_txg&TXG_MASK], ==, 0);
+       ASSERT0(dd->dd_tempreserved[tx->tx_txg&TXG_MASK]);
        dprintf_dd(dd, "txg=%llu towrite=%lluK\n", tx->tx_txg,
            dd->dd_space_towrite[tx->tx_txg&TXG_MASK] / 1024);
        dd->dd_space_towrite[tx->tx_txg&TXG_MASK] = 0;
@@ -788,7 +790,7 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree,
            asize - ref_rsrv);
        mutex_exit(&dd->dd_lock);
 
-       tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
+       tr = kmem_zalloc(sizeof (struct tempreserve), KM_PUSHPAGE);
        tr->tr_ds = dd;
        tr->tr_size = asize;
        list_insert_tail(tr_list, tr);
@@ -822,7 +824,7 @@ dsl_dir_tempreserve_space(dsl_dir_t *dd, uint64_t lsize, uint64_t asize,
                return (0);
        }
 
-       tr_list = kmem_alloc(sizeof (list_t), KM_SLEEP);
+       tr_list = kmem_alloc(sizeof (list_t), KM_PUSHPAGE);
        list_create(tr_list, sizeof (struct tempreserve),
            offsetof(struct tempreserve, tr_node));
        ASSERT3S(asize, >, 0);
@@ -832,7 +834,7 @@ dsl_dir_tempreserve_space(dsl_dir_t *dd, uint64_t lsize, uint64_t asize,
        if (err == 0) {
                struct tempreserve *tr;
 
-               tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
+               tr = kmem_zalloc(sizeof (struct tempreserve), KM_PUSHPAGE);
                tr->tr_size = lsize;
                list_insert_tail(tr_list, tr);
 
@@ -848,7 +850,7 @@ dsl_dir_tempreserve_space(dsl_dir_t *dd, uint64_t lsize, uint64_t asize,
        if (err == 0) {
                struct tempreserve *tr;
 
-               tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
+               tr = kmem_zalloc(sizeof (struct tempreserve), KM_PUSHPAGE);
                tr->tr_dp = dd->dd_pool;
                tr->tr_size = asize;
                list_insert_tail(tr_list, tr);
@@ -945,8 +947,6 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
        ASSERT(dmu_tx_is_syncing(tx));
        ASSERT(type < DD_USED_NUM);
 
-       dsl_dir_dirty(dd, tx);
-
        if (needlock)
                mutex_enter(&dd->dd_lock);
        accounted_delta = parent_delta(dd, dd->dd_phys->dd_used_bytes, used);
@@ -955,6 +955,7 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
            dd->dd_phys->dd_compressed_bytes >= -compressed);
        ASSERT(uncompressed >= 0 ||
            dd->dd_phys->dd_uncompressed_bytes >= -uncompressed);
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
        dd->dd_phys->dd_used_bytes += used;
        dd->dd_phys->dd_uncompressed_bytes += uncompressed;
        dd->dd_phys->dd_compressed_bytes += compressed;
@@ -998,13 +999,13 @@ dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta,
        if (delta == 0 || !(dd->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN))
                return;
 
-       dsl_dir_dirty(dd, tx);
        if (needlock)
                mutex_enter(&dd->dd_lock);
        ASSERT(delta > 0 ?
            dd->dd_phys->dd_used_breakdown[oldtype] >= delta :
            dd->dd_phys->dd_used_breakdown[newtype] >= -delta);
        ASSERT(dd->dd_phys->dd_used_bytes >= ABS(delta));
+       dmu_buf_will_dirty(dd->dd_dbuf, tx);
        dd->dd_phys->dd_used_breakdown[oldtype] -= delta;
        dd->dd_phys->dd_used_breakdown[newtype] += delta;
        if (needlock)
@@ -1061,10 +1062,6 @@ dsl_dir_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx)
        mutex_enter(&dd->dd_lock);
        dd->dd_phys->dd_quota = effective_value;
        mutex_exit(&dd->dd_lock);
-
-       spa_history_log_internal(LOG_DS_QUOTA, dd->dd_pool->dp_spa,
-           tx, "%lld dataset = %llu ",
-           (longlong_t)effective_value, dd->dd_phys->dd_head_dataset_obj);
 }
 
 int
@@ -1177,10 +1174,6 @@ dsl_dir_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
                    delta, 0, 0, tx);
        }
        mutex_exit(&dd->dd_lock);
-
-       spa_history_log_internal(LOG_DS_RESERVATION, dd->dd_pool->dp_spa,
-           tx, "%lld dataset = %llu",
-           (longlong_t)effective_value, dd->dd_phys->dd_head_dataset_obj);
 }
 
 int
@@ -1330,7 +1323,7 @@ dsl_dir_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
        /* remove from old parent zapobj */
        err = zap_remove(mos, dd->dd_parent->dd_phys->dd_child_dir_zapobj,
            dd->dd_myname, tx);
-       ASSERT3U(err, ==, 0);
+       ASSERT0(err);
 
        (void) strcpy(dd->dd_myname, ra->mynewname);
        dsl_dir_close(dd->dd_parent, dd);
@@ -1341,7 +1334,7 @@ dsl_dir_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
        /* add to new parent zapobj */
        err = zap_add(mos, ra->newparent->dd_phys->dd_child_dir_zapobj,
            dd->dd_myname, 8, 1, &dd->dd_object, tx);
-       ASSERT3U(err, ==, 0);
+       ASSERT0(err);
 
        spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa,
            tx, "dataset = %llu", dd->dd_phys->dd_head_dataset_obj);
@@ -1416,3 +1409,10 @@ dsl_dir_snap_cmtime_update(dsl_dir_t *dd)
        dd->dd_snap_cmtime = t;
        mutex_exit(&dd->dd_lock);
 }
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_dir_set_quota);
+EXPORT_SYMBOL(dsl_dir_set_reservation);
+EXPORT_SYMBOL(dsl_dir_open);
+EXPORT_SYMBOL(dsl_dir_close);
+#endif