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 <[email protected]> */
@@ -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
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to