--- sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c.orig
+++ sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c
@@ -128,7 +128,8 @@
 			struct g_provider *zsg_provider;
 		} _zso_geom;
 	} _zso_state;
-	int zso_dying;
+	boolean_t zso_opening;
+	boolean_t zso_dying;
 };
 
 static uint32_t zvol_minors;
@@ -226,12 +227,13 @@
 	}
 
 retry:
-	zv = atomic_load_ptr(&pp->private);
+	zv = pp->private;
 	if (zv == NULL)
 		return (SET_ERROR(ENXIO));
 
 	mutex_enter(&zv->zv_state_lock);
-	if (zv->zv_zso->zso_dying || zv->zv_flags & ZVOL_REMOVING) {
+	g_topology_unlock();
+	if (zv->zv_flags & ZVOL_REMOVING || zv->zv_zso->zso_dying) {
 		err = SET_ERROR(ENXIO);
 		goto out_locked;
 	}
@@ -245,18 +247,16 @@
 	if (zv->zv_open_count == 0) {
 		drop_suspend = B_TRUE;
 		if (!rw_tryenter(&zv->zv_suspend_lock, ZVOL_RW_READER)) {
-			mutex_exit(&zv->zv_state_lock);
-
 			/*
-			 * Removal may happen while the locks are down, so
-			 * we can't trust zv any longer; we have to start over.
+			 * Set a flag to interlock with zvol_os_remove_minor()
+			 * while locks are dropped.
 			 */
-			zv = atomic_load_ptr(&pp->private);
-			if (zv == NULL)
-				return (SET_ERROR(ENXIO));
-
+			zv->zv_zso->zso_opening = B_TRUE;
+			mutex_exit(&zv->zv_state_lock);
 			rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
 			mutex_enter(&zv->zv_state_lock);
+			zv->zv_zso->zso_opening = B_FALSE;
+			cv_broadcast(&zv->zv_removing_cv);
 
 			if (zv->zv_zso->zso_dying ||
 			    zv->zv_flags & ZVOL_REMOVING) {
@@ -289,6 +289,7 @@
 				rw_exit(&zv->zv_suspend_lock);
 				drop_suspend = B_FALSE;
 				kern_yield(PRI_USER);
+				g_topology_lock();
 				goto retry;
 			} else {
 				drop_namespace = B_TRUE;
@@ -337,6 +338,7 @@
 	mutex_exit(&zv->zv_state_lock);
 	if (drop_suspend)
 		rw_exit(&zv->zv_suspend_lock);
+	g_topology_lock();
 	return (err);
 }
 
@@ -348,11 +350,12 @@
 	boolean_t drop_suspend = B_TRUE;
 	int new_open_count;
 
-	zv = atomic_load_ptr(&pp->private);
+	zv = pp->private;
 	if (zv == NULL)
 		return (SET_ERROR(ENXIO));
 
 	mutex_enter(&zv->zv_state_lock);
+	g_topology_unlock();
 	if (zv->zv_flags & ZVOL_EXCL) {
 		ASSERT3U(zv->zv_open_count, ==, 1);
 		zv->zv_flags &= ~ZVOL_EXCL;
@@ -413,6 +416,7 @@
 
 	if (drop_suspend)
 		rw_exit(&zv->zv_suspend_lock);
+	g_topology_lock();
 	return (0);
 }
 
@@ -448,7 +452,7 @@
 	    ("Unsupported access request to %s (acr=%d, acw=%d, ace=%d).",
 	    pp->name, acr, acw, ace));
 
-	if (atomic_load_ptr(&pp->private) == NULL) {
+	if (pp->private == NULL) {
 		if (acr <= 0 && acw <= 0 && ace <= 0)
 			return (0);
 		return (pp->error);
@@ -473,24 +477,16 @@
 	if (acw != 0)
 		flags |= FWRITE;
 
-	g_topology_unlock();
 	if (count > 0)
 		error = zvol_geom_open(pp, flags, count);
 	else
 		error = zvol_geom_close(pp, flags, -count);
-	g_topology_lock();
 	return (error);
 }
 
 static void
 zvol_geom_bio_start(struct bio *bp)
 {
-	zvol_state_t *zv = bp->bio_to->private;
-
-	if (zv == NULL) {
-		g_io_deliver(bp, ENXIO);
-		return;
-	}
 	if (bp->bio_cmd == BIO_GETATTR) {
 		if (zvol_geom_bio_getattr(bp))
 			g_io_deliver(bp, EOPNOTSUPP);
@@ -507,7 +503,10 @@
 	zvol_state_t *zv;
 
 	zv = bp->bio_to->private;
-	ASSERT3P(zv, !=, NULL);
+	if (zv == NULL) {
+		g_io_deliver(bp, ENXIO);
+		return (0);
+	}
 
 	spa_t *spa = dmu_objset_spa(zv->zv_objset);
 	uint64_t refd, avail, usedobjs, availobjs;
@@ -920,7 +919,7 @@
 		return (SET_ERROR(ENXIO));
 
 	mutex_enter(&zv->zv_state_lock);
-	if (zv->zv_zso->zso_dying || zv->zv_flags & ZVOL_REMOVING) {
+	if (zv->zv_flags & ZVOL_REMOVING || zv->zv_zso->zso_dying) {
 		err = SET_ERROR(ENXIO);
 		goto out_locked;
 	}
@@ -1251,24 +1250,32 @@
 {
 	int error = 0;
 
-	ASSERT(RW_LOCK_HELD(&zvol_state_lock));
+	ASSERT(RW_WRITE_HELD(&zvol_state_lock));
 	ASSERT(MUTEX_HELD(&zv->zv_state_lock));
 
 	/* Move to a new hashtable entry.  */
 	zv->zv_hash = zvol_name_hash(newname);
 	hlist_del(&zv->zv_hlink);
 	hlist_add_head(&zv->zv_hlink, ZVOL_HT_HEAD(zv->zv_hash));
+	strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
+	dataset_kstats_rename(&zv->zv_kstat, newname);
 
 	if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
 		struct zvol_state_geom *zsg = &zv->zv_zso->zso_geom;
-		struct g_provider *pp = zsg->zsg_provider;
+		struct g_provider *pp;
 		struct g_geom *gp;
 
+		mutex_exit(&zv->zv_state_lock);
 		g_topology_lock();
+		pp = zsg->zsg_provider;
+		if (pp->private == NULL) {
+			g_topology_unlock();
+			mutex_enter(&zv->zv_state_lock);
+			return (SET_ERROR(ENXIO));
+		}
 		gp = pp->geom;
 		ASSERT3P(gp, !=, NULL);
 
-		zsg->zsg_provider = NULL;
 		g_wither_provider(pp, ENXIO);
 
 		pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, newname);
@@ -1278,6 +1285,7 @@
 		pp->private = zv;
 		zsg->zsg_provider = pp;
 		g_error_provider(pp, 0);
+		mutex_enter(&zv->zv_state_lock);
 		g_topology_unlock();
 	} else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
 		struct zvol_state_dev *zsd = &zv->zv_zso->zso_dev;
@@ -1310,8 +1318,6 @@
 			zsd->zsd_cdev = dev;
 		}
 	}
-	strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
-	dataset_kstats_rename(&zv->zv_kstat, newname);
 
 	return (error);
 }
@@ -1400,27 +1406,32 @@
 void
 zvol_os_remove_minor(zvol_state_t *zv)
 {
+	struct zvol_state_os *zso = zv->zv_zso;
+
 	ASSERT(MUTEX_HELD(&zv->zv_state_lock));
 	ASSERT0(zv->zv_open_count);
 	ASSERT0(atomic_read(&zv->zv_suspend_ref));
 	ASSERT(zv->zv_flags & ZVOL_REMOVING);
 
-	struct zvol_state_os *zso = zv->zv_zso;
-	zv->zv_zso = NULL;
-
 	if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
 		struct zvol_state_geom *zsg = &zso->zso_geom;
-		struct g_provider *pp = zsg->zsg_provider;
-		atomic_store_ptr(&pp->private, NULL);
-		mutex_exit(&zv->zv_state_lock);
+		struct g_provider *pp;
 
+		while (zso->zso_opening)
+			cv_wait(&zv->zv_removing_cv, &zv->zv_state_lock);
+		zv->zv_zso = NULL;
+		mutex_exit(&zv->zv_state_lock);
 		g_topology_lock();
+		pp = zsg->zsg_provider;
+		pp->private = NULL;
 		g_wither_geom(pp->geom, ENXIO);
 		g_topology_unlock();
+		g_waitidle(curthread);
 	} else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
 		struct zvol_state_dev *zsd = &zso->zso_dev;
 		struct cdev *dev = zsd->zsd_cdev;
 
+		zv->zv_zso = NULL;
 		if (dev != NULL)
 			atomic_store_ptr(&dev->si_drv2, NULL);
 		mutex_exit(&zv->zv_state_lock);
@@ -1545,6 +1556,7 @@
 		g_error_provider(zv->zv_zso->zso_geom.zsg_provider, 0);
 		/* geom was locked inside zvol_alloc() function */
 		g_topology_unlock();
+		g_waitidle(curthread);
 	}
 out_doi:
 	kmem_free(doi, sizeof (dmu_object_info_t));
@@ -1565,10 +1577,10 @@
 	zv->zv_volsize = volsize;
 	if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
 		struct zvol_state_geom *zsg = &zv->zv_zso->zso_geom;
-		struct g_provider *pp = zsg->zsg_provider;
+		struct g_provider *pp;
 
 		g_topology_lock();
-
+		pp = zsg->zsg_provider;
 		if (pp->private == NULL) {
 			g_topology_unlock();
 			return (SET_ERROR(ENXIO));
--- sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c.orig
+++ sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
@@ -1796,7 +1796,7 @@
 {
 	int readonly = get_disk_ro(zv->zv_zso->zvo_disk);
 
-	ASSERT(RW_LOCK_HELD(&zvol_state_lock));
+	ASSERT(RW_WRITE_HELD(&zvol_state_lock));
 	ASSERT(MUTEX_HELD(&zv->zv_state_lock));
 
 	strlcpy(zv->zv_name, newname, sizeof (zv->zv_name));
--- sys/contrib/openzfs/module/zfs/zvol.c.orig
+++ sys/contrib/openzfs/module/zfs/zvol.c
@@ -1762,9 +1762,10 @@
 	if (zvol_inhibit_dev)
 		return;
 
+	last_error = 0;
 	oldnamelen = strlen(oldname);
 
-	rw_enter(&zvol_state_lock, RW_READER);
+	rw_enter(&zvol_state_lock, RW_WRITER);
 
 	for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
 		zv_next = list_next(&zvol_state_list, zv);
@@ -1781,6 +1782,8 @@
 			    zv->zv_name + oldnamelen + 1);
 			error = zvol_os_rename_minor(zv, name);
 			kmem_strfree(name);
+		} else {
+			error = 0;
 		}
 		if (error) {
 			last_error = error;
@@ -1936,6 +1939,10 @@
 	uint64_t zsda_value;
 	zprop_source_t zsda_source;
 	zfs_prop_t zsda_prop;
+	taskqid_t zsda_taskqid;
+	boolean_t zsda_dispatched;
+	kmutex_t zsda_lock;
+	kcondvar_t zsda_cv;
 } zvol_set_prop_int_arg_t;
 
 /*
@@ -1966,6 +1973,7 @@
 	char dsname[ZFS_MAX_DATASET_NAME_LEN];
 	zvol_task_t *task;
 	uint64_t prop;
+	taskqid_t id;
 
 	const char *prop_name = zfs_prop_to_name(zsda->zsda_prop);
 	dsl_dataset_name(ds, dsname);
@@ -1984,8 +1992,12 @@
 	}
 	task->zt_value = prop;
 	strlcpy(task->zt_name1, dsname, sizeof (task->zt_name1));
-	(void) taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb,
-	    task, TQ_SLEEP);
+	id = taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb, task,
+	    TQ_SLEEP);
+	mutex_enter(&zsda->zsda_lock);
+	if (id != TASKQID_INVALID && id > zsda->zsda_taskqid)
+		zsda->zsda_taskqid = id;
+	mutex_exit(&zsda->zsda_lock);
 	return (0);
 }
 
@@ -2018,6 +2030,11 @@
 	dmu_objset_find_dp(dp, dd->dd_object, zvol_set_common_sync_cb,
 	    zsda, DS_FIND_CHILDREN);
 
+	mutex_enter(&zsda->zsda_lock);
+	zsda->zsda_dispatched = TRUE;
+	cv_broadcast(&zsda->zsda_cv);
+	mutex_exit(&zsda->zsda_lock);
+
 	dsl_dir_rele(dd, FTAG);
 }
 
@@ -2026,14 +2043,38 @@
     uint64_t val)
 {
 	zvol_set_prop_int_arg_t zsda;
+	spa_t *spa;
+	int error;
 
 	zsda.zsda_name = ddname;
 	zsda.zsda_source = source;
 	zsda.zsda_value = val;
 	zsda.zsda_prop = prop;
+	zsda.zsda_taskqid = TASKQID_INVALID;
+	zsda.zsda_dispatched = FALSE;
+	mutex_init(&zsda.zsda_lock, NULL, MUTEX_DEFAULT, NULL);
+	cv_init(&zsda.zsda_cv, NULL, CV_DEFAULT, NULL);
 
-	return (dsl_sync_task(ddname, zvol_set_common_check,
-	    zvol_set_common_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
+	error = spa_open(ddname, &spa, FTAG);
+	if (error != 0)
+		goto out;
+	error = dsl_sync_task(ddname, zvol_set_common_check,
+	    zvol_set_common_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE);
+	if (error == 0) {
+		mutex_enter(&zsda.zsda_lock);
+		while (!zsda.zsda_dispatched)
+			cv_wait(&zsda.zsda_cv, &zsda.zsda_lock);
+		mutex_exit(&zsda.zsda_lock);
+
+		if (zsda.zsda_taskqid != TASKQID_INVALID)
+			taskq_wait_outstanding(spa->spa_zvol_taskq,
+			    zsda.zsda_taskqid);
+	}
+	spa_close(spa, FTAG);
+out:
+	cv_destroy(&zsda.zsda_cv);
+	mutex_destroy(&zsda.zsda_lock);
+	return (error);
 }
 
 void
