1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12 /*
13 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
14 * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
15 */
16
17 #include <sys/dmu.h>
18 #include <sys/dmu_tx.h>
19 #include <sys/dsl_pool.h>
20 #include <sys/dsl_dir.h>
21 #include <sys/dsl_synctask.h>
22 #include <sys/metaslab.h>
23
24 #define DST_AVG_BLKSHIFT 14
25
26 static int
dsl_null_checkfunc(void * arg,dmu_tx_t * tx)27 dsl_null_checkfunc(void *arg, dmu_tx_t *tx)
28 {
29 (void) arg, (void) tx;
30 return (0);
31 }
32
33 static int
dsl_sync_task_common(const char * pool,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,dsl_sigfunc_t * sigfunc,void * arg,int blocks_modified,zfs_space_check_t space_check,boolean_t early)34 dsl_sync_task_common(const char *pool, dsl_checkfunc_t *checkfunc,
35 dsl_syncfunc_t *syncfunc, dsl_sigfunc_t *sigfunc, void *arg,
36 int blocks_modified, zfs_space_check_t space_check, boolean_t early)
37 {
38 spa_t *spa;
39 dmu_tx_t *tx;
40 int err;
41 dsl_sync_task_t dst = { { { NULL } } };
42 dsl_pool_t *dp;
43
44 err = spa_open(pool, &spa, FTAG);
45 if (err != 0)
46 return (err);
47 dp = spa_get_dsl(spa);
48
49 top:
50 tx = dmu_tx_create_dd(dp->dp_mos_dir);
51 VERIFY0(dmu_tx_assign(tx, DMU_TX_WAIT | DMU_TX_SUSPEND));
52
53 dst.dst_pool = dp;
54 dst.dst_txg = dmu_tx_get_txg(tx);
55 dst.dst_space = blocks_modified << DST_AVG_BLKSHIFT;
56 dst.dst_space_check = space_check;
57 dst.dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc;
58 dst.dst_syncfunc = syncfunc;
59 dst.dst_arg = arg;
60 dst.dst_error = 0;
61 dst.dst_nowaiter = B_FALSE;
62
63 dsl_pool_config_enter(dp, FTAG);
64 err = dst.dst_checkfunc(arg, tx);
65 dsl_pool_config_exit(dp, FTAG);
66
67 if (err != 0) {
68 dmu_tx_commit(tx);
69 spa_close(spa, FTAG);
70 return (err);
71 }
72
73 txg_list_t *task_list = (early) ?
74 &dp->dp_early_sync_tasks : &dp->dp_sync_tasks;
75 VERIFY(txg_list_add_tail(task_list, &dst, dst.dst_txg));
76
77 dmu_tx_commit(tx);
78
79 if (sigfunc != NULL) {
80 err = txg_wait_synced_flags(dp, dst.dst_txg, TXG_WAIT_SIGNAL);
81 if (err != 0) {
82 VERIFY3U(err, ==, EINTR);
83 /* current contract is to call func once */
84 sigfunc(arg, tx);
85 /* in case we're performing an EAGAIN retry */
86 sigfunc = NULL;
87
88 txg_wait_synced(dp, dst.dst_txg);
89 }
90 } else
91 txg_wait_synced(dp, dst.dst_txg);
92
93 if (dst.dst_error == EAGAIN) {
94 txg_wait_synced(dp, dst.dst_txg + TXG_DEFER_SIZE);
95 goto top;
96 }
97
98 spa_close(spa, FTAG);
99 return (dst.dst_error);
100 }
101
102 /*
103 * Called from open context to perform a callback in syncing context. Waits
104 * for the operation to complete.
105 *
106 * The checkfunc will be called from open context as a preliminary check
107 * which can quickly fail. If it succeeds, it will be called again from
108 * syncing context. The checkfunc should generally be designed to work
109 * properly in either context, but if necessary it can check
110 * dmu_tx_is_syncing(tx).
111 *
112 * The synctask infrastructure enforces proper locking strategy with respect
113 * to the dp_config_rwlock -- the lock will always be held when the callbacks
114 * are called. It will be held for read during the open-context (preliminary)
115 * call to the checkfunc, and then held for write from syncing context during
116 * the calls to the check and sync funcs.
117 *
118 * A dataset or pool name can be passed as the first argument. Typically,
119 * the check func will hold, check the return value of the hold, and then
120 * release the dataset. The sync func will VERIFYO(hold()) the dataset.
121 * This is safe because no changes can be made between the check and sync funcs,
122 * and the sync func will only be called if the check func successfully opened
123 * the dataset.
124 */
125 int
dsl_sync_task(const char * pool,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,void * arg,int blocks_modified,zfs_space_check_t space_check)126 dsl_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
127 dsl_syncfunc_t *syncfunc, void *arg,
128 int blocks_modified, zfs_space_check_t space_check)
129 {
130 return (dsl_sync_task_common(pool, checkfunc, syncfunc, NULL, arg,
131 blocks_modified, space_check, B_FALSE));
132 }
133
134 /*
135 * An early synctask works exactly as a standard synctask with one important
136 * difference on the way it is handled during syncing context. Standard
137 * synctasks run after we've written out all the dirty blocks of dirty
138 * datasets. Early synctasks are executed before writing out any dirty data,
139 * and thus before standard synctasks.
140 *
141 * For that reason, early synctasks can affect the process of writing dirty
142 * changes to disk for the txg that they run and should be used with caution.
143 * In addition, early synctasks should not dirty any metaslabs as this would
144 * invalidate the precondition/invariant for subsequent early synctasks.
145 * [see dsl_pool_sync() and dsl_early_sync_task_verify()]
146 */
147 int
dsl_early_sync_task(const char * pool,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,void * arg,int blocks_modified,zfs_space_check_t space_check)148 dsl_early_sync_task(const char *pool, dsl_checkfunc_t *checkfunc,
149 dsl_syncfunc_t *syncfunc, void *arg,
150 int blocks_modified, zfs_space_check_t space_check)
151 {
152 return (dsl_sync_task_common(pool, checkfunc, syncfunc, NULL, arg,
153 blocks_modified, space_check, B_TRUE));
154 }
155
156 /*
157 * A standard synctask that can be interrupted from a signal. The sigfunc
158 * is called once if a signal occurred while waiting for the task to sync.
159 */
160 int
dsl_sync_task_sig(const char * pool,dsl_checkfunc_t * checkfunc,dsl_syncfunc_t * syncfunc,dsl_sigfunc_t * sigfunc,void * arg,int blocks_modified,zfs_space_check_t space_check)161 dsl_sync_task_sig(const char *pool, dsl_checkfunc_t *checkfunc,
162 dsl_syncfunc_t *syncfunc, dsl_sigfunc_t *sigfunc, void *arg,
163 int blocks_modified, zfs_space_check_t space_check)
164 {
165 return (dsl_sync_task_common(pool, checkfunc, syncfunc, sigfunc, arg,
166 blocks_modified, space_check, B_FALSE));
167 }
168
169 static void
dsl_sync_task_nowait_common(dsl_pool_t * dp,dsl_syncfunc_t * syncfunc,void * arg,dmu_tx_t * tx,boolean_t early)170 dsl_sync_task_nowait_common(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg,
171 dmu_tx_t *tx, boolean_t early)
172 {
173 dsl_sync_task_t *dst = kmem_zalloc(sizeof (*dst), KM_SLEEP);
174
175 dst->dst_pool = dp;
176 dst->dst_txg = dmu_tx_get_txg(tx);
177 dst->dst_space_check = ZFS_SPACE_CHECK_NONE;
178 dst->dst_checkfunc = dsl_null_checkfunc;
179 dst->dst_syncfunc = syncfunc;
180 dst->dst_arg = arg;
181 dst->dst_error = 0;
182 dst->dst_nowaiter = B_TRUE;
183
184 txg_list_t *task_list = (early) ?
185 &dp->dp_early_sync_tasks : &dp->dp_sync_tasks;
186 VERIFY(txg_list_add_tail(task_list, dst, dst->dst_txg));
187 }
188
189 void
dsl_sync_task_nowait(dsl_pool_t * dp,dsl_syncfunc_t * syncfunc,void * arg,dmu_tx_t * tx)190 dsl_sync_task_nowait(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg,
191 dmu_tx_t *tx)
192 {
193 dsl_sync_task_nowait_common(dp, syncfunc, arg, tx, B_FALSE);
194 }
195
196 void
dsl_early_sync_task_nowait(dsl_pool_t * dp,dsl_syncfunc_t * syncfunc,void * arg,dmu_tx_t * tx)197 dsl_early_sync_task_nowait(dsl_pool_t *dp, dsl_syncfunc_t *syncfunc, void *arg,
198 dmu_tx_t *tx)
199 {
200 dsl_sync_task_nowait_common(dp, syncfunc, arg, tx, B_TRUE);
201 }
202
203 /*
204 * Called in syncing context to execute the synctask.
205 */
206 void
dsl_sync_task_sync(dsl_sync_task_t * dst,dmu_tx_t * tx)207 dsl_sync_task_sync(dsl_sync_task_t *dst, dmu_tx_t *tx)
208 {
209 dsl_pool_t *dp = dst->dst_pool;
210
211 ASSERT0(dst->dst_error);
212
213 /*
214 * Check for sufficient space.
215 *
216 * When the sync task was created, the caller specified the
217 * type of space checking required. See the comment in
218 * zfs_space_check_t for details on the semantics of each
219 * type of space checking.
220 *
221 * We just check against what's on-disk; we don't want any
222 * in-flight accounting to get in our way, because open context
223 * may have already used up various in-core limits
224 * (arc_tempreserve, dsl_pool_tempreserve).
225 */
226 if (dst->dst_space_check != ZFS_SPACE_CHECK_NONE) {
227 uint64_t quota = dsl_pool_unreserved_space(dp,
228 dst->dst_space_check);
229 uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes;
230
231 /* MOS space is triple-dittoed, so we multiply by 3. */
232 if (used + dst->dst_space * 3 > quota) {
233 dst->dst_error = SET_ERROR(ENOSPC);
234 if (dst->dst_nowaiter)
235 kmem_free(dst, sizeof (*dst));
236 return;
237 }
238 }
239
240 /*
241 * Check for errors by calling checkfunc.
242 */
243 rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
244 dst->dst_error = dst->dst_checkfunc(dst->dst_arg, tx);
245 if (dst->dst_error == 0)
246 dst->dst_syncfunc(dst->dst_arg, tx);
247 rrw_exit(&dp->dp_config_rwlock, FTAG);
248 if (dst->dst_nowaiter)
249 kmem_free(dst, sizeof (*dst));
250 }
251
252 #if defined(_KERNEL)
253 EXPORT_SYMBOL(dsl_sync_task);
254 EXPORT_SYMBOL(dsl_sync_task_nowait);
255 #endif
256