12199Sahrens /*
22199Sahrens * CDDL HEADER START
32199Sahrens *
42199Sahrens * The contents of this file are subject to the terms of the
52199Sahrens * Common Development and Distribution License (the "License").
62199Sahrens * You may not use this file except in compliance with the License.
72199Sahrens *
82199Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92199Sahrens * or http://www.opensolaris.org/os/licensing.
102199Sahrens * See the License for the specific language governing permissions
112199Sahrens * and limitations under the License.
122199Sahrens *
132199Sahrens * When distributing Covered Code, include this CDDL HEADER in each
142199Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152199Sahrens * If applicable, add the following below this CDDL HEADER, with the
162199Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
172199Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
182199Sahrens *
192199Sahrens * CDDL HEADER END
202199Sahrens */
212199Sahrens /*
2212296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
232199Sahrens */
242199Sahrens
252199Sahrens #include <sys/dmu.h>
262199Sahrens #include <sys/dmu_tx.h>
272199Sahrens #include <sys/dsl_pool.h>
282199Sahrens #include <sys/dsl_dir.h>
292199Sahrens #include <sys/dsl_synctask.h>
3011822SMatthew.Ahrens@Sun.COM #include <sys/metaslab.h>
312199Sahrens
322199Sahrens #define DST_AVG_BLKSHIFT 14
332199Sahrens
342199Sahrens /* ARGSUSED */
352199Sahrens static int
dsl_null_checkfunc(void * arg1,void * arg2,dmu_tx_t * tx)362199Sahrens dsl_null_checkfunc(void *arg1, void *arg2, dmu_tx_t *tx)
372199Sahrens {
382199Sahrens return (0);
392199Sahrens }
402199Sahrens
412199Sahrens dsl_sync_task_group_t *
dsl_sync_task_group_create(dsl_pool_t * dp)422199Sahrens dsl_sync_task_group_create(dsl_pool_t *dp)
432199Sahrens {
442199Sahrens dsl_sync_task_group_t *dstg;
452199Sahrens
462199Sahrens dstg = kmem_zalloc(sizeof (dsl_sync_task_group_t), KM_SLEEP);
472199Sahrens list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t),
482199Sahrens offsetof(dsl_sync_task_t, dst_node));
492199Sahrens dstg->dstg_pool = dp;
502199Sahrens
512199Sahrens return (dstg);
522199Sahrens }
532199Sahrens
542199Sahrens void
dsl_sync_task_create(dsl_sync_task_group_t * dstg,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,void * arg1,void * arg2,int blocks_modified)552199Sahrens dsl_sync_task_create(dsl_sync_task_group_t *dstg,
562199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
572199Sahrens void *arg1, void *arg2, int blocks_modified)
582199Sahrens {
592199Sahrens dsl_sync_task_t *dst;
602199Sahrens
612199Sahrens if (checkfunc == NULL)
622199Sahrens checkfunc = dsl_null_checkfunc;
632199Sahrens dst = kmem_zalloc(sizeof (dsl_sync_task_t), KM_SLEEP);
642199Sahrens dst->dst_checkfunc = checkfunc;
652199Sahrens dst->dst_syncfunc = syncfunc;
662199Sahrens dst->dst_arg1 = arg1;
672199Sahrens dst->dst_arg2 = arg2;
682199Sahrens list_insert_tail(&dstg->dstg_tasks, dst);
692199Sahrens
702199Sahrens dstg->dstg_space += blocks_modified << DST_AVG_BLKSHIFT;
712199Sahrens }
722199Sahrens
732199Sahrens int
dsl_sync_task_group_wait(dsl_sync_task_group_t * dstg)742199Sahrens dsl_sync_task_group_wait(dsl_sync_task_group_t *dstg)
752199Sahrens {
762199Sahrens dmu_tx_t *tx;
772199Sahrens uint64_t txg;
782199Sahrens dsl_sync_task_t *dst;
792199Sahrens
802199Sahrens top:
812199Sahrens tx = dmu_tx_create_dd(dstg->dstg_pool->dp_mos_dir);
822199Sahrens VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT));
832199Sahrens
842199Sahrens txg = dmu_tx_get_txg(tx);
852199Sahrens
862199Sahrens /* Do a preliminary error check. */
872199Sahrens dstg->dstg_err = 0;
882199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_READER);
892199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst;
902199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) {
912199Sahrens #ifdef ZFS_DEBUG
922199Sahrens /*
932199Sahrens * Only check half the time, otherwise, the sync-context
942199Sahrens * check will almost never fail.
952199Sahrens */
962199Sahrens if (spa_get_random(2) == 0)
972199Sahrens continue;
982199Sahrens #endif
992199Sahrens dst->dst_err =
1002199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx);
1012199Sahrens if (dst->dst_err)
1022199Sahrens dstg->dstg_err = dst->dst_err;
1032199Sahrens }
1042199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock);
1052199Sahrens
1062199Sahrens if (dstg->dstg_err) {
1072199Sahrens dmu_tx_commit(tx);
1082199Sahrens return (dstg->dstg_err);
1092199Sahrens }
1102199Sahrens
11111816SMatthew.Ahrens@Sun.COM /*
11211816SMatthew.Ahrens@Sun.COM * We don't generally have many sync tasks, so pay the price of
11311816SMatthew.Ahrens@Sun.COM * add_tail to get the tasks executed in the right order.
11411816SMatthew.Ahrens@Sun.COM */
11511816SMatthew.Ahrens@Sun.COM VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks,
11611816SMatthew.Ahrens@Sun.COM dstg, txg));
1172199Sahrens
1182199Sahrens dmu_tx_commit(tx);
1192199Sahrens
1202199Sahrens txg_wait_synced(dstg->dstg_pool, txg);
1212199Sahrens
12210922SJeff.Bonwick@Sun.COM if (dstg->dstg_err == EAGAIN) {
12310922SJeff.Bonwick@Sun.COM txg_wait_synced(dstg->dstg_pool, txg + TXG_DEFER_SIZE);
1242199Sahrens goto top;
12510922SJeff.Bonwick@Sun.COM }
1262199Sahrens
1272199Sahrens return (dstg->dstg_err);
1282199Sahrens }
1292199Sahrens
1302199Sahrens void
dsl_sync_task_group_nowait(dsl_sync_task_group_t * dstg,dmu_tx_t * tx)1314577Sahrens dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
1324577Sahrens {
1334577Sahrens uint64_t txg;
1344577Sahrens
1354577Sahrens dstg->dstg_nowaiter = B_TRUE;
1364577Sahrens txg = dmu_tx_get_txg(tx);
13711816SMatthew.Ahrens@Sun.COM /*
13811816SMatthew.Ahrens@Sun.COM * We don't generally have many sync tasks, so pay the price of
13911816SMatthew.Ahrens@Sun.COM * add_tail to get the tasks executed in the right order.
14011816SMatthew.Ahrens@Sun.COM */
14111816SMatthew.Ahrens@Sun.COM VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks,
14211816SMatthew.Ahrens@Sun.COM dstg, txg));
1434577Sahrens }
1444577Sahrens
1454577Sahrens void
dsl_sync_task_group_destroy(dsl_sync_task_group_t * dstg)1462199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg)
1472199Sahrens {
1482199Sahrens dsl_sync_task_t *dst;
1492199Sahrens
1502199Sahrens while (dst = list_head(&dstg->dstg_tasks)) {
1512199Sahrens list_remove(&dstg->dstg_tasks, dst);
1522199Sahrens kmem_free(dst, sizeof (dsl_sync_task_t));
1532199Sahrens }
1542199Sahrens kmem_free(dstg, sizeof (dsl_sync_task_group_t));
1552199Sahrens }
1562199Sahrens
1572199Sahrens void
dsl_sync_task_group_sync(dsl_sync_task_group_t * dstg,dmu_tx_t * tx)1582199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
1592199Sahrens {
1602199Sahrens dsl_sync_task_t *dst;
16111822SMatthew.Ahrens@Sun.COM dsl_pool_t *dp = dstg->dstg_pool;
16211822SMatthew.Ahrens@Sun.COM uint64_t quota, used;
1632199Sahrens
1642199Sahrens ASSERT3U(dstg->dstg_err, ==, 0);
1652199Sahrens
1662199Sahrens /*
16711822SMatthew.Ahrens@Sun.COM * Check for sufficient space. We just check against what's
16811823SMatthew.Ahrens@Sun.COM * on-disk; we don't want any in-flight accounting to get in our
16911822SMatthew.Ahrens@Sun.COM * way, because open context may have already used up various
17011822SMatthew.Ahrens@Sun.COM * in-core limits (arc_tempreserve, dsl_pool_tempreserve).
1712199Sahrens */
17211822SMatthew.Ahrens@Sun.COM quota = dsl_pool_adjustedsize(dp, B_FALSE) -
17311822SMatthew.Ahrens@Sun.COM metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
17411822SMatthew.Ahrens@Sun.COM used = dp->dp_root_dir->dd_phys->dd_used_bytes;
17511822SMatthew.Ahrens@Sun.COM /* MOS space is triple-dittoed, so we multiply by 3. */
17611822SMatthew.Ahrens@Sun.COM if (dstg->dstg_space > 0 && used + dstg->dstg_space * 3 > quota) {
17711822SMatthew.Ahrens@Sun.COM dstg->dstg_err = ENOSPC;
1782199Sahrens return;
17911822SMatthew.Ahrens@Sun.COM }
1802199Sahrens
1812199Sahrens /*
1822199Sahrens * Check for errors by calling checkfuncs.
1832199Sahrens */
18411822SMatthew.Ahrens@Sun.COM rw_enter(&dp->dp_config_rwlock, RW_WRITER);
1852199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst;
1862199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) {
1872199Sahrens dst->dst_err =
1882199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx);
1892199Sahrens if (dst->dst_err)
1902199Sahrens dstg->dstg_err = dst->dst_err;
1912199Sahrens }
1922199Sahrens
1932199Sahrens if (dstg->dstg_err == 0) {
1942199Sahrens /*
1952199Sahrens * Execute sync tasks.
1962199Sahrens */
1972199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst;
1982199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) {
19912296SLin.Ling@Sun.COM dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, tx);
2002199Sahrens }
2012199Sahrens }
20211822SMatthew.Ahrens@Sun.COM rw_exit(&dp->dp_config_rwlock);
2034577Sahrens
2044577Sahrens if (dstg->dstg_nowaiter)
2054577Sahrens dsl_sync_task_group_destroy(dstg);
2062199Sahrens }
2072199Sahrens
2082199Sahrens int
dsl_sync_task_do(dsl_pool_t * dp,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,void * arg1,void * arg2,int blocks_modified)2092199Sahrens dsl_sync_task_do(dsl_pool_t *dp,
2102199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
2112199Sahrens void *arg1, void *arg2, int blocks_modified)
2122199Sahrens {
2132199Sahrens dsl_sync_task_group_t *dstg;
2142199Sahrens int err;
2152199Sahrens
216*13049SGeorge.Wilson@Sun.COM ASSERT(spa_writeable(dp->dp_spa));
217*13049SGeorge.Wilson@Sun.COM
2182199Sahrens dstg = dsl_sync_task_group_create(dp);
2192199Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc,
2202199Sahrens arg1, arg2, blocks_modified);
2212199Sahrens err = dsl_sync_task_group_wait(dstg);
2222199Sahrens dsl_sync_task_group_destroy(dstg);
2232199Sahrens return (err);
2242199Sahrens }
2254577Sahrens
2264577Sahrens void
dsl_sync_task_do_nowait(dsl_pool_t * dp,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,void * arg1,void * arg2,int blocks_modified,dmu_tx_t * tx)2274577Sahrens dsl_sync_task_do_nowait(dsl_pool_t *dp,
2284577Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
2294577Sahrens void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx)
2304577Sahrens {
2314577Sahrens dsl_sync_task_group_t *dstg;
2324577Sahrens
233*13049SGeorge.Wilson@Sun.COM if (!spa_writeable(dp->dp_spa))
234*13049SGeorge.Wilson@Sun.COM return;
235*13049SGeorge.Wilson@Sun.COM
2364577Sahrens dstg = dsl_sync_task_group_create(dp);
2374577Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc,
2384577Sahrens arg1, arg2, blocks_modified);
2394577Sahrens dsl_sync_task_group_nowait(dstg, tx);
2404577Sahrens }
241