From f4c8e9c69b5410cf5edf891bfab2660820cc1861 Mon Sep 17 00:00:00 2001 From: Matthew Macy Date: Sun, 30 Aug 2020 14:11:33 -0700 Subject: [PATCH] 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 Reviewed-by: Ryan Moeller Signed-off-by: Matt Macy Closes #10841 --- module/os/freebsd/zfs/zvol_os.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 113733a5c1..19018be3b1 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);