xref: /freebsd/sys/contrib/openzfs/module/zfs/dsl_synctask.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
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