summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2012-09-22 17:42:53 +0000
committeravg <avg@FreeBSD.org>2012-09-22 17:42:53 +0000
commit02934e110a785a9a3f85509757c2a164e02801f6 (patch)
tree238e6a86617d39ecabbcce3d2d7d2b58f2e56a63 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
parent49513a358327ab44bfa3bdd8356dd64cc35fbc91 (diff)
downloadFreeBSD-src-02934e110a785a9a3f85509757c2a164e02801f6.zip
FreeBSD-src-02934e110a785a9a3f85509757c2a164e02801f6.tar.gz
zfs: allow a zvol to be used as a pool vdev, again
Do this by checking if spa_namespace_lock is already held and not taking it again in that case. Add a comment explaining why that is done and why it is safe. Reviewed by: pjd MFC after: 24 days
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.c48
1 files changed, 33 insertions, 15 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 1b2a4da..be4f518 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -878,27 +878,36 @@ zvol_open(struct g_provider *pp, int flag, int count)
{
zvol_state_t *zv;
int err = 0;
+ boolean_t locked = B_FALSE;
- if (MUTEX_HELD(&spa_namespace_lock)) {
- /*
- * If the spa_namespace_lock is being held, it means that ZFS
- * is trying to open ZVOL as its VDEV. This is not supported.
- */
- return (EOPNOTSUPP);
+ /*
+ * 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(&spa_namespace_lock)) {
+ mutex_enter(&spa_namespace_lock);
+ locked = B_TRUE;
}
- mutex_enter(&spa_namespace_lock);
-
zv = pp->private;
if (zv == NULL) {
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (ENXIO);
}
if (zv->zv_total_opens == 0)
err = zvol_first_open(zv);
if (err) {
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (err);
}
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
@@ -920,13 +929,15 @@ zvol_open(struct g_provider *pp, int flag, int count)
#endif
zv->zv_total_opens += count;
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (err);
out:
if (zv->zv_total_opens == 0)
zvol_last_close(zv);
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (err);
}
@@ -936,12 +947,18 @@ zvol_close(struct g_provider *pp, int flag, int count)
{
zvol_state_t *zv;
int error = 0;
+ boolean_t locked = B_FALSE;
- mutex_enter(&spa_namespace_lock);
+ /* See comment in zvol_open(). */
+ if (!MUTEX_HELD(&spa_namespace_lock)) {
+ mutex_enter(&spa_namespace_lock);
+ locked = B_TRUE;
+ }
zv = pp->private;
if (zv == NULL) {
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (ENXIO);
}
@@ -964,7 +981,8 @@ zvol_close(struct g_provider *pp, int flag, int count)
if (zv->zv_total_opens == 0)
zvol_last_close(zv);
- mutex_exit(&spa_namespace_lock);
+ if (locked)
+ mutex_exit(&spa_namespace_lock);
return (error);
}
OpenPOWER on IntegriCloud