svn commit: r364917 - in stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs: . sys
Andriy Gapon
avg at FreeBSD.org
Fri Aug 28 13:15:15 UTC 2020
Author: avg
Date: Fri Aug 28 13:15:13 2020
New Revision: 364917
URL: https://svnweb.freebsd.org/changeset/base/364917
Log:
MFC r362047,r362048: rework how ZVOLs are updated in response to DSL operations
Modified:
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -1053,6 +1053,9 @@ dmu_objset_create_sync(void *arg, dmu_tx_t *tx)
doca->doca_cred, tx);
}
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ zvol_create_minors(dp->dp_spa, doca->doca_name);
+#endif
spa_history_log_internal_ds(ds, "create", tx, "");
dsl_dataset_rele(ds, FTAG);
dsl_dir_rele(pdd, FTAG);
@@ -1148,6 +1151,9 @@ dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
VERIFY0(dsl_dataset_hold_obj(pdd->dd_pool, obj, FTAG, &ds));
dsl_dataset_name(origin, namebuf);
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ zvol_create_minors(dp->dp_spa, doca->doca_clone);
+#endif
spa_history_log_internal_ds(ds, "clone", tx,
"origin=%s (%llu)", namebuf, origin->ds_object);
dsl_dataset_rele(ds, FTAG);
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -57,6 +57,9 @@
#include <sys/dsl_bookmark.h>
#include <sys/zfeature.h>
#include <sys/bqueue.h>
+#ifdef __FreeBSD__
+#include <sys/zvol.h>
+#endif
#ifdef __FreeBSD__
#undef dump_write
@@ -3445,6 +3448,11 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
drc->drc_newsnapobj =
dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
}
+
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ zvol_create_minors(dp->dp_spa, drc->drc_tofs);
+#endif
+
/*
* Release the hold from dmu_recv_begin. This must be done before
* we return to open context, so that when we free the dataset's dnode,
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -1572,6 +1572,9 @@ dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
dsl_props_set_sync_impl(ds->ds_prev,
ZPROP_SRC_LOCAL, ddsa->ddsa_props, tx);
}
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ zvol_create_minors(dp->dp_spa, name);
+#endif
dsl_dataset_rele(ds, FTAG);
}
}
@@ -1646,17 +1649,6 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props,
fnvlist_free(suspended);
}
-#ifdef __FreeBSD__
-#ifdef _KERNEL
- if (error == 0) {
- for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
- pair = nvlist_next_nvpair(snaps, pair)) {
- char *snapname = nvpair_name(pair);
- zvol_create_minors(snapname);
- }
- }
-#endif
-#endif
return (error);
}
@@ -2535,7 +2527,7 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
snprintf(newname, ZFS_MAX_DATASET_NAME_LEN, "%s@%s",
ddrsa->ddrsa_fsname, ddrsa->ddrsa_newsnapname);
zfsvfs_update_fromname(oldname, newname);
- zvol_rename_minors(oldname, newname);
+ zvol_rename_minors(dp->dp_spa, oldname, newname);
kmem_free(newname, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(oldname, ZFS_MAX_DATASET_NAME_LEN);
#endif
@@ -3087,9 +3079,6 @@ dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
}
#if defined(__FreeBSD__) && defined(_KERNEL)
- /* Take the spa_namespace_lock early so zvol renames don't deadlock. */
- mutex_enter(&spa_namespace_lock);
-
oldname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
newname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
#endif
@@ -3135,7 +3124,7 @@ dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
#if defined(__FreeBSD__) && defined(_KERNEL)
dsl_dataset_name(ds, newname);
zfsvfs_update_fromname(oldname, newname);
- zvol_rename_minors(oldname, newname);
+ zvol_rename_minors(dp->dp_spa, oldname, newname);
#endif
/* move any clone references */
@@ -3177,8 +3166,6 @@ dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
}
#if defined(__FreeBSD__) && defined(_KERNEL)
- mutex_exit(&spa_namespace_lock);
-
kmem_free(newname, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(oldname, ZFS_MAX_DATASET_NAME_LEN);
#endif
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -43,7 +43,11 @@
#include <sys/dsl_deleg.h>
#include <sys/dmu_impl.h>
#include <sys/zcp.h>
+#if defined(__FreeBSD__) && defined(_KERNEL)
+#include <sys/zvol.h>
+#endif
+
int
dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
{
@@ -489,6 +493,14 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, bool
if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0)
VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
tx));
+
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ char dsname[ZFS_MAX_DATASET_NAME_LEN];
+
+ dsl_dataset_name(ds, dsname);
+ zvol_remove_minors(dp->dp_spa, dsname);
+#endif
+
dsl_dir_rele(ds->ds_dir, ds);
ds->ds_dir = NULL;
dmu_object_free_zapified(mos, obj, tx);
@@ -979,6 +991,9 @@ dsl_destroy_head_sync(void *arg, dmu_tx_t *tx)
VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds));
dsl_destroy_head_sync_impl(ds, tx);
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ zvol_remove_minors(dp->dp_spa, ddha->ddha_name);
+#endif
dsl_dataset_rele(ds, FTAG);
}
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -2093,7 +2093,7 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
#ifdef __FreeBSD__
#ifdef _KERNEL
zfsvfs_update_fromname(ddra->ddra_oldname, ddra->ddra_newname);
- zvol_rename_minors(ddra->ddra_oldname, ddra->ddra_newname);
+ zvol_rename_minors(dp->dp_spa, ddra->ddra_oldname, ddra->ddra_newname);
#endif
#endif
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -32,6 +32,7 @@
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2017 Datto Inc.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
*/
/*
@@ -1280,6 +1281,24 @@ spa_activate(spa_t *spa, int mode)
*/
trim_thread_create(spa);
+ /*
+ * This taskq is used to perform zvol-minor-related tasks
+ * asynchronously. This has several advantages, including easy
+ * resolution of various deadlocks (zfsonlinux bug #3681).
+ *
+ * The taskq must be single threaded to ensure tasks are always
+ * processed in the order in which they were dispatched.
+ *
+ * A taskq per pool allows one 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.
+ */
+ spa->spa_zvol_taskq = taskq_create("z_zvol", 1, minclsyspri,
+ 1, INT_MAX, 0);
+
for (size_t i = 0; i < TXG_SIZE; i++) {
spa->spa_txg_zio[i] = zio_root(spa, NULL, NULL,
ZIO_FLAG_CANFAIL);
@@ -1323,6 +1342,11 @@ spa_deactivate(spa_t *spa)
spa_evicting_os_wait(spa);
+ if (spa->spa_zvol_taskq) {
+ taskq_destroy(spa->spa_zvol_taskq);
+ spa->spa_zvol_taskq = NULL;
+ }
+
txg_list_destroy(&spa->spa_vdev_txg_list);
list_destroy(&spa->spa_config_dirty_list);
@@ -4614,7 +4638,7 @@ spa_open_common(const char *pool, spa_t **spapp, void
#ifdef __FreeBSD__
#ifdef _KERNEL
if (firstopen)
- zvol_create_minors(spa->spa_name);
+ zvol_create_minors(spa, spa->spa_name);
#endif
#endif
}
@@ -5970,7 +5994,7 @@ spa_import(const char *pool, nvlist_t *config, nvlist_
#ifdef __FreeBSD__
#ifdef _KERNEL
- zvol_create_minors(pool);
+ zvol_create_minors(spa, pool);
#endif
#endif
return (0);
@@ -6119,6 +6143,12 @@ spa_export_common(char *pool, int new_state, nvlist_t
spa_open_ref(spa, FTAG);
mutex_exit(&spa_namespace_lock);
spa_async_suspend(spa);
+ if (spa->spa_zvol_taskq) {
+#ifdef _KERNEL
+ zvol_remove_minors(spa, spa_name(spa));
+#endif
+ taskq_wait(spa->spa_zvol_taskq);
+ }
mutex_enter(&spa_namespace_lock);
spa_close(spa, FTAG);
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h Fri Aug 28 13:15:13 2020 (r364917)
@@ -27,6 +27,7 @@
* Copyright 2013 Saso Kiselkov. All rights reserved.
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017, Intel Corporation.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
*/
#ifndef _SYS_SPA_IMPL_H
@@ -398,6 +399,8 @@ struct spa {
uint64_t spa_lowmem_last_txg; /* txg window start */
hrtime_t spa_ccw_fail_time; /* Conf cache write fail time */
+
+ taskq_t *spa_zvol_taskq; /* Taskq for minor management */
uint64_t spa_multihost; /* multihost aware (mmp) */
mmp_thread_t spa_mmp; /* multihost mmp thread */
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zvol.h Fri Aug 28 13:15:13 2020 (r364917)
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
*/
#ifndef _SYS_ZVOL_H
@@ -40,9 +41,6 @@ extern int zvol_check_volsize(uint64_t volsize, uint64
extern int zvol_check_volblocksize(uint64_t volblocksize);
extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
-extern int zvol_create_minor(const char *);
-extern int zvol_remove_minor(const char *);
-extern void zvol_remove_minors(const char *);
extern int zvol_set_volsize(const char *, uint64_t);
#ifdef illumos
@@ -72,8 +70,10 @@ extern void zvol_log_write_minor(void *minor_hdl, dmu_
#endif /* illumos */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-extern int zvol_create_minors(const char *name);
-extern void zvol_rename_minors(const char *oldname, const char *newname);
+extern void zvol_create_minors(spa_t *spa, const char *name);
+extern void zvol_remove_minors(spa_t *spa, const char *name);
+extern void zvol_rename_minors(spa_t *spa, const char *oldname,
+ const char *newname);
#endif
#endif /* _KERNEL */
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -1642,8 +1642,10 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
int error;
zfs_log_history(zc);
error = spa_destroy(zc->zc_name);
+#ifndef __FreeBSD__
if (error == 0)
zvol_remove_minors(zc->zc_name);
+#endif
return (error);
}
@@ -1694,8 +1696,10 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
zfs_log_history(zc);
error = spa_export(zc->zc_name, NULL, force, hardforce);
+#ifndef __FreeBSD__
if (error == 0)
zvol_remove_minors(zc->zc_name);
+#endif
return (error);
}
@@ -3395,13 +3399,23 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nv
if (error == 0) {
error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL,
nvprops, outnvl);
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ /*
+ * Wait for ZVOL operations to settle down before destroying.
+ */
+ if (error != 0) {
+ spa_t *spa;
+
+ if (spa_open(fsname, &spa, FTAG) == 0) {
+ taskqueue_drain_all(
+ spa->spa_zvol_taskq->tq_queue);
+ spa_close(spa, FTAG);
+ }
+ }
+#endif
if (error != 0)
(void) dsl_destroy_head(fsname);
}
-#ifdef __FreeBSD__
- if (error == 0 && type == DMU_OST_ZVOL)
- zvol_create_minors(fsname);
-#endif
return (error);
}
@@ -3443,10 +3457,6 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvl
if (error != 0)
(void) dsl_destroy_head(fsname);
}
-#ifdef __FreeBSD__
- if (error == 0)
- zvol_create_minors(fsname);
-#endif
return (error);
}
@@ -3738,9 +3748,6 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *
return (SET_ERROR(EXDEV));
zfs_unmount_snap(nvpair_name(pair));
-#if defined(__FreeBSD__)
- zvol_remove_minors(name);
-#endif
}
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
@@ -3924,10 +3931,8 @@ 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);
+#ifndef __FreeBSD__
if (ost == DMU_OST_ZVOL && err == 0)
-#ifdef __FreeBSD__
- zvol_remove_minors(zc->zc_name);
-#else
(void) zvol_remove_minor(zc->zc_name);
#endif
return (err);
@@ -4813,11 +4818,6 @@ zfs_ioc_recv(zfs_cmd_t *zc)
}
#endif
-#ifdef __FreeBSD__
- if (error == 0)
- zvol_create_minors(tofs);
-#endif
-
/*
* On error, restore the original props.
*/
@@ -6958,6 +6958,24 @@ zfsdev_ioctl(struct cdev *dev, u_long zcmd, caddr_t ar
out:
nvlist_free(innvl);
+
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ /*
+ * Wait for ZVOL changes to get applied.
+ * NB: taskqueue_drain_all() does less than taskq_wait(),
+ * but enough for what we want.
+ * And there is no equivalent illumos API.
+ */
+ if (error == 0) {
+ spa_t *spa;
+
+ if (spa_open(saved_poolname, &spa, FTAG) == 0) {
+ taskqueue_drain_all(
+ spa->spa_zvol_taskq->tq_queue);
+ spa_close(spa, FTAG);
+ }
+ }
+#endif
#ifdef illumos
rc = ddi_copyout(zc, (void *)arg, sizeof (zfs_cmd_t), flag);
Modified: stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
==============================================================================
--- stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c Fri Aug 28 10:33:19 2020 (r364916)
+++ stable/12/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c Fri Aug 28 13:15:13 2020 (r364917)
@@ -30,6 +30,7 @@
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
*/
/* Portions Copyright 2011 Martin Matuska <mm at FreeBSD.org> */
@@ -184,6 +185,20 @@ typedef struct zvol_state {
#endif
} zvol_state_t;
+typedef enum {
+ ZVOL_ASYNC_CREATE_MINORS,
+ ZVOL_ASYNC_REMOVE_MINORS,
+ ZVOL_ASYNC_RENAME_MINORS,
+ ZVOL_ASYNC_MAX
+} zvol_async_op_t;
+
+typedef struct {
+ zvol_async_op_t op;
+ char pool[ZFS_MAX_DATASET_NAME_LEN];
+ char name1[ZFS_MAX_DATASET_NAME_LEN];
+ char name2[ZFS_MAX_DATASET_NAME_LEN];
+} zvol_task_t;
+
#ifndef illumos
static LIST_HEAD(, zvol_state) all_zvols;
#endif
@@ -606,7 +621,7 @@ zvol_name2minor(const char *name, minor_t *minor)
/*
* Create a minor node (plus a whole lot more) for the specified volume.
*/
-int
+static int
zvol_create_minor(const char *name)
{
zfs_soft_state_t *zs;
@@ -690,7 +705,6 @@ zvol_create_minor(const char *name)
if (error != 0 || mode == ZFS_VOLMODE_DEFAULT)
mode = volmode;
- DROP_GIANT();
zv->zv_volmode = mode;
if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
g_topology_lock();
@@ -765,7 +779,6 @@ zvol_create_minor(const char *name)
zvol_geom_run(zv);
g_topology_unlock();
}
- PICKUP_GIANT();
ZFS_LOG(1, "ZVOL %s created.", name);
#endif
@@ -819,22 +832,6 @@ zvol_remove_zv(zvol_state_t *zv)
}
int
-zvol_remove_minor(const char *name)
-{
- zvol_state_t *zv;
- int rc;
-
- mutex_enter(&zfsdev_state_lock);
- if ((zv = zvol_minor_lookup(name)) == NULL) {
- mutex_exit(&zfsdev_state_lock);
- return (SET_ERROR(ENXIO));
- }
- rc = zvol_remove_zv(zv);
- mutex_exit(&zfsdev_state_lock);
- return (rc);
-}
-
-int
zvol_first_open(zvol_state_t *zv)
{
dmu_object_info_t doi;
@@ -975,7 +972,7 @@ zvol_update_volsize(objset_t *os, uint64_t volsize)
}
void
-zvol_remove_minors(const char *name)
+zvol_remove_minors_impl(const char *name)
{
#ifdef illumos
zvol_state_t *zv;
@@ -1003,7 +1000,6 @@ zvol_remove_minors(const char *name)
namelen = strlen(name);
- DROP_GIANT();
mutex_enter(&zfsdev_state_lock);
LIST_FOREACH_SAFE(zv, &all_zvols, zv_links, tzv) {
@@ -1016,7 +1012,6 @@ zvol_remove_minors(const char *name)
}
mutex_exit(&zfsdev_state_lock);
- PICKUP_GIANT();
#endif /* illumos */
}
@@ -2919,7 +2914,7 @@ zvol_create_snapshots(objset_t *os, const char *name)
}
int
-zvol_create_minors(const char *name)
+zvol_create_minors_impl(const char *name)
{
uint64_t cookie;
objset_t *os;
@@ -2975,7 +2970,7 @@ zvol_create_minors(const char *name)
while (dmu_dir_list_next(os, MAXPATHLEN - (p - osname), p, NULL,
&cookie) == 0) {
dmu_objset_rele(os, FTAG);
- (void)zvol_create_minors(osname);
+ (void)zvol_create_minors_impl(osname);
if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) {
printf("ZFS WARNING: Unable to put hold on %s (error=%d).\n",
name, error);
@@ -3044,7 +3039,7 @@ zvol_rename_minor(zvol_state_t *zv, const char *newnam
}
void
-zvol_rename_minors(const char *oldname, const char *newname)
+zvol_rename_minors_impl(const char *oldname, const char *newname)
{
char name[MAXPATHLEN];
struct g_provider *pp;
@@ -3057,7 +3052,6 @@ zvol_rename_minors(const char *oldname, const char *ne
oldnamelen = strlen(oldname);
newnamelen = strlen(newname);
- DROP_GIANT();
/* See comment in zvol_open(). */
if (!MUTEX_HELD(&zfsdev_state_lock)) {
mutex_enter(&zfsdev_state_lock);
@@ -3079,7 +3073,88 @@ zvol_rename_minors(const char *oldname, const char *ne
if (locked)
mutex_exit(&zfsdev_state_lock);
- PICKUP_GIANT();
+}
+
+static zvol_task_t *
+zvol_task_alloc(zvol_async_op_t op, const char *name1, const char *name2)
+{
+ zvol_task_t *task;
+ char *delim;
+
+ task = kmem_zalloc(sizeof (zvol_task_t), KM_SLEEP);
+ task->op = op;
+ delim = strchr(name1, '/');
+ strlcpy(task->pool, name1, delim ? (delim - name1 + 1) : MAXNAMELEN);
+
+ strlcpy(task->name1, name1, MAXNAMELEN);
+ if (name2 != NULL)
+ strlcpy(task->name2, name2, MAXNAMELEN);
+
+ return (task);
+}
+
+static void
+zvol_task_free(zvol_task_t *task)
+{
+ kmem_free(task, sizeof (zvol_task_t));
+}
+
+/*
+ * The worker thread function performed asynchronously.
+ */
+static void
+zvol_task_cb(void *param)
+{
+ zvol_task_t *task = (zvol_task_t *)param;
+
+ switch (task->op) {
+ case ZVOL_ASYNC_CREATE_MINORS:
+ (void) zvol_create_minors_impl(task->name1);
+ break;
+ case ZVOL_ASYNC_REMOVE_MINORS:
+ zvol_remove_minors_impl(task->name1);
+ break;
+ case ZVOL_ASYNC_RENAME_MINORS:
+ zvol_rename_minors_impl(task->name1, task->name2);
+ break;
+ default:
+ VERIFY(0);
+ break;
+ }
+
+ zvol_task_free(task);
+}
+
+static void
+zvol_minors_helper(spa_t *spa, zvol_async_op_t op, const char *name1,
+ const char *name2)
+{
+ zvol_task_t *task;
+
+ if (dataset_name_hidden(name1))
+ return;
+ if (name2 != NULL && dataset_name_hidden(name2))
+ return;
+ task = zvol_task_alloc(op, name1, name2);
+ (void)taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+}
+
+void
+zvol_create_minors(spa_t *spa, const char *name)
+{
+ zvol_minors_helper(spa, ZVOL_ASYNC_CREATE_MINORS, name, NULL);
+}
+
+void
+zvol_remove_minors(spa_t *spa, const char *name)
+{
+ zvol_minors_helper(spa, ZVOL_ASYNC_REMOVE_MINORS, name, NULL);
+}
+
+void
+zvol_rename_minors(spa_t *spa, const char *oldname, const char *newname)
+{
+ zvol_minors_helper(spa, ZVOL_ASYNC_RENAME_MINORS, oldname, newname);
}
static int
More information about the svn-src-stable-12
mailing list