summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2016-10-28 18:18:53 +0000
committermav <mav@FreeBSD.org>2016-10-28 18:18:53 +0000
commitc8c4c6244daef57c7b854dfe5de8a10d8675634b (patch)
treea8e6cb6833101513ffe3bbb9ecea29fca0736409 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
parentc60f65ebc02c81225657a336afc72d7d08f4fe36 (diff)
downloadFreeBSD-src-c8c4c6244daef57c7b854dfe5de8a10d8675634b.zip
FreeBSD-src-c8c4c6244daef57c7b854dfe5de8a10d8675634b.tar.gz
MFC r294329 (by asomers): Disallow zvol-backed ZFS pools
Using zvols as backing devices for ZFS pools is fraught with panics and deadlocks. For example, attempting to online a missing device in the presence of a zvol can cause a panic when vdev_geom tastes the zvol. Better to completely disable vdev_geom from ever opening a zvol. The solution relies on setting a thread-local variable during vdev_geom_open, and returning EOPNOTSUPP during zvol_open if that thread-local variable is set. Remove the check for MUTEX_HELD(&zfsdev_state_lock) in zvol_open. Its intent was to prevent a recursive mutex acquisition panic. However, the new check for the thread-local variable also fixes that problem. Also, fix a panic in vdev_geom_taste_orphan. For an unknown reason, this function was set to panic. But it can occur that a device disappears during tasting, and it causes no problems to ignore this departure.
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c40
1 files changed, 16 insertions, 24 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index 77d951e..d1427b0 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -1123,36 +1123,30 @@ zvol_open(struct g_provider *pp, int flag, int count)
return (err);
}
#else /* !illumos */
- boolean_t locked = B_FALSE;
-
- /*
- * Protect against recursively entering spa_namespace_lock
- * when spa_open() is used for a pool on a (local) ZVOL(s).
- * This is needed since we replaced upstream zfsdev_state_lock
- * with spa_namespace_lock in the ZVOL code.
- * We are using the same trick as spa_open().
- * Note that calls in zvol_first_open which need to resolve
- * pool name to a spa object will enter spa_open()
- * recursively, but that function already has all the
- * necessary protection.
- */
- if (!MUTEX_HELD(&zfsdev_state_lock)) {
- mutex_enter(&zfsdev_state_lock);
- locked = B_TRUE;
+ if (tsd_get(zfs_geom_probe_vdev_key) != NULL) {
+ /*
+ * if zfs_geom_probe_vdev_key is set, that means that zfs is
+ * attempting to probe geom providers while looking for a
+ * replacement for a missing VDEV. In this case, the
+ * spa_namespace_lock will not be held, but it is still illegal
+ * to use a zvol as a vdev. Deadlocks can result if another
+ * thread has spa_namespace_lock
+ */
+ return (EOPNOTSUPP);
}
+ mutex_enter(&zfsdev_state_lock);
+
zv = pp->private;
if (zv == NULL) {
- if (locked)
- mutex_exit(&zfsdev_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (SET_ERROR(ENXIO));
}
if (zv->zv_total_opens == 0) {
err = zvol_first_open(zv);
if (err) {
- if (locked)
- mutex_exit(&zfsdev_state_lock);
+ mutex_exit(&zfsdev_state_lock);
return (err);
}
pp->mediasize = zv->zv_volsize;
@@ -1186,8 +1180,7 @@ zvol_open(struct g_provider *pp, int flag, int count)
mutex_exit(&zfsdev_state_lock);
#else
zv->zv_total_opens += count;
- if (locked)
- mutex_exit(&zfsdev_state_lock);
+ mutex_exit(&zfsdev_state_lock);
#endif
return (err);
@@ -1197,8 +1190,7 @@ out:
#ifdef illumos
mutex_exit(&zfsdev_state_lock);
#else
- if (locked)
- mutex_exit(&zfsdev_state_lock);
+ mutex_exit(&zfsdev_state_lock);
#endif
return (err);
}
OpenPOWER on IntegriCloud