zvol: Cleanup set property

zvol_set_volmode() and zvol_set_snapdev() share a common code path.
Merge this shared code path into zvol_set_common().

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
Closes #15409
This commit is contained in:
Ameer Hamza 2023-10-12 03:31:11 +05:00 committed by Brian Behlendorf
parent 799e09f75a
commit dbe839a9ca
3 changed files with 37 additions and 107 deletions

View File

@ -50,8 +50,7 @@ extern int zvol_get_stats(objset_t *, nvlist_t *);
extern boolean_t zvol_is_zvol(const char *); extern boolean_t zvol_is_zvol(const char *);
extern void zvol_create_cb(objset_t *, void *, cred_t *, dmu_tx_t *); extern void zvol_create_cb(objset_t *, void *, cred_t *, dmu_tx_t *);
extern int zvol_set_volsize(const char *, uint64_t); extern int zvol_set_volsize(const char *, uint64_t);
extern int zvol_set_snapdev(const char *, zprop_source_t, uint64_t); extern int zvol_set_common(const char *, zfs_prop_t, zprop_source_t, uint64_t);
extern int zvol_set_volmode(const char *, zprop_source_t, uint64_t);
extern zvol_state_handle_t *zvol_suspend(const char *); extern zvol_state_handle_t *zvol_suspend(const char *);
extern int zvol_resume(zvol_state_handle_t *); extern int zvol_resume(zvol_state_handle_t *);
extern void *zvol_tag(zvol_state_handle_t *); extern void *zvol_tag(zvol_state_handle_t *);

View File

@ -2523,10 +2523,8 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
err = zvol_set_volsize(dsname, intval); err = zvol_set_volsize(dsname, intval);
break; break;
case ZFS_PROP_SNAPDEV: case ZFS_PROP_SNAPDEV:
err = zvol_set_snapdev(dsname, source, intval);
break;
case ZFS_PROP_VOLMODE: case ZFS_PROP_VOLMODE:
err = zvol_set_volmode(dsname, source, intval); err = zvol_set_common(dsname, prop, source, intval);
break; break;
case ZFS_PROP_VERSION: case ZFS_PROP_VERSION:
{ {

View File

@ -1538,6 +1538,7 @@ typedef struct zvol_set_prop_int_arg {
const char *zsda_name; const char *zsda_name;
uint64_t zsda_value; uint64_t zsda_value;
zprop_source_t zsda_source; zprop_source_t zsda_source;
zfs_prop_t zsda_prop;
dmu_tx_t *zsda_tx; dmu_tx_t *zsda_tx;
} zvol_set_prop_int_arg_t; } zvol_set_prop_int_arg_t;
@ -1546,7 +1547,7 @@ typedef struct zvol_set_prop_int_arg {
* conditions are imposed. * conditions are imposed.
*/ */
static int static int
zvol_set_snapdev_check(void *arg, dmu_tx_t *tx) zvol_set_common_check(void *arg, dmu_tx_t *tx)
{ {
zvol_set_prop_int_arg_t *zsda = arg; zvol_set_prop_int_arg_t *zsda = arg;
dsl_pool_t *dp = dmu_tx_pool(tx); dsl_pool_t *dp = dmu_tx_pool(tx);
@ -1563,17 +1564,33 @@ zvol_set_snapdev_check(void *arg, dmu_tx_t *tx)
} }
static int static int
zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) zvol_set_common_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{ {
(void) arg; zvol_set_prop_int_arg_t *zsda = arg;
char dsname[MAXNAMELEN]; char dsname[MAXNAMELEN];
zvol_task_t *task; zvol_task_t *task;
uint64_t snapdev; uint64_t prop;
const char *prop_name = zfs_prop_to_name(zsda->zsda_prop);
dsl_dataset_name(ds, dsname); dsl_dataset_name(ds, dsname);
if (dsl_prop_get_int_ds(ds, "snapdev", &snapdev) != 0)
if (dsl_prop_get_int_ds(ds, prop_name, &prop) != 0)
return (0); return (0);
task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname, NULL, snapdev);
switch (zsda->zsda_prop) {
case ZFS_PROP_VOLMODE:
task = zvol_task_alloc(ZVOL_ASYNC_SET_VOLMODE, dsname,
NULL, prop);
break;
case ZFS_PROP_SNAPDEV:
task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname,
NULL, prop);
break;
default:
task = NULL;
break;
}
if (task == NULL) if (task == NULL)
return (0); return (0);
@ -1583,14 +1600,14 @@ zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
} }
/* /*
* Traverse all child datasets and apply snapdev appropriately. * Traverse all child datasets and apply the property appropriately.
* We call dsl_prop_set_sync_impl() here to set the value only on the toplevel * We call dsl_prop_set_sync_impl() here to set the value only on the toplevel
* dataset and read the effective "snapdev" on every child in the callback * dataset and read the effective "property" on every child in the callback
* function: this is because the value is not guaranteed to be the same in the * function: this is because the value is not guaranteed to be the same in the
* whole dataset hierarchy. * whole dataset hierarchy.
*/ */
static void static void
zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx) zvol_set_common_sync(void *arg, dmu_tx_t *tx)
{ {
zvol_set_prop_int_arg_t *zsda = arg; zvol_set_prop_int_arg_t *zsda = arg;
dsl_pool_t *dp = dmu_tx_pool(tx); dsl_pool_t *dp = dmu_tx_pool(tx);
@ -1603,115 +1620,31 @@ zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx)
error = dsl_dataset_hold(dp, zsda->zsda_name, FTAG, &ds); error = dsl_dataset_hold(dp, zsda->zsda_name, FTAG, &ds);
if (error == 0) { if (error == 0) {
dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_SNAPDEV), dsl_prop_set_sync_impl(ds, zfs_prop_to_name(zsda->zsda_prop),
zsda->zsda_source, sizeof (zsda->zsda_value), 1, zsda->zsda_source, sizeof (zsda->zsda_value), 1,
&zsda->zsda_value, zsda->zsda_tx); &zsda->zsda_value, zsda->zsda_tx);
dsl_dataset_rele(ds, FTAG); dsl_dataset_rele(ds, FTAG);
} }
dmu_objset_find_dp(dp, dd->dd_object, zvol_set_snapdev_sync_cb,
dmu_objset_find_dp(dp, dd->dd_object, zvol_set_common_sync_cb,
zsda, DS_FIND_CHILDREN); zsda, DS_FIND_CHILDREN);
dsl_dir_rele(dd, FTAG); dsl_dir_rele(dd, FTAG);
} }
int int
zvol_set_snapdev(const char *ddname, zprop_source_t source, uint64_t snapdev) zvol_set_common(const char *ddname, zfs_prop_t prop, zprop_source_t source,
uint64_t val)
{ {
zvol_set_prop_int_arg_t zsda; zvol_set_prop_int_arg_t zsda;
zsda.zsda_name = ddname; zsda.zsda_name = ddname;
zsda.zsda_source = source; zsda.zsda_source = source;
zsda.zsda_value = snapdev; zsda.zsda_value = val;
zsda.zsda_prop = prop;
return (dsl_sync_task(ddname, zvol_set_snapdev_check, return (dsl_sync_task(ddname, zvol_set_common_check,
zvol_set_snapdev_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE)); zvol_set_common_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
}
/*
* Sanity check the dataset for safe use by the sync task. No additional
* conditions are imposed.
*/
static int
zvol_set_volmode_check(void *arg, dmu_tx_t *tx)
{
zvol_set_prop_int_arg_t *zsda = arg;
dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dir_t *dd;
int error;
error = dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL);
if (error != 0)
return (error);
dsl_dir_rele(dd, FTAG);
return (error);
}
static int
zvol_set_volmode_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
(void) arg;
char dsname[MAXNAMELEN];
zvol_task_t *task;
uint64_t volmode;
dsl_dataset_name(ds, dsname);
if (dsl_prop_get_int_ds(ds, "volmode", &volmode) != 0)
return (0);
task = zvol_task_alloc(ZVOL_ASYNC_SET_VOLMODE, dsname, NULL, volmode);
if (task == NULL)
return (0);
(void) taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb,
task, TQ_SLEEP);
return (0);
}
/*
* Traverse all child datasets and apply volmode appropriately.
* We call dsl_prop_set_sync_impl() here to set the value only on the toplevel
* dataset and read the effective "volmode" on every child in the callback
* function: this is because the value is not guaranteed to be the same in the
* whole dataset hierarchy.
*/
static void
zvol_set_volmode_sync(void *arg, dmu_tx_t *tx)
{
zvol_set_prop_int_arg_t *zsda = arg;
dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dir_t *dd;
dsl_dataset_t *ds;
int error;
VERIFY0(dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL));
zsda->zsda_tx = tx;
error = dsl_dataset_hold(dp, zsda->zsda_name, FTAG, &ds);
if (error == 0) {
dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_VOLMODE),
zsda->zsda_source, sizeof (zsda->zsda_value), 1,
&zsda->zsda_value, zsda->zsda_tx);
dsl_dataset_rele(ds, FTAG);
}
dmu_objset_find_dp(dp, dd->dd_object, zvol_set_volmode_sync_cb,
zsda, DS_FIND_CHILDREN);
dsl_dir_rele(dd, FTAG);
}
int
zvol_set_volmode(const char *ddname, zprop_source_t source, uint64_t volmode)
{
zvol_set_prop_int_arg_t zsda;
zsda.zsda_name = ddname;
zsda.zsda_source = source;
zsda.zsda_value = volmode;
return (dsl_sync_task(ddname, zvol_set_volmode_check,
zvol_set_volmode_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
} }
void void