aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorMatthew Macy <[email protected]>2020-08-30 14:11:33 -0700
committerGitHub <[email protected]>2020-08-30 14:11:33 -0700
commitcd23154a8c2b657d1f4c15cd5f35c20f17e119d2 (patch)
treed9206cc5efe2ec2756effcb0e8db959a255e8742 /module
parent0e6a7aaac01eaf7dea8d4ce56555e0cc29a7d606 (diff)
FreeBSD: Fix spurious failure in zvol_geom_open
In zvol_geom_open on first open we need to guarantee that the namespace lock is held to avoid spurious failures in zvol_first_open. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Ryan Moeller <[email protected]> Signed-off-by: Matt Macy <[email protected]> Closes #10841
Diffstat (limited to 'module')
-rw-r--r--module/os/freebsd/zfs/zvol_os.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c
index 113733a5c..19018be3b 100644
--- a/module/os/freebsd/zfs/zvol_os.c
+++ b/module/os/freebsd/zfs/zvol_os.c
@@ -210,6 +210,7 @@ zvol_geom_open(struct g_provider *pp, int flag, int count)
zvol_state_t *zv;
int err = 0;
boolean_t drop_suspend = B_TRUE;
+ boolean_t drop_namespace = B_FALSE;
if (!zpool_on_zvol && tsd_get(zfs_geom_probe_vdev_key) != NULL) {
/*
@@ -223,13 +224,28 @@ zvol_geom_open(struct g_provider *pp, int flag, int count)
return (SET_ERROR(EOPNOTSUPP));
}
+retry:
rw_enter(&zvol_state_lock, ZVOL_RW_READER);
zv = pp->private;
if (zv == NULL) {
+ if (drop_namespace)
+ mutex_exit(&spa_namespace_lock);
rw_exit(&zvol_state_lock);
return (SET_ERROR(ENXIO));
}
+ if (zv->zv_open_count == 0 && !mutex_owned(&spa_namespace_lock)) {
+ /*
+ * We need to guarantee that the namespace lock is held
+ * to avoid spurious failures in zvol_first_open
+ */
+ drop_namespace = B_TRUE;
+ if (!mutex_tryenter(&spa_namespace_lock)) {
+ rw_exit(&zvol_state_lock);
+ mutex_enter(&spa_namespace_lock);
+ goto retry;
+ }
+ }
mutex_enter(&zv->zv_state_lock);
ASSERT(zv->zv_zso->zso_volmode == ZFS_VOLMODE_GEOM);
@@ -291,6 +307,8 @@ zvol_geom_open(struct g_provider *pp, int flag, int count)
#endif
zv->zv_open_count += count;
+ if (drop_namespace)
+ mutex_exit(&spa_namespace_lock);
mutex_exit(&zv->zv_state_lock);
if (drop_suspend)
rw_exit(&zv->zv_suspend_lock);
@@ -300,6 +318,8 @@ out_open_count:
if (zv->zv_open_count == 0)
zvol_last_close(zv);
out_mutex:
+ if (drop_namespace)
+ mutex_exit(&spa_namespace_lock);
mutex_exit(&zv->zv_state_lock);
if (drop_suspend)
rw_exit(&zv->zv_suspend_lock);