summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/os/linux/zfs/zvol_os.c13
-rw-r--r--module/zfs/zvol.c7
2 files changed, 14 insertions, 6 deletions
diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
index b89028dc3..2cb0cfca7 100644
--- a/module/os/linux/zfs/zvol_os.c
+++ b/module/os/linux/zfs/zvol_os.c
@@ -845,6 +845,11 @@ out_kmem:
* At this time, the structure is not opened by anyone, is taken off
* the zvol_state_list, and has its private data set to NULL.
* The zvol_state_lock is dropped.
+ *
+ * This function may take many milliseconds to complete (e.g. we've seen
+ * it take over 256ms), due to the calls to "blk_cleanup_queue" and
+ * "del_gendisk". Thus, consumers need to be careful to account for this
+ * latency when calling this function.
*/
static void
zvol_free(zvol_state_t *zv)
@@ -1089,6 +1094,14 @@ zvol_fini(void)
{
zvol_remove_minors_impl(NULL);
+ /*
+ * The call to "zvol_remove_minors_impl" may dispatch entries to
+ * the system_taskq, but it doesn't wait for those entires to
+ * complete before it returns. Thus, we must wait for all of the
+ * removals to finish, before we can continue.
+ */
+ taskq_wait_outstanding(system_taskq, 0);
+
zvol_fini_impl();
blk_unregister_region(MKDEV(zvol_major, 0), 1UL << MINORBITS);
unregister_blkdev(zvol_major, ZVOL_DRIVER);
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 9b26084bb..e76a1c61b 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -1170,7 +1170,7 @@ zvol_remove_minors_impl(const char *name)
{
zvol_state_t *zv, *zv_next;
int namelen = ((name) ? strlen(name) : 0);
- taskqid_t t, tid = TASKQID_INVALID;
+ taskqid_t t;
list_t free_list;
if (zvol_inhibit_dev)
@@ -1217,8 +1217,6 @@ zvol_remove_minors_impl(const char *name)
(task_func_t *)ops->zv_free, zv, TQ_SLEEP);
if (t == TASKQID_INVALID)
list_insert_head(&free_list, zv);
- else
- tid = t;
} else {
mutex_exit(&zv->zv_state_lock);
}
@@ -1230,9 +1228,6 @@ zvol_remove_minors_impl(const char *name)
list_remove(&free_list, zv);
ops->zv_free(zv);
}
-
- if (tid != TASKQID_INVALID)
- taskq_wait_outstanding(system_taskq, tid);
}
/* Remove minor for this specific volume only */