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 /* 22*4543Smarks * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 232199Sahrens * Use is subject to license terms. 242199Sahrens */ 252199Sahrens 262199Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 272199Sahrens 282199Sahrens #include <sys/dmu.h> 292199Sahrens #include <sys/dmu_tx.h> 302199Sahrens #include <sys/dsl_pool.h> 312199Sahrens #include <sys/dsl_dir.h> 322199Sahrens #include <sys/dsl_synctask.h> 33*4543Smarks #include <sys/cred.h> 342199Sahrens 352199Sahrens #define DST_AVG_BLKSHIFT 14 362199Sahrens 372199Sahrens /* ARGSUSED */ 382199Sahrens static int 392199Sahrens dsl_null_checkfunc(void *arg1, void *arg2, dmu_tx_t *tx) 402199Sahrens { 412199Sahrens return (0); 422199Sahrens } 432199Sahrens 442199Sahrens dsl_sync_task_group_t * 452199Sahrens dsl_sync_task_group_create(dsl_pool_t *dp) 462199Sahrens { 472199Sahrens dsl_sync_task_group_t *dstg; 482199Sahrens 492199Sahrens dstg = kmem_zalloc(sizeof (dsl_sync_task_group_t), KM_SLEEP); 502199Sahrens list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t), 512199Sahrens offsetof(dsl_sync_task_t, dst_node)); 522199Sahrens dstg->dstg_pool = dp; 532199Sahrens 542199Sahrens return (dstg); 552199Sahrens } 562199Sahrens 572199Sahrens void 582199Sahrens dsl_sync_task_create(dsl_sync_task_group_t *dstg, 592199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 602199Sahrens void *arg1, void *arg2, int blocks_modified) 612199Sahrens { 622199Sahrens dsl_sync_task_t *dst; 632199Sahrens 642199Sahrens if (checkfunc == NULL) 652199Sahrens checkfunc = dsl_null_checkfunc; 662199Sahrens dst = kmem_zalloc(sizeof (dsl_sync_task_t), KM_SLEEP); 672199Sahrens dst->dst_checkfunc = checkfunc; 682199Sahrens dst->dst_syncfunc = syncfunc; 692199Sahrens dst->dst_arg1 = arg1; 702199Sahrens dst->dst_arg2 = arg2; 71*4543Smarks dst->dst_cr = CRED(); 722199Sahrens list_insert_tail(&dstg->dstg_tasks, dst); 732199Sahrens 742199Sahrens dstg->dstg_space += blocks_modified << DST_AVG_BLKSHIFT; 752199Sahrens } 762199Sahrens 772199Sahrens int 782199Sahrens dsl_sync_task_group_wait(dsl_sync_task_group_t *dstg) 792199Sahrens { 802199Sahrens dmu_tx_t *tx; 812199Sahrens uint64_t txg; 822199Sahrens dsl_sync_task_t *dst; 832199Sahrens 842199Sahrens top: 852199Sahrens tx = dmu_tx_create_dd(dstg->dstg_pool->dp_mos_dir); 862199Sahrens VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT)); 872199Sahrens 882199Sahrens txg = dmu_tx_get_txg(tx); 892199Sahrens 902199Sahrens /* Do a preliminary error check. */ 912199Sahrens dstg->dstg_err = 0; 922199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_READER); 932199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 942199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 952199Sahrens #ifdef ZFS_DEBUG 962199Sahrens /* 972199Sahrens * Only check half the time, otherwise, the sync-context 982199Sahrens * check will almost never fail. 992199Sahrens */ 1002199Sahrens if (spa_get_random(2) == 0) 1012199Sahrens continue; 1022199Sahrens #endif 1032199Sahrens dst->dst_err = 1042199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 1052199Sahrens if (dst->dst_err) 1062199Sahrens dstg->dstg_err = dst->dst_err; 1072199Sahrens } 1082199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 1092199Sahrens 1102199Sahrens if (dstg->dstg_err) { 1112199Sahrens dmu_tx_commit(tx); 1122199Sahrens return (dstg->dstg_err); 1132199Sahrens } 1142199Sahrens 1152199Sahrens VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg)); 1162199Sahrens 1172199Sahrens dmu_tx_commit(tx); 1182199Sahrens 1192199Sahrens txg_wait_synced(dstg->dstg_pool, txg); 1202199Sahrens 1212199Sahrens if (dstg->dstg_err == EAGAIN) 1222199Sahrens goto top; 1232199Sahrens 1242199Sahrens return (dstg->dstg_err); 1252199Sahrens } 1262199Sahrens 1272199Sahrens void 1282199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg) 1292199Sahrens { 1302199Sahrens dsl_sync_task_t *dst; 1312199Sahrens 1322199Sahrens while (dst = list_head(&dstg->dstg_tasks)) { 1332199Sahrens list_remove(&dstg->dstg_tasks, dst); 1342199Sahrens kmem_free(dst, sizeof (dsl_sync_task_t)); 1352199Sahrens } 1362199Sahrens kmem_free(dstg, sizeof (dsl_sync_task_group_t)); 1372199Sahrens } 1382199Sahrens 1392199Sahrens void 1402199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 1412199Sahrens { 1422199Sahrens dsl_sync_task_t *dst; 1432199Sahrens void *tr_cookie; 1442199Sahrens 1452199Sahrens ASSERT3U(dstg->dstg_err, ==, 0); 1462199Sahrens 1472199Sahrens /* 1482199Sahrens * Check for sufficient space. 1492199Sahrens */ 1502199Sahrens dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir, 1512199Sahrens dstg->dstg_space, dstg->dstg_space * 3, 0, &tr_cookie, tx); 1522199Sahrens /* don't bother trying again */ 1532199Sahrens if (dstg->dstg_err == ERESTART) 1542532Sahrens dstg->dstg_err = EAGAIN; 1552199Sahrens if (dstg->dstg_err) 1562199Sahrens return; 1572199Sahrens 1582199Sahrens /* 1592199Sahrens * Check for errors by calling checkfuncs. 1602199Sahrens */ 1612199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER); 1622199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1632199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 1642199Sahrens dst->dst_err = 1652199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 1662199Sahrens if (dst->dst_err) 1672199Sahrens dstg->dstg_err = dst->dst_err; 1682199Sahrens } 1692199Sahrens 1702199Sahrens if (dstg->dstg_err == 0) { 1712199Sahrens /* 1722199Sahrens * Execute sync tasks. 1732199Sahrens */ 1742199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1752199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 176*4543Smarks dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, 177*4543Smarks dst->dst_cr, tx); 1782199Sahrens } 1792199Sahrens } 1802199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 1812199Sahrens 1822199Sahrens dsl_dir_tempreserve_clear(tr_cookie, tx); 1832199Sahrens } 1842199Sahrens 1852199Sahrens int 1862199Sahrens dsl_sync_task_do(dsl_pool_t *dp, 1872199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 1882199Sahrens void *arg1, void *arg2, int blocks_modified) 1892199Sahrens { 1902199Sahrens dsl_sync_task_group_t *dstg; 1912199Sahrens int err; 1922199Sahrens 1932199Sahrens dstg = dsl_sync_task_group_create(dp); 1942199Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 1952199Sahrens arg1, arg2, blocks_modified); 1962199Sahrens err = dsl_sync_task_group_wait(dstg); 1972199Sahrens dsl_sync_task_group_destroy(dstg); 1982199Sahrens return (err); 1992199Sahrens } 200