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