diff options
author | LOLi <[email protected]> | 2017-06-02 16:17:00 +0200 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-06-02 07:17:00 -0700 |
commit | 92aceb2a7ee8c9367fdc901fed933f6f258173e0 (patch) | |
tree | b05170d226a597196ab3389d9c798d01908b76dc /module/zfs/zvol.c | |
parent | b870c4b5d716d87ddfb29f28745e639dd635fd5f (diff) |
Fix "snapdev" property issues
When inheriting the "snapdev" property to we don't always call
zfs_prop_set_special(): this prevents device nodes from being created in
certain situations. Because "snapdev" is the only *special* property
that is also inheritable we need to call zfs_prop_set_special() even
when we're not reverting it to the received value ('zfs inherit -S').
Additionally, fix a NULL pointer dereference accidentally introduced in
5559ba0 that can be triggered when setting the "snapdev" property to
the value "hidden" twice.
Finally, add a new test case "zvol_misc_snapdev" to the ZFS Test Suite.
Reviewed by: Boris Protopopov <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: loli10K <[email protected]>
Closes #6131
Closes #6175
Closes #6176
Diffstat (limited to 'module/zfs/zvol.c')
-rw-r--r-- | module/zfs/zvol.c | 36 |
1 files changed, 23 insertions, 13 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index cff3da8b4..1a86cd3cd 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -2018,7 +2018,7 @@ zvol_remove_minors_impl(const char *name) static void zvol_remove_minor_impl(const char *name) { - zvol_state_t *zv, *zv_next; + zvol_state_t *zv = NULL, *zv_next; if (zvol_inhibit_dev) return; @@ -2049,12 +2049,11 @@ zvol_remove_minor_impl(const char *name) } } + /* Drop zvol_state_lock before calling zvol_free() */ mutex_exit(&zvol_state_lock); - /* - * Drop zvol_state_lock before calling zvol_free() - */ - zvol_free(zv); + if (zv != NULL) + zvol_free(zv); } /* @@ -2224,20 +2223,18 @@ zvol_set_snapdev_check(void *arg, dmu_tx_t *tx) return (error); } +/* ARGSUSED */ static int zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) { - zvol_set_snapdev_arg_t *zsda = arg; char dsname[MAXNAMELEN]; zvol_task_t *task; + uint64_t snapdev; dsl_dataset_name(ds, dsname); - dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_SNAPDEV), - zsda->zsda_source, sizeof (zsda->zsda_value), 1, - &zsda->zsda_value, zsda->zsda_tx); - - task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname, - NULL, zsda->zsda_value); + if (dsl_prop_get_int_ds(ds, "snapdev", &snapdev) != 0) + return (0); + task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname, NULL, snapdev); if (task == NULL) return (0); @@ -2247,7 +2244,11 @@ zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) } /* - * Traverse all child snapshot datasets and apply snapdev appropriately. + * Traverse all child datasets and apply snapdev appropriately. + * 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 + * function: this is because the value is not guaranteed to be the same in the + * whole dataset hierarchy. */ static void zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx) @@ -2255,10 +2256,19 @@ zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx) zvol_set_snapdev_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_SNAPDEV), + 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_snapdev_sync_cb, zsda, DS_FIND_CHILDREN); |