xref: /onnv-gate/usr/src/uts/common/fs/zfs/dsl_synctask.c (revision 2199:712a788c2dfd)
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