Illumos #3006
[zfs.git] / module / zfs / dsl_synctask.c
index 2110022..75eb507 100644 (file)
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
-
 #include <sys/dmu.h>
 #include <sys/dmu_tx.h>
 #include <sys/dsl_pool.h>
 #include <sys/dsl_dir.h>
 #include <sys/dsl_synctask.h>
-#include <sys/cred.h>
+#include <sys/metaslab.h>
 
 #define        DST_AVG_BLKSHIFT 14
 
@@ -50,7 +47,6 @@ dsl_sync_task_group_create(dsl_pool_t *dp)
        list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t),
            offsetof(dsl_sync_task_t, dst_node));
        dstg->dstg_pool = dp;
-       dstg->dstg_cr = CRED();
 
        return (dstg);
 }
@@ -112,14 +108,21 @@ top:
                return (dstg->dstg_err);
        }
 
-       VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg));
+       /*
+        * We don't generally have many sync tasks, so pay the price of
+        * add_tail to get the tasks executed in the right order.
+        */
+       VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks,
+           dstg, txg));
 
        dmu_tx_commit(tx);
 
        txg_wait_synced(dstg->dstg_pool, txg);
 
-       if (dstg->dstg_err == EAGAIN)
+       if (dstg->dstg_err == EAGAIN) {
+               txg_wait_synced(dstg->dstg_pool, txg + TXG_DEFER_SIZE);
                goto top;
+       }
 
        return (dstg->dstg_err);
 }
@@ -131,7 +134,12 @@ dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
 
        dstg->dstg_nowaiter = B_TRUE;
        txg = dmu_tx_get_txg(tx);
-       VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg));
+       /*
+        * We don't generally have many sync tasks, so pay the price of
+        * add_tail to get the tasks executed in the right order.
+        */
+       VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks,
+           dstg, txg));
 }
 
 void
@@ -139,7 +147,7 @@ dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg)
 {
        dsl_sync_task_t *dst;
 
-       while (dst = list_head(&dstg->dstg_tasks)) {
+       while ((dst = list_head(&dstg->dstg_tasks))) {
                list_remove(&dstg->dstg_tasks, dst);
                kmem_free(dst, sizeof (dsl_sync_task_t));
        }
@@ -150,25 +158,30 @@ void
 dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
 {
        dsl_sync_task_t *dst;
-       void *tr_cookie;
+       dsl_pool_t *dp = dstg->dstg_pool;
+       uint64_t quota, used;
 
-       ASSERT3U(dstg->dstg_err, ==, 0);
+       ASSERT0(dstg->dstg_err);
 
        /*
-        * Check for sufficient space.
+        * Check for sufficient space.  We just check against what's
+        * on-disk; we don't want any in-flight accounting to get in our
+        * way, because open context may have already used up various
+        * in-core limits (arc_tempreserve, dsl_pool_tempreserve).
         */
-       dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir,
-           dstg->dstg_space, dstg->dstg_space * 3, 0, 0, &tr_cookie, tx);
-       /* don't bother trying again */
-       if (dstg->dstg_err == ERESTART)
-               dstg->dstg_err = EAGAIN;
-       if (dstg->dstg_err)
+       quota = dsl_pool_adjustedsize(dp, B_FALSE) -
+           metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
+       used = dp->dp_root_dir->dd_phys->dd_used_bytes;
+       /* MOS space is triple-dittoed, so we multiply by 3. */
+       if (dstg->dstg_space > 0 && used + dstg->dstg_space * 3 > quota) {
+               dstg->dstg_err = ENOSPC;
                return;
+       }
 
        /*
         * Check for errors by calling checkfuncs.
         */
-       rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER);
+       rw_enter(&dp->dp_config_rwlock, RW_WRITER);
        for (dst = list_head(&dstg->dstg_tasks); dst;
            dst = list_next(&dstg->dstg_tasks, dst)) {
                dst->dst_err =
@@ -183,13 +196,10 @@ dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
                 */
                for (dst = list_head(&dstg->dstg_tasks); dst;
                    dst = list_next(&dstg->dstg_tasks, dst)) {
-                       dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2,
-                           dstg->dstg_cr, tx);
+                       dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, tx);
                }
        }
-       rw_exit(&dstg->dstg_pool->dp_config_rwlock);
-
-       dsl_dir_tempreserve_clear(tr_cookie, tx);
+       rw_exit(&dp->dp_config_rwlock);
 
        if (dstg->dstg_nowaiter)
                dsl_sync_task_group_destroy(dstg);
@@ -203,6 +213,8 @@ dsl_sync_task_do(dsl_pool_t *dp,
        dsl_sync_task_group_t *dstg;
        int err;
 
+       ASSERT(spa_writeable(dp->dp_spa));
+
        dstg = dsl_sync_task_group_create(dp);
        dsl_sync_task_create(dstg, checkfunc, syncfunc,
            arg1, arg2, blocks_modified);
@@ -218,8 +230,16 @@ dsl_sync_task_do_nowait(dsl_pool_t *dp,
 {
        dsl_sync_task_group_t *dstg;
 
+       if (!spa_writeable(dp->dp_spa))
+               return;
+
        dstg = dsl_sync_task_group_create(dp);
        dsl_sync_task_create(dstg, checkfunc, syncfunc,
            arg1, arg2, blocks_modified);
        dsl_sync_task_group_nowait(dstg, tx);
 }
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_sync_task_do);
+EXPORT_SYMBOL(dsl_sync_task_do_nowait);
+#endif