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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/dmu_tx.h>
30 #include <sys/dsl_pool.h>
31 #include <sys/dsl_dir.h>
32 #include <sys/dsl_synctask.h>
35 #define DST_AVG_BLKSHIFT 14
39 dsl_null_checkfunc(void *arg1
, void *arg2
, dmu_tx_t
*tx
)
44 dsl_sync_task_group_t
*
45 dsl_sync_task_group_create(dsl_pool_t
*dp
)
47 dsl_sync_task_group_t
*dstg
;
49 dstg
= kmem_zalloc(sizeof (dsl_sync_task_group_t
), KM_SLEEP
);
50 list_create(&dstg
->dstg_tasks
, sizeof (dsl_sync_task_t
),
51 offsetof(dsl_sync_task_t
, dst_node
));
53 dstg
->dstg_cr
= CRED();
59 dsl_sync_task_create(dsl_sync_task_group_t
*dstg
,
60 dsl_checkfunc_t
*checkfunc
, dsl_syncfunc_t
*syncfunc
,
61 void *arg1
, void *arg2
, int blocks_modified
)
65 if (checkfunc
== NULL
)
66 checkfunc
= dsl_null_checkfunc
;
67 dst
= kmem_zalloc(sizeof (dsl_sync_task_t
), KM_SLEEP
);
68 dst
->dst_checkfunc
= checkfunc
;
69 dst
->dst_syncfunc
= syncfunc
;
72 list_insert_tail(&dstg
->dstg_tasks
, dst
);
74 dstg
->dstg_space
+= blocks_modified
<< DST_AVG_BLKSHIFT
;
78 dsl_sync_task_group_wait(dsl_sync_task_group_t
*dstg
)
85 tx
= dmu_tx_create_dd(dstg
->dstg_pool
->dp_mos_dir
);
86 VERIFY(0 == dmu_tx_assign(tx
, TXG_WAIT
));
88 txg
= dmu_tx_get_txg(tx
);
90 /* Do a preliminary error check. */
92 rw_enter(&dstg
->dstg_pool
->dp_config_rwlock
, RW_READER
);
93 for (dst
= list_head(&dstg
->dstg_tasks
); dst
;
94 dst
= list_next(&dstg
->dstg_tasks
, dst
)) {
97 * Only check half the time, otherwise, the sync-context
98 * check will almost never fail.
100 if (spa_get_random(2) == 0)
104 dst
->dst_checkfunc(dst
->dst_arg1
, dst
->dst_arg2
, tx
);
106 dstg
->dstg_err
= dst
->dst_err
;
108 rw_exit(&dstg
->dstg_pool
->dp_config_rwlock
);
110 if (dstg
->dstg_err
) {
112 return (dstg
->dstg_err
);
115 VERIFY(0 == txg_list_add(&dstg
->dstg_pool
->dp_sync_tasks
, dstg
, txg
));
119 txg_wait_synced(dstg
->dstg_pool
, txg
);
121 if (dstg
->dstg_err
== EAGAIN
)
124 return (dstg
->dstg_err
);
128 dsl_sync_task_group_nowait(dsl_sync_task_group_t
*dstg
, dmu_tx_t
*tx
)
132 dstg
->dstg_nowaiter
= B_TRUE
;
133 txg
= dmu_tx_get_txg(tx
);
134 VERIFY(0 == txg_list_add(&dstg
->dstg_pool
->dp_sync_tasks
, dstg
, txg
));
138 dsl_sync_task_group_destroy(dsl_sync_task_group_t
*dstg
)
140 dsl_sync_task_t
*dst
;
142 while (dst
= list_head(&dstg
->dstg_tasks
)) {
143 list_remove(&dstg
->dstg_tasks
, dst
);
144 kmem_free(dst
, sizeof (dsl_sync_task_t
));
146 kmem_free(dstg
, sizeof (dsl_sync_task_group_t
));
150 dsl_sync_task_group_sync(dsl_sync_task_group_t
*dstg
, dmu_tx_t
*tx
)
152 dsl_sync_task_t
*dst
;
155 ASSERT3U(dstg
->dstg_err
, ==, 0);
158 * Check for sufficient space.
160 dstg
->dstg_err
= dsl_dir_tempreserve_space(dstg
->dstg_pool
->dp_mos_dir
,
161 dstg
->dstg_space
, dstg
->dstg_space
* 3, 0, 0, &tr_cookie
, tx
);
162 /* don't bother trying again */
163 if (dstg
->dstg_err
== ERESTART
)
164 dstg
->dstg_err
= EAGAIN
;
169 * Check for errors by calling checkfuncs.
171 rw_enter(&dstg
->dstg_pool
->dp_config_rwlock
, RW_WRITER
);
172 for (dst
= list_head(&dstg
->dstg_tasks
); dst
;
173 dst
= list_next(&dstg
->dstg_tasks
, dst
)) {
175 dst
->dst_checkfunc(dst
->dst_arg1
, dst
->dst_arg2
, tx
);
177 dstg
->dstg_err
= dst
->dst_err
;
180 if (dstg
->dstg_err
== 0) {
182 * Execute sync tasks.
184 for (dst
= list_head(&dstg
->dstg_tasks
); dst
;
185 dst
= list_next(&dstg
->dstg_tasks
, dst
)) {
186 dst
->dst_syncfunc(dst
->dst_arg1
, dst
->dst_arg2
,
190 rw_exit(&dstg
->dstg_pool
->dp_config_rwlock
);
192 dsl_dir_tempreserve_clear(tr_cookie
, tx
);
194 if (dstg
->dstg_nowaiter
)
195 dsl_sync_task_group_destroy(dstg
);
199 dsl_sync_task_do(dsl_pool_t
*dp
,
200 dsl_checkfunc_t
*checkfunc
, dsl_syncfunc_t
*syncfunc
,
201 void *arg1
, void *arg2
, int blocks_modified
)
203 dsl_sync_task_group_t
*dstg
;
206 dstg
= dsl_sync_task_group_create(dp
);
207 dsl_sync_task_create(dstg
, checkfunc
, syncfunc
,
208 arg1
, arg2
, blocks_modified
);
209 err
= dsl_sync_task_group_wait(dstg
);
210 dsl_sync_task_group_destroy(dstg
);
215 dsl_sync_task_do_nowait(dsl_pool_t
*dp
,
216 dsl_checkfunc_t
*checkfunc
, dsl_syncfunc_t
*syncfunc
,
217 void *arg1
, void *arg2
, int blocks_modified
, dmu_tx_t
*tx
)
219 dsl_sync_task_group_t
*dstg
;
221 dstg
= dsl_sync_task_group_create(dp
);
222 dsl_sync_task_create(dstg
, checkfunc
, syncfunc
,
223 arg1
, arg2
, blocks_modified
);
224 dsl_sync_task_group_nowait(dstg
, tx
);