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
This commit is contained in:
parent
a6512306ce
commit
81c4584e30
@ -878,27 +878,36 @@ zvol_open(struct g_provider *pp, int flag, int count)
|
|||||||
{
|
{
|
||||||
zvol_state_t *zv;
|
zvol_state_t *zv;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
boolean_t locked = B_FALSE;
|
||||||
|
|
||||||
if (MUTEX_HELD(&spa_namespace_lock)) {
|
/*
|
||||||
/*
|
* Protect against recursively entering spa_namespace_lock
|
||||||
* If the spa_namespace_lock is being held, it means that ZFS
|
* when spa_open() is used for a pool on a (local) ZVOL(s).
|
||||||
* is trying to open ZVOL as its VDEV. This is not supported.
|
* This is needed since we replaced upstream zfsdev_state_lock
|
||||||
*/
|
* with spa_namespace_lock in the ZVOL code.
|
||||||
return (EOPNOTSUPP);
|
* 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;
|
zv = pp->private;
|
||||||
if (zv == NULL) {
|
if (zv == NULL) {
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zv->zv_total_opens == 0)
|
if (zv->zv_total_opens == 0)
|
||||||
err = zvol_first_open(zv);
|
err = zvol_first_open(zv);
|
||||||
if (err) {
|
if (err) {
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
|
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
|
||||||
@ -920,13 +929,15 @@ zvol_open(struct g_provider *pp, int flag, int count)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
zv->zv_total_opens += count;
|
zv->zv_total_opens += count;
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
|
|
||||||
return (err);
|
return (err);
|
||||||
out:
|
out:
|
||||||
if (zv->zv_total_opens == 0)
|
if (zv->zv_total_opens == 0)
|
||||||
zvol_last_close(zv);
|
zvol_last_close(zv);
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -936,12 +947,18 @@ zvol_close(struct g_provider *pp, int flag, int count)
|
|||||||
{
|
{
|
||||||
zvol_state_t *zv;
|
zvol_state_t *zv;
|
||||||
int error = 0;
|
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;
|
zv = pp->private;
|
||||||
if (zv == NULL) {
|
if (zv == NULL) {
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,7 +981,8 @@ zvol_close(struct g_provider *pp, int flag, int count)
|
|||||||
if (zv->zv_total_opens == 0)
|
if (zv->zv_total_opens == 0)
|
||||||
zvol_last_close(zv);
|
zvol_last_close(zv);
|
||||||
|
|
||||||
mutex_exit(&spa_namespace_lock);
|
if (locked)
|
||||||
|
mutex_exit(&spa_namespace_lock);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user