1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2013 by Delphix. All rights reserved. 24 */ 25 26 #include <sys/dmu.h> 27 #include <sys/dmu_tx.h> 28 #include <sys/dsl_pool.h> 29 #include <sys/dsl_dir.h> 30 #include <sys/dsl_synctask.h> 31 #include <sys/metaslab.h> 32 33 #define DST_AVG_BLKSHIFT 14 34 35 /* ARGSUSED */ 36 static int 37 dsl_null_checkfunc(void *arg, dmu_tx_t *tx) 38 { 39 return (0); 40 } 41 42 /* 43 * Called from open context to perform a callback in syncing context. Waits 44 * for the operation to complete. 45 * 46 * The checkfunc will be called from open context as a preliminary check 47 * which can quickly fail. If it succeeds, it will be called again from 48 * syncing context. The checkfunc should generally be designed to work 49 * properly in either context, but if necessary it can check 50 * dmu_tx_is_syncing(tx). 51 * 52 * The synctask infrastructure enforces proper locking strategy with respect 53 * to the dp_config_rwlock -- the lock will always be held when the callbacks 54 * are called. It will be held for read during the open-context (preliminary) 55 * call to the checkfunc, and then held for write from syncing context during 56 * the calls to the check and sync funcs. 57 * 58 * A dataset or pool name can be passed as the first argument. Typically, 59 * the check func will hold, check the return value of the hold, and then 60 * release the dataset. The sync func will VERIFYO(hold()) the dataset. 61 * This is safe because no changes can be made between the check and sync funcs, 62 * and the sync func will only be called if the check func successfully opened 63 * the dataset. 64 */ 65 int 66 dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc, 67 dsl_syncfunc_t *syncfunc, void *arg, int blocks_modified) 68 { 69 spa_t *spa; 70 dmu_tx_t *tx; 71 int err; 72 dsl_sync_task_t dst = { 0 }; 73 dsl_pool_t *dp; 74 75 err = spa_open(pool, &spa, FTAG); 76 if (err != 0) 77 return (err); 78 dp = spa_get_dsl(spa); 79 80 top: 81 tx = dmu_tx_create_dd(dp->dp_mos_dir); 82 VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); 83 84 dst.dst_pool = dp; 85 dst.dst_txg = dmu_tx_get_txg(tx); 86 dst.dst_space = blocks_modified << DST_AVG_BLKSHIFT; 87 dst.dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc; 88 dst.dst_syncfunc = syncfunc; 89 dst.dst_arg = arg; 90 dst.dst_error = 0; 91 dst.dst_nowaiter = B_FALSE; 92 93 dsl_pool_config_enter(dp, FTAG); 94 err = dst.dst_checkfunc(arg, tx); 95 dsl_pool_config_exit(dp, FTAG); 96 97 if (err != 0) { 98 dmu_tx_commit(tx); 99 spa_close(spa, FTAG); 100 return (err); 101 } 102 103 VERIFY(txg_list_add_tail(&dp->dp_sync_tasks, &dst, dst.dst_txg)); 104 105 dmu_tx_commit(tx); 106 107 txg_wait_synced(dp, dst.dst_txg); 108 109 if (dst.dst_error == EAGAIN) { 110 txg_wait_synced(dp, dst.dst_txg + TXG_DEFER_SIZE); 111 goto top; 112 } 113 114 spa_close(spa, FTAG); 115 return (dst.dst_error); 116 } 117 118 void 119 dsl_sync_task_nowait(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg, 120 int blocks_modified, dmu_tx_t *tx) 121 { 122 dsl_sync_task_t *dst = kmem_zalloc(sizeof (*dst), KM_SLEEP); 123 124 dst->dst_pool = dp; 125 dst->dst_txg = dmu_tx_get_txg(tx); 126 dst->dst_space = blocks_modified << DST_AVG_BLKSHIFT; 127 dst->dst_checkfunc = dsl_null_checkfunc; 128 dst->dst_syncfunc = syncfunc; 129 dst->dst_arg = arg; 130 dst->dst_error = 0; 131 dst->dst_nowaiter = B_TRUE; 132 133 VERIFY(txg_list_add_tail(&dp->dp_sync_tasks, dst, dst->dst_txg)); 134 } 135 136 /* 137 * Called in syncing context to execute the synctask. 138 */ 139 void 140 dsl_sync_task_sync(dsl_sync_task_t *dst, dmu_tx_t *tx) 141 { 142 dsl_pool_t *dp = dst->dst_pool; 143 uint64_t quota, used; 144 145 ASSERT0(dst->dst_error); 146 147 /* 148 * Check for sufficient space. We just check against what's 149 * on-disk; we don't want any in-flight accounting to get in our 150 * way, because open context may have already used up various 151 * in-core limits (arc_tempreserve, dsl_pool_tempreserve). 152 */ 153 quota = dsl_pool_adjustedsize(dp, B_FALSE) - 154 metaslab_class_get_deferred(spa_normal_class(dp->dp_spa)); 155 used = dp->dp_root_dir->dd_phys->dd_used_bytes; 156 /* MOS space is triple-dittoed, so we multiply by 3. */ 157 if (dst->dst_space > 0 && used + dst->dst_space * 3 > quota) { 158 dst->dst_error = SET_ERROR(ENOSPC); 159 if (dst->dst_nowaiter) 160 kmem_free(dst, sizeof (*dst)); 161 return; 162 } 163 164 /* 165 * Check for errors by calling checkfunc. 166 */ 167 rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG); 168 dst->dst_error = dst->dst_checkfunc(dst->dst_arg, tx); 169 if (dst->dst_error == 0) 170 dst->dst_syncfunc(dst->dst_arg, tx); 171 rrw_exit(&dp->dp_config_rwlock, FTAG); 172 if (dst->dst_nowaiter) 173 kmem_free(dst, sizeof (*dst)); 174 } 175