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 /* 224543Smarks * 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> 334543Smarks #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; 53*4577Sahrens dstg->dstg_cr = CRED(); 542199Sahrens 552199Sahrens return (dstg); 562199Sahrens } 572199Sahrens 582199Sahrens void 592199Sahrens dsl_sync_task_create(dsl_sync_task_group_t *dstg, 602199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 612199Sahrens void *arg1, void *arg2, int blocks_modified) 622199Sahrens { 632199Sahrens dsl_sync_task_t *dst; 642199Sahrens 652199Sahrens if (checkfunc == NULL) 662199Sahrens checkfunc = dsl_null_checkfunc; 672199Sahrens dst = kmem_zalloc(sizeof (dsl_sync_task_t), KM_SLEEP); 682199Sahrens dst->dst_checkfunc = checkfunc; 692199Sahrens dst->dst_syncfunc = syncfunc; 702199Sahrens dst->dst_arg1 = arg1; 712199Sahrens dst->dst_arg2 = arg2; 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 128*4577Sahrens dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 129*4577Sahrens { 130*4577Sahrens uint64_t txg; 131*4577Sahrens 132*4577Sahrens dstg->dstg_nowaiter = B_TRUE; 133*4577Sahrens txg = dmu_tx_get_txg(tx); 134*4577Sahrens VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg)); 135*4577Sahrens } 136*4577Sahrens 137*4577Sahrens void 1382199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg) 1392199Sahrens { 1402199Sahrens dsl_sync_task_t *dst; 1412199Sahrens 1422199Sahrens while (dst = list_head(&dstg->dstg_tasks)) { 1432199Sahrens list_remove(&dstg->dstg_tasks, dst); 1442199Sahrens kmem_free(dst, sizeof (dsl_sync_task_t)); 1452199Sahrens } 1462199Sahrens kmem_free(dstg, sizeof (dsl_sync_task_group_t)); 1472199Sahrens } 1482199Sahrens 1492199Sahrens void 1502199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 1512199Sahrens { 1522199Sahrens dsl_sync_task_t *dst; 1532199Sahrens void *tr_cookie; 1542199Sahrens 1552199Sahrens ASSERT3U(dstg->dstg_err, ==, 0); 1562199Sahrens 1572199Sahrens /* 1582199Sahrens * Check for sufficient space. 1592199Sahrens */ 1602199Sahrens dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir, 1612199Sahrens dstg->dstg_space, dstg->dstg_space * 3, 0, &tr_cookie, tx); 1622199Sahrens /* don't bother trying again */ 1632199Sahrens if (dstg->dstg_err == ERESTART) 1642532Sahrens dstg->dstg_err = EAGAIN; 1652199Sahrens if (dstg->dstg_err) 1662199Sahrens return; 1672199Sahrens 1682199Sahrens /* 1692199Sahrens * Check for errors by calling checkfuncs. 1702199Sahrens */ 1712199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER); 1722199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1732199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 1742199Sahrens dst->dst_err = 1752199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 1762199Sahrens if (dst->dst_err) 1772199Sahrens dstg->dstg_err = dst->dst_err; 1782199Sahrens } 1792199Sahrens 1802199Sahrens if (dstg->dstg_err == 0) { 1812199Sahrens /* 1822199Sahrens * Execute sync tasks. 1832199Sahrens */ 1842199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1852199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 1864543Smarks dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, 187*4577Sahrens dstg->dstg_cr, tx); 1882199Sahrens } 1892199Sahrens } 1902199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 1912199Sahrens 1922199Sahrens dsl_dir_tempreserve_clear(tr_cookie, tx); 193*4577Sahrens 194*4577Sahrens if (dstg->dstg_nowaiter) 195*4577Sahrens dsl_sync_task_group_destroy(dstg); 1962199Sahrens } 1972199Sahrens 1982199Sahrens int 1992199Sahrens dsl_sync_task_do(dsl_pool_t *dp, 2002199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 2012199Sahrens void *arg1, void *arg2, int blocks_modified) 2022199Sahrens { 2032199Sahrens dsl_sync_task_group_t *dstg; 2042199Sahrens int err; 2052199Sahrens 2062199Sahrens dstg = dsl_sync_task_group_create(dp); 2072199Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 2082199Sahrens arg1, arg2, blocks_modified); 2092199Sahrens err = dsl_sync_task_group_wait(dstg); 2102199Sahrens dsl_sync_task_group_destroy(dstg); 2112199Sahrens return (err); 2122199Sahrens } 213*4577Sahrens 214*4577Sahrens void 215*4577Sahrens dsl_sync_task_do_nowait(dsl_pool_t *dp, 216*4577Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 217*4577Sahrens void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx) 218*4577Sahrens { 219*4577Sahrens dsl_sync_task_group_t *dstg; 220*4577Sahrens 221*4577Sahrens dstg = dsl_sync_task_group_create(dp); 222*4577Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 223*4577Sahrens arg1, arg2, blocks_modified); 224*4577Sahrens dsl_sync_task_group_nowait(dstg, tx); 225*4577Sahrens } 226