Add support for asynchronous zvol minor operations

zfsonlinux issue #2217 - zvol minor operations: check snapdev
property before traversing snapshots of a dataset

zfsonlinux issue #3681 - lock order inversion between zvol_open()
and dsl_pool_sync()...zvol_rename_minors()

Create a per-pool zvol taskq for asynchronous zvol tasks.
There are a few key design decisions to be aware of.

* Each taskq must be single threaded to ensure tasks are always
  processed in the order in which they were dispatched.

* There is a taskq per-pool in order to keep the pools independent.
  This way if one pool is suspended it will not impact another.

* The preferred location to dispatch a zvol minor task is a sync
  task.  In this context there is easy access to the spa_t and
  minimal error handling is required because the sync task must
  succeed.

Support for asynchronous zvol minor operations address issue #3681.

Signed-off-by: Boris Protopopov <boris.protopopov@actifio.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2217
Closes #3678
Closes #3681
This commit is contained in:
Boris Protopopov
2014-03-22 05:07:14 -04:00
committed by Brian Behlendorf
parent eb0856779f
commit a0bd735adb
12 changed files with 485 additions and 217 deletions
+12 -38
View File
@@ -29,6 +29,7 @@
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
*/
/*
@@ -1499,8 +1500,7 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
int error;
zfs_log_history(zc);
error = spa_destroy(zc->zc_name);
if (error == 0)
zvol_remove_minors(zc->zc_name);
return (error);
}
@@ -1552,8 +1552,7 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
zfs_log_history(zc);
error = spa_export(zc->zc_name, NULL, force, hardforce);
if (error == 0)
zvol_remove_minors(zc->zc_name);
return (error);
}
@@ -2394,7 +2393,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
err = zvol_set_volsize(dsname, intval);
break;
case ZFS_PROP_SNAPDEV:
err = zvol_set_snapdev(dsname, intval);
err = zvol_set_snapdev(dsname, source, intval);
break;
case ZFS_PROP_VERSION:
{
@@ -3188,12 +3187,6 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
if (error != 0)
(void) dsl_destroy_head(fsname);
}
#ifdef _KERNEL
if (error == 0 && type == DMU_OST_ZVOL)
zvol_create_minors(fsname);
#endif
return (error);
}
@@ -3236,12 +3229,6 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
if (error != 0)
(void) dsl_destroy_head(fsname);
}
#ifdef _KERNEL
if (error == 0)
zvol_create_minors(fsname);
#endif
return (error);
}
@@ -3304,11 +3291,6 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
error = dsl_dataset_snapshot(snaps, props, outnvl);
#ifdef _KERNEL
if (error == 0)
zvol_create_minors(poolname);
#endif
return (error);
}
@@ -3434,7 +3416,6 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
(void) zfs_unmount_snap(nvpair_name(pair));
(void) zvol_remove_minor(nvpair_name(pair));
}
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
@@ -3560,8 +3541,7 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
else
err = dsl_destroy_head(zc->zc_name);
if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0)
(void) zvol_remove_minor(zc->zc_name);
return (err);
}
@@ -4127,11 +4107,6 @@ zfs_ioc_recv(zfs_cmd_t *zc)
}
#endif
#ifdef _KERNEL
if (error == 0)
zvol_create_minors(tofs);
#endif
/*
* On error, restore the original props.
*/
@@ -6032,16 +6007,16 @@ _init(void)
return (error);
}
if ((error = -zvol_init()) != 0)
return (error);
spa_init(FREAD | FWRITE);
zfs_init();
if ((error = -zvol_init()) != 0)
goto out1;
zfs_ioctl_init();
if ((error = zfs_attach()) != 0)
goto out2;
goto out;
tsd_create(&zfs_fsyncer_key, NULL);
tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
@@ -6057,11 +6032,10 @@ _init(void)
return (0);
out2:
(void) zvol_fini();
out1:
out:
zfs_fini();
spa_fini();
(void) zvol_fini();
printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
ZFS_DEBUG_STR, error);
@@ -6073,9 +6047,9 @@ static void __exit
_fini(void)
{
zfs_detach();
zvol_fini();
zfs_fini();
spa_fini();
zvol_fini();
tsd_destroy(&zfs_fsyncer_key);
tsd_destroy(&rrw_tsd_key);