diff options
author | mav <mav@FreeBSD.org> | 2016-10-28 18:18:53 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2016-10-28 18:18:53 +0000 |
commit | c8c4c6244daef57c7b854dfe5de8a10d8675634b (patch) | |
tree | a8e6cb6833101513ffe3bbb9ecea29fca0736409 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c | |
parent | c60f65ebc02c81225657a336afc72d7d08f4fe36 (diff) | |
download | FreeBSD-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.c | 40 |
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); } |