1*2199Sahrens /* 2*2199Sahrens * CDDL HEADER START 3*2199Sahrens * 4*2199Sahrens * The contents of this file are subject to the terms of the 5*2199Sahrens * Common Development and Distribution License (the "License"). 6*2199Sahrens * You may not use this file except in compliance with the License. 7*2199Sahrens * 8*2199Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2199Sahrens * or http://www.opensolaris.org/os/licensing. 10*2199Sahrens * See the License for the specific language governing permissions 11*2199Sahrens * and limitations under the License. 12*2199Sahrens * 13*2199Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14*2199Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2199Sahrens * If applicable, add the following below this CDDL HEADER, with the 16*2199Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17*2199Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18*2199Sahrens * 19*2199Sahrens * CDDL HEADER END 20*2199Sahrens */ 21*2199Sahrens /* 22*2199Sahrens * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*2199Sahrens * Use is subject to license terms. 24*2199Sahrens */ 25*2199Sahrens 26*2199Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27*2199Sahrens 28*2199Sahrens #include <sys/dmu.h> 29*2199Sahrens #include <sys/dmu_tx.h> 30*2199Sahrens #include <sys/dsl_pool.h> 31*2199Sahrens #include <sys/dsl_dir.h> 32*2199Sahrens #include <sys/dsl_synctask.h> 33*2199Sahrens 34*2199Sahrens #define DST_AVG_BLKSHIFT 14 35*2199Sahrens 36*2199Sahrens /* ARGSUSED */ 37*2199Sahrens static int 38*2199Sahrens dsl_null_checkfunc(void *arg1, void *arg2, dmu_tx_t *tx) 39*2199Sahrens { 40*2199Sahrens return (0); 41*2199Sahrens } 42*2199Sahrens 43*2199Sahrens dsl_sync_task_group_t * 44*2199Sahrens dsl_sync_task_group_create(dsl_pool_t *dp) 45*2199Sahrens { 46*2199Sahrens dsl_sync_task_group_t *dstg; 47*2199Sahrens 48*2199Sahrens dstg = kmem_zalloc(sizeof (dsl_sync_task_group_t), KM_SLEEP); 49*2199Sahrens list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t), 50*2199Sahrens offsetof(dsl_sync_task_t, dst_node)); 51*2199Sahrens dstg->dstg_pool = dp; 52*2199Sahrens 53*2199Sahrens return (dstg); 54*2199Sahrens } 55*2199Sahrens 56*2199Sahrens void 57*2199Sahrens dsl_sync_task_create(dsl_sync_task_group_t *dstg, 58*2199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 59*2199Sahrens void *arg1, void *arg2, int blocks_modified) 60*2199Sahrens { 61*2199Sahrens dsl_sync_task_t *dst; 62*2199Sahrens 63*2199Sahrens if (checkfunc == NULL) 64*2199Sahrens checkfunc = dsl_null_checkfunc; 65*2199Sahrens dst = kmem_zalloc(sizeof (dsl_sync_task_t), KM_SLEEP); 66*2199Sahrens dst->dst_checkfunc = checkfunc; 67*2199Sahrens dst->dst_syncfunc = syncfunc; 68*2199Sahrens dst->dst_arg1 = arg1; 69*2199Sahrens dst->dst_arg2 = arg2; 70*2199Sahrens list_insert_tail(&dstg->dstg_tasks, dst); 71*2199Sahrens 72*2199Sahrens dstg->dstg_space += blocks_modified << DST_AVG_BLKSHIFT; 73*2199Sahrens } 74*2199Sahrens 75*2199Sahrens int 76*2199Sahrens dsl_sync_task_group_wait(dsl_sync_task_group_t *dstg) 77*2199Sahrens { 78*2199Sahrens dmu_tx_t *tx; 79*2199Sahrens uint64_t txg; 80*2199Sahrens dsl_sync_task_t *dst; 81*2199Sahrens 82*2199Sahrens top: 83*2199Sahrens tx = dmu_tx_create_dd(dstg->dstg_pool->dp_mos_dir); 84*2199Sahrens VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT)); 85*2199Sahrens 86*2199Sahrens txg = dmu_tx_get_txg(tx); 87*2199Sahrens 88*2199Sahrens /* Do a preliminary error check. */ 89*2199Sahrens dstg->dstg_err = 0; 90*2199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_READER); 91*2199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 92*2199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 93*2199Sahrens #ifdef ZFS_DEBUG 94*2199Sahrens /* 95*2199Sahrens * Only check half the time, otherwise, the sync-context 96*2199Sahrens * check will almost never fail. 97*2199Sahrens */ 98*2199Sahrens if (spa_get_random(2) == 0) 99*2199Sahrens continue; 100*2199Sahrens #endif 101*2199Sahrens dst->dst_err = 102*2199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 103*2199Sahrens if (dst->dst_err) 104*2199Sahrens dstg->dstg_err = dst->dst_err; 105*2199Sahrens } 106*2199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 107*2199Sahrens 108*2199Sahrens if (dstg->dstg_err) { 109*2199Sahrens dmu_tx_commit(tx); 110*2199Sahrens return (dstg->dstg_err); 111*2199Sahrens } 112*2199Sahrens 113*2199Sahrens VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg)); 114*2199Sahrens 115*2199Sahrens dmu_tx_commit(tx); 116*2199Sahrens 117*2199Sahrens txg_wait_synced(dstg->dstg_pool, txg); 118*2199Sahrens 119*2199Sahrens if (dstg->dstg_err == EAGAIN) 120*2199Sahrens goto top; 121*2199Sahrens 122*2199Sahrens return (dstg->dstg_err); 123*2199Sahrens } 124*2199Sahrens 125*2199Sahrens void 126*2199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg) 127*2199Sahrens { 128*2199Sahrens dsl_sync_task_t *dst; 129*2199Sahrens 130*2199Sahrens while (dst = list_head(&dstg->dstg_tasks)) { 131*2199Sahrens list_remove(&dstg->dstg_tasks, dst); 132*2199Sahrens kmem_free(dst, sizeof (dsl_sync_task_t)); 133*2199Sahrens } 134*2199Sahrens kmem_free(dstg, sizeof (dsl_sync_task_group_t)); 135*2199Sahrens } 136*2199Sahrens 137*2199Sahrens void 138*2199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) 139*2199Sahrens { 140*2199Sahrens dsl_sync_task_t *dst; 141*2199Sahrens void *tr_cookie; 142*2199Sahrens 143*2199Sahrens ASSERT3U(dstg->dstg_err, ==, 0); 144*2199Sahrens 145*2199Sahrens /* 146*2199Sahrens * Check for sufficient space. 147*2199Sahrens */ 148*2199Sahrens dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir, 149*2199Sahrens dstg->dstg_space, dstg->dstg_space * 3, 0, &tr_cookie, tx); 150*2199Sahrens /* don't bother trying again */ 151*2199Sahrens if (dstg->dstg_err == ERESTART) 152*2199Sahrens dstg->dstg_err = ENOSPC; 153*2199Sahrens if (dstg->dstg_err) 154*2199Sahrens return; 155*2199Sahrens 156*2199Sahrens /* 157*2199Sahrens * Check for errors by calling checkfuncs. 158*2199Sahrens */ 159*2199Sahrens rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER); 160*2199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 161*2199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 162*2199Sahrens dst->dst_err = 163*2199Sahrens dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx); 164*2199Sahrens if (dst->dst_err) 165*2199Sahrens dstg->dstg_err = dst->dst_err; 166*2199Sahrens } 167*2199Sahrens 168*2199Sahrens if (dstg->dstg_err == 0) { 169*2199Sahrens /* 170*2199Sahrens * Execute sync tasks. 171*2199Sahrens */ 172*2199Sahrens for (dst = list_head(&dstg->dstg_tasks); dst; 173*2199Sahrens dst = list_next(&dstg->dstg_tasks, dst)) { 174*2199Sahrens dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, tx); 175*2199Sahrens } 176*2199Sahrens } 177*2199Sahrens rw_exit(&dstg->dstg_pool->dp_config_rwlock); 178*2199Sahrens 179*2199Sahrens dsl_dir_tempreserve_clear(tr_cookie, tx); 180*2199Sahrens } 181*2199Sahrens 182*2199Sahrens int 183*2199Sahrens dsl_sync_task_do(dsl_pool_t *dp, 184*2199Sahrens dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, 185*2199Sahrens void *arg1, void *arg2, int blocks_modified) 186*2199Sahrens { 187*2199Sahrens dsl_sync_task_group_t *dstg; 188*2199Sahrens int err; 189*2199Sahrens 190*2199Sahrens dstg = dsl_sync_task_group_create(dp); 191*2199Sahrens dsl_sync_task_create(dstg, checkfunc, syncfunc, 192*2199Sahrens arg1, arg2, blocks_modified); 193*2199Sahrens err = dsl_sync_task_group_wait(dstg); 194*2199Sahrens dsl_sync_task_group_destroy(dstg); 195*2199Sahrens return (err); 196*2199Sahrens } 197