FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_synctask.c
/*
 * Called from open context to perform a callback in syncing context.  Waits
 * for the operation to complete.
 *
 * The checkfunc will be called from open context as a preliminary check
 * which can quickly fail.  If it succeeds, it will be called again from
 * syncing context.  The checkfunc should generally be designed to work
 * properly in either context, but if necessary it can check
 * dmu_tx_is_syncing(tx).
 *
 * The synctask infrastructure enforces proper locking strategy with respect
 * to the dp_config_rwlock -- the lock will always be held when the callbacks
 * are called.  It will be held for read during the open-context (preliminary)
 * call to the checkfunc, and then held for write from syncing context during
 * the calls to the check and sync funcs.
 *
 * A dataset or pool name can be passed as the first argument.  Typically,
 * the check func will hold, check the return value of the hold, and then
 * release the dataset.  The sync func will VERIFYO(hold()) the dataset.
 * This is safe because no changes can be made between the check and sync funcs,
 * and the sync func will only be called if the check func successfully opened
 * the dataset.
 */
Called from open context to perform a callback in syncing context.  Waits
for the operation to complete.

The checkfunc will be called from open context as a preliminary check
which can quickly fail.  If it succeeds, it will be called again from
syncing context.  The checkfunc should generally be designed to work
properly in either context, but if necessary it can check
dmu_tx_is_syncing(tx).

The synctask infrastructure enforces proper locking strategy with respect
to the dp_config_rwlock -- the lock will always be held when the callbacks
are called.  It will be held for read during the open-context (preliminary)
call to the checkfunc, and then held for write from syncing context during
the calls to the check and sync funcs.

A dataset or pool name can be passed as the first argument.  Typically,
the check func will hold, check the return value of the hold, and then
release the dataset.  The sync func will VERIFYO(hold()) the dataset.
This is safe because no changes can be made between the check and sync funcs,
and the sync func will only be called if the check func successfully opened
the dataset.
Called from open context to perform a callback in syncing context . Waits for the operation to complete . The checkfunc will be called from open context as a preliminary check which can quickly fail . If it succeeds it will be called again from syncing context . The checkfunc should generally be designed to work properly in either context but if necessary it can check dmu_tx_is_syncing ( tx ) . The synctask infrastructure enforces proper locking strategy with respect to the dp_config_rwlock -- the lock will always be held when the callbacks are called . It will be held for read during the open - context ( preliminary ) call to the checkfunc and then held for write from syncing context during the calls to the check and sync funcs . A dataset or pool name can be passed as the first argument . Typically the check func will hold check the return value of the hold and then release the dataset . The sync func will VERIFYO ( hold () ) the dataset . This is safe because no changes can be made between the check and sync funcs and the sync func will only be called if the check func successfully opened the dataset .
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)
{
	spa_t *spa;
	dmu_tx_t *tx;
	int err;
	dsl_sync_task_t dst = { 0 };
	dsl_pool_t *dp;
	err = spa_open(pool, &spa, FTAG);
	if (err != 0)
		return (err);
	dp = spa_get_dsl(spa);
top:
	tx = dmu_tx_create_dd(dp->dp_mos_dir);
	VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
	dst.dst_pool = dp;
	dst.dst_txg = dmu_tx_get_txg(tx);
	dst.dst_space = blocks_modified << DST_AVG_BLKSHIFT;
	dst.dst_space_check = space_check;
	dst.dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc;
	dst.dst_syncfunc = syncfunc;
	dst.dst_arg = arg;
	dst.dst_error = 0;
	dst.dst_nowaiter = B_FALSE;
	dsl_pool_config_enter(dp, FTAG);
	err = dst.dst_checkfunc(arg, tx);
	dsl_pool_config_exit(dp, FTAG);
	if (err != 0) {
		dmu_tx_commit(tx);
		spa_close(spa, FTAG);
		return (err);
	}
	VERIFY(txg_list_add_tail(&dp->dp_sync_tasks, &dst, dst.dst_txg));
	dmu_tx_commit(tx);
	txg_wait_synced(dp, dst.dst_txg);
	if (dst.dst_error == EAGAIN) {
		txg_wait_synced(dp, dst.dst_txg + TXG_DEFER_SIZE);
		goto top;
	}
	spa_close(spa, FTAG);
	return (dst.dst_error);
}
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 ) { spa_t * spa ; dmu_tx_t * tx ; int err ; dsl_sync_task_t dst = { 0 } ; dsl_pool_t * dp ; err = spa_open ( pool , & spa , FTAG ) ; if ( err != 0 ) return ( err ) ; dp = spa_get_dsl ( spa ) ; top : tx = dmu_tx_create_dd ( dp -> dp_mos_dir ) ; VERIFY0 ( dmu_tx_assign ( tx , TXG_WAIT ) ) ; dst . dst_pool = dp ; dst . dst_txg = dmu_tx_get_txg ( tx ) ; dst . dst_space = blocks_modified << DST_AVG_BLKSHIFT ; dst . dst_space_check = space_check ; dst . dst_checkfunc = checkfunc != NULL ? checkfunc : dsl_null_checkfunc ; dst . dst_syncfunc = syncfunc ; dst . dst_arg = arg ; dst . dst_error = 0 ; dst . dst_nowaiter = B_FALSE ; dsl_pool_config_enter ( dp , FTAG ) ; err = dst . dst_checkfunc ( arg , tx ) ; dsl_pool_config_exit ( dp , FTAG ) ; if ( err != 0 ) { dmu_tx_commit ( tx ) ; spa_close ( spa , FTAG ) ; return ( err ) ; } VERIFY ( txg_list_add_tail ( & dp -> dp_sync_tasks , & dst , dst . dst_txg ) ) ; dmu_tx_commit ( tx ) ; txg_wait_synced ( dp , dst . dst_txg ) ; if ( dst . dst_error == EAGAIN ) { txg_wait_synced ( dp , dst . dst_txg + TXG_DEFER_SIZE ) ; goto top ; } spa_close ( spa , FTAG ) ; return ( dst . dst_error ) ; }
Called from open context to perform a callback in syncing context.
Called from open context to perform a callback in syncing context .