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*11816SMatthew.Ahrens@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 232199Sahrens * Use is subject to license terms. 242199Sahrens */ 252199Sahrens 262199Sahrens #include <sys/dmu.h> 272199Sahrens #include <sys/dmu_tx.h> 282199Sahrens #include <sys/dsl_pool.h> 292199Sahrens #include <sys/dsl_dir.h> 302199Sahrens #include <sys/dsl_synctask.h> 314543Smarks #include <sys/cred.h> 322199Sahrens 332199Sahrens #define DST_AVG_BLKSHIFT 14 342199Sahrens 352199Sahrens /* ARGSUSED */ 362199Sahrens static int 372199Sahrens dsl_null_checkfunc(void *arg1, void *arg2, dmu_tx_t *tx) 382199Sahrens { 392199Sahrens return (0); 402199Sahrens } 412199Sahrens 422199Sahrens dsl_sync_task_group_t * 432199Sahrens dsl_sync_task_group_create(dsl_pool_t *dp) 442199Sahrens { 452199Sahrens dsl_sync_task_group_t *dstg; 462199Sahrens 472199Sahrens dstg = kmem_zalloc(sizeof (dsl_sync_task_group_t), KM_SLEEP); 482199Sahrens list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t), 492199Sahrens offsetof(dsl_sync_task_t, dst_node)); 502199Sahrens dstg->dstg_pool = dp; 514577Sahrens dstg->dstg_cr = CRED(); 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 113*11816SMatthew.Ahrens@Sun.COM /* 114*11816SMatthew.Ahrens@Sun.COM * We don't generally have many sync tasks, so pay the price of 115*11816SMatthew.Ahrens@Sun.COM * add_tail to get the tasks executed in the right order. 116*11816SMatthew.Ahrens@Sun.COM */ 117*11816SMatthew.Ahrens@Sun.COM VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks, 118*11816SMatthew.Ahrens@Sun.COM dstg, txg)); 1192199Sahrens 1202199Sahrens dmu_tx_commit(tx); 1212199Sahrens 1222199Sahrens txg_wait_synced(dstg->dstg_pool, txg); 1232199Sahrens 12410922SJeff.Bonwick@Sun.COM if (dstg->dstg_err == EAGAIN) { 12510922SJeff.Bonwick@Sun.COM txg_wait_synced(dstg->dstg_pool, txg + TXG_DEFER_SIZE); 1262199Sahrens goto top; 12710922SJeff.Bonwick@Sun.COM } 1282199Sahrens 1292199Sahrens return (dstg->dstg_err); 1302199Sahrens } 1312199Sahrens 1322199Sahrens void 1334577Sahrens dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 1344577Sahrens { 1354577Sahrens uint64_t txg; 1364577Sahrens 1374577Sahrens dstg->dstg_nowaiter = B_TRUE; 1384577Sahrens txg = dmu_tx_get_txg(tx); 139*11816SMatthew.Ahrens@Sun.COM /* 140*11816SMatthew.Ahrens@Sun.COM * We don't generally have many sync tasks, so pay the price of 141*11816SMatthew.Ahrens@Sun.COM * add_tail to get the tasks executed in the right order. 142*11816SMatthew.Ahrens@Sun.COM */ 143*11816SMatthew.Ahrens@Sun.COM VERIFY(0 == txg_list_add_tail(&dstg->dstg_pool->dp_sync_tasks, 144*11816SMatthew.Ahrens@Sun.COM dstg, txg)); 1454577Sahrens } 1464577Sahrens 1474577Sahrens void 1482199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg) 1492199Sahrens { 1502199Sahrens dsl_sync_task_t *dst; 1512199Sahrens 1522199Sahrens while (dst = list_head(&dstg->dstg_tasks)) { 1532199Sahrens list_remove(&dstg->dstg_tasks, dst); 1542199Sahrens kmem_free(dst, sizeof (dsl_sync_task_t)); 1552199Sahrens } 1562199Sahrens kmem_free(dstg, sizeof (dsl_sync_task_group_t)); 1572199Sahrens } 1582199Sahrens 1592199Sahrens void 1602199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 1612199Sahrens { 1622199Sahrens dsl_sync_task_t *dst; 1632199Sahrens void *tr_cookie; 1642199Sahrens 1652199Sahrens ASSERT3U(dstg->dstg_err, ==, 0); 1662199Sahrens 1672199Sahrens /* 1682199Sahrens * Check for sufficient space. 1692199Sahrens */ 1702199Sahrens dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir, 1715378Sck153898 dstg->dstg_space, dstg->dstg_space * 3, 0, 0, &tr_cookie, tx); 1722199Sahrens /* don't bother trying again */ 1732199Sahrens if (dstg->dstg_err == ERESTART) 1742532Sahrens dstg->dstg_err = EAGAIN; 1752199Sahrens if (dstg->dstg_err) 1762199Sahrens return; 1772199Sahrens 1782199Sahrens /* 1792199Sahrens * Check for errors by calling checkfuncs. 1802199Sahrens */ 1812199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER); 1822199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1832199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 1842199Sahrens dst->dst_err = 1852199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 1862199Sahrens if (dst->dst_err) 1872199Sahrens dstg->dstg_err = dst->dst_err; 1882199Sahrens } 1892199Sahrens 1902199Sahrens if (dstg->dstg_err == 0) { 1912199Sahrens /* 1922199Sahrens * Execute sync tasks. 1932199Sahrens */ 1942199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 1952199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 1964543Smarks dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, 1974577Sahrens dstg->dstg_cr, tx); 1982199Sahrens } 1992199Sahrens } 2002199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 2012199Sahrens 2022199Sahrens dsl_dir_tempreserve_clear(tr_cookie, tx); 2034577Sahrens 2044577Sahrens if (dstg->dstg_nowaiter) 2054577Sahrens dsl_sync_task_group_destroy(dstg); 2062199Sahrens } 2072199Sahrens 2082199Sahrens int 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 2162199Sahrens dstg = dsl_sync_task_group_create(dp); 2172199Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 2182199Sahrens arg1, arg2, blocks_modified); 2192199Sahrens err = dsl_sync_task_group_wait(dstg); 2202199Sahrens dsl_sync_task_group_destroy(dstg); 2212199Sahrens return (err); 2222199Sahrens } 2234577Sahrens 2244577Sahrens void 2254577Sahrens dsl_sync_task_do_nowait(dsl_pool_t *dp, 2264577Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 2274577Sahrens void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx) 2284577Sahrens { 2294577Sahrens dsl_sync_task_group_t *dstg; 2304577Sahrens 2314577Sahrens dstg = dsl_sync_task_group_create(dp); 2324577Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 2334577Sahrens arg1, arg2, blocks_modified); 2344577Sahrens dsl_sync_task_group_nowait(dstg, tx); 2354577Sahrens } 236