xref: /onnv-gate/usr/src/uts/common/fs/zfs/dsl_synctask.c (revision 10922:e2081f502306)
12199Sahrens /*
22199Sahrens  * CDDL HEADER START
32199Sahrens  *
42199Sahrens  * The contents of this file are subject to the terms of the
52199Sahrens  * Common Development and Distribution License (the "License").
62199Sahrens  * You may not use this file except in compliance with the License.
72199Sahrens  *
82199Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92199Sahrens  * or http://www.opensolaris.org/os/licensing.
102199Sahrens  * See the License for the specific language governing permissions
112199Sahrens  * and limitations under the License.
122199Sahrens  *
132199Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
142199Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152199Sahrens  * If applicable, add the following below this CDDL HEADER, with the
162199Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
172199Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
182199Sahrens  *
192199Sahrens  * CDDL HEADER END
202199Sahrens  */
212199Sahrens /*
22*10922SJeff.Bonwick@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
232199Sahrens  * Use is subject to license terms.
242199Sahrens  */
252199Sahrens 
262199Sahrens #include <sys/dmu.h>
272199Sahrens #include <sys/dmu_tx.h>
282199Sahrens #include <sys/dsl_pool.h>
292199Sahrens #include <sys/dsl_dir.h>
302199Sahrens #include <sys/dsl_synctask.h>
314543Smarks #include <sys/cred.h>
322199Sahrens 
332199Sahrens #define	DST_AVG_BLKSHIFT 14
342199Sahrens 
352199Sahrens /* ARGSUSED */
362199Sahrens static int
372199Sahrens dsl_null_checkfunc(void *arg1, void *arg2, dmu_tx_t *tx)
382199Sahrens {
392199Sahrens 	return (0);
402199Sahrens }
412199Sahrens 
422199Sahrens dsl_sync_task_group_t *
432199Sahrens dsl_sync_task_group_create(dsl_pool_t *dp)
442199Sahrens {
452199Sahrens 	dsl_sync_task_group_t *dstg;
462199Sahrens 
472199Sahrens 	dstg = kmem_zalloc(sizeof (dsl_sync_task_group_t), KM_SLEEP);
482199Sahrens 	list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t),
492199Sahrens 	    offsetof(dsl_sync_task_t, dst_node));
502199Sahrens 	dstg->dstg_pool = dp;
514577Sahrens 	dstg->dstg_cr = CRED();
522199Sahrens 
532199Sahrens 	return (dstg);
542199Sahrens }
552199Sahrens 
562199Sahrens void
572199Sahrens dsl_sync_task_create(dsl_sync_task_group_t *dstg,
582199Sahrens     dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
592199Sahrens     void *arg1, void *arg2, int blocks_modified)
602199Sahrens {
612199Sahrens 	dsl_sync_task_t *dst;
622199Sahrens 
632199Sahrens 	if (checkfunc == NULL)
642199Sahrens 		checkfunc = dsl_null_checkfunc;
652199Sahrens 	dst = kmem_zalloc(sizeof (dsl_sync_task_t), KM_SLEEP);
662199Sahrens 	dst->dst_checkfunc = checkfunc;
672199Sahrens 	dst->dst_syncfunc = syncfunc;
682199Sahrens 	dst->dst_arg1 = arg1;
692199Sahrens 	dst->dst_arg2 = arg2;
702199Sahrens 	list_insert_tail(&dstg->dstg_tasks, dst);
712199Sahrens 
722199Sahrens 	dstg->dstg_space += blocks_modified << DST_AVG_BLKSHIFT;
732199Sahrens }
742199Sahrens 
752199Sahrens int
762199Sahrens dsl_sync_task_group_wait(dsl_sync_task_group_t *dstg)
772199Sahrens {
782199Sahrens 	dmu_tx_t *tx;
792199Sahrens 	uint64_t txg;
802199Sahrens 	dsl_sync_task_t *dst;
812199Sahrens 
822199Sahrens top:
832199Sahrens 	tx = dmu_tx_create_dd(dstg->dstg_pool->dp_mos_dir);
842199Sahrens 	VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT));
852199Sahrens 
862199Sahrens 	txg = dmu_tx_get_txg(tx);
872199Sahrens 
882199Sahrens 	/* Do a preliminary error check. */
892199Sahrens 	dstg->dstg_err = 0;
902199Sahrens 	rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_READER);
912199Sahrens 	for (dst = list_head(&dstg->dstg_tasks); dst;
922199Sahrens 	    dst = list_next(&dstg->dstg_tasks, dst)) {
932199Sahrens #ifdef ZFS_DEBUG
942199Sahrens 		/*
952199Sahrens 		 * Only check half the time, otherwise, the sync-context
962199Sahrens 		 * check will almost never fail.
972199Sahrens 		 */
982199Sahrens 		if (spa_get_random(2) == 0)
992199Sahrens 			continue;
1002199Sahrens #endif
1012199Sahrens 		dst->dst_err =
1022199Sahrens 		    dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx);
1032199Sahrens 		if (dst->dst_err)
1042199Sahrens 			dstg->dstg_err = dst->dst_err;
1052199Sahrens 	}
1062199Sahrens 	rw_exit(&dstg->dstg_pool->dp_config_rwlock);
1072199Sahrens 
1082199Sahrens 	if (dstg->dstg_err) {
1092199Sahrens 		dmu_tx_commit(tx);
1102199Sahrens 		return (dstg->dstg_err);
1112199Sahrens 	}
1122199Sahrens 
1132199Sahrens 	VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg));
1142199Sahrens 
1152199Sahrens 	dmu_tx_commit(tx);
1162199Sahrens 
1172199Sahrens 	txg_wait_synced(dstg->dstg_pool, txg);
1182199Sahrens 
119*10922SJeff.Bonwick@Sun.COM 	if (dstg->dstg_err == EAGAIN) {
120*10922SJeff.Bonwick@Sun.COM 		txg_wait_synced(dstg->dstg_pool, txg + TXG_DEFER_SIZE);
1212199Sahrens 		goto top;
122*10922SJeff.Bonwick@Sun.COM 	}
1232199Sahrens 
1242199Sahrens 	return (dstg->dstg_err);
1252199Sahrens }
1262199Sahrens 
1272199Sahrens void
1284577Sahrens dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
1294577Sahrens {
1304577Sahrens 	uint64_t txg;
1314577Sahrens 
1324577Sahrens 	dstg->dstg_nowaiter = B_TRUE;
1334577Sahrens 	txg = dmu_tx_get_txg(tx);
1344577Sahrens 	VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg));
1354577Sahrens }
1364577Sahrens 
1374577Sahrens void
1382199Sahrens dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg)
1392199Sahrens {
1402199Sahrens 	dsl_sync_task_t *dst;
1412199Sahrens 
1422199Sahrens 	while (dst = list_head(&dstg->dstg_tasks)) {
1432199Sahrens 		list_remove(&dstg->dstg_tasks, dst);
1442199Sahrens 		kmem_free(dst, sizeof (dsl_sync_task_t));
1452199Sahrens 	}
1462199Sahrens 	kmem_free(dstg, sizeof (dsl_sync_task_group_t));
1472199Sahrens }
1482199Sahrens 
1492199Sahrens void
1502199Sahrens dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx)
1512199Sahrens {
1522199Sahrens 	dsl_sync_task_t *dst;
1532199Sahrens 	void *tr_cookie;
1542199Sahrens 
1552199Sahrens 	ASSERT3U(dstg->dstg_err, ==, 0);
1562199Sahrens 
1572199Sahrens 	/*
1582199Sahrens 	 * Check for sufficient space.
1592199Sahrens 	 */
1602199Sahrens 	dstg->dstg_err = dsl_dir_tempreserve_space(dstg->dstg_pool->dp_mos_dir,
1615378Sck153898 	    dstg->dstg_space, dstg->dstg_space * 3, 0, 0, &tr_cookie, tx);
1622199Sahrens 	/* don't bother trying again */
1632199Sahrens 	if (dstg->dstg_err == ERESTART)
1642532Sahrens 		dstg->dstg_err = EAGAIN;
1652199Sahrens 	if (dstg->dstg_err)
1662199Sahrens 		return;
1672199Sahrens 
1682199Sahrens 	/*
1692199Sahrens 	 * Check for errors by calling checkfuncs.
1702199Sahrens 	 */
1712199Sahrens 	rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_WRITER);
1722199Sahrens 	for (dst = list_head(&dstg->dstg_tasks); dst;
1732199Sahrens 	    dst = list_next(&dstg->dstg_tasks, dst)) {
1742199Sahrens 		dst->dst_err =
1752199Sahrens 		    dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx);
1762199Sahrens 		if (dst->dst_err)
1772199Sahrens 			dstg->dstg_err = dst->dst_err;
1782199Sahrens 	}
1792199Sahrens 
1802199Sahrens 	if (dstg->dstg_err == 0) {
1812199Sahrens 		/*
1822199Sahrens 		 * Execute sync tasks.
1832199Sahrens 		 */
1842199Sahrens 		for (dst = list_head(&dstg->dstg_tasks); dst;
1852199Sahrens 		    dst = list_next(&dstg->dstg_tasks, dst)) {
1864543Smarks 			dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2,
1874577Sahrens 			    dstg->dstg_cr, tx);
1882199Sahrens 		}
1892199Sahrens 	}
1902199Sahrens 	rw_exit(&dstg->dstg_pool->dp_config_rwlock);
1912199Sahrens 
1922199Sahrens 	dsl_dir_tempreserve_clear(tr_cookie, tx);
1934577Sahrens 
1944577Sahrens 	if (dstg->dstg_nowaiter)
1954577Sahrens 		dsl_sync_task_group_destroy(dstg);
1962199Sahrens }
1972199Sahrens 
1982199Sahrens int
1992199Sahrens dsl_sync_task_do(dsl_pool_t *dp,
2002199Sahrens     dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
2012199Sahrens     void *arg1, void *arg2, int blocks_modified)
2022199Sahrens {
2032199Sahrens 	dsl_sync_task_group_t *dstg;
2042199Sahrens 	int err;
2052199Sahrens 
2062199Sahrens 	dstg = dsl_sync_task_group_create(dp);
2072199Sahrens 	dsl_sync_task_create(dstg, checkfunc, syncfunc,
2082199Sahrens 	    arg1, arg2, blocks_modified);
2092199Sahrens 	err = dsl_sync_task_group_wait(dstg);
2102199Sahrens 	dsl_sync_task_group_destroy(dstg);
2112199Sahrens 	return (err);
2122199Sahrens }
2134577Sahrens 
2144577Sahrens void
2154577Sahrens dsl_sync_task_do_nowait(dsl_pool_t *dp,
2164577Sahrens     dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc,
2174577Sahrens     void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx)
2184577Sahrens {
2194577Sahrens 	dsl_sync_task_group_t *dstg;
2204577Sahrens 
2214577Sahrens 	dstg = dsl_sync_task_group_create(dp);
2224577Sahrens 	dsl_sync_task_create(dstg, checkfunc, syncfunc,
2234577Sahrens 	    arg1, arg2, blocks_modified);
2244577Sahrens 	dsl_sync_task_group_nowait(dstg, tx);
2254577Sahrens }
226