diff options
author | Ryan Moeller <[email protected]> | 2020-11-06 13:52:16 -0500 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2020-11-10 11:07:25 -0800 |
commit | 2186ed33f1a24313ee9b62591cece6373a8378f6 (patch) | |
tree | f15d5c34105c7e0cf484b6dbe08209c98e5085f0 | |
parent | d1dd72a2c576ff5acc4a7b219570ecc8338e3469 (diff) |
FreeBSD: Avoid spurious EINTR in zvol_cdev_open
zvol_first_open can fail with EINTR if spa_namespace_lock is not held
and cannot be taken without waiting.
Apply the same logic that was done for zvol_geom_open to take
spa_namespace_lock if not already held on first open in zvol_cdev_open.
Reviewed-by: Matt Macy <[email protected]>
Reviewed-by: Alexander Motin <[email protected]>
Signed-off-by: Ryan Moeller <[email protected]>
Closes #11175
-rw-r--r-- | module/os/freebsd/zfs/zvol_os.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 14c43bbff..0fac3b44d 100644 --- a/module/os/freebsd/zfs/zvol_os.c +++ b/module/os/freebsd/zfs/zvol_os.c @@ -827,14 +827,30 @@ zvol_cdev_open(struct cdev *dev, int flags, int fmt, struct thread *td) struct zvol_state_dev *zsd; int err = 0; boolean_t drop_suspend = B_TRUE; + boolean_t drop_namespace = B_FALSE; +retry: rw_enter(&zvol_state_lock, ZVOL_RW_READER); zv = dev->si_drv2; 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); ASSERT3S(zv->zv_zso->zso_volmode, ==, ZFS_VOLMODE_DEV); @@ -895,7 +911,8 @@ zvol_cdev_open(struct cdev *dev, int flags, int fmt, struct thread *td) (zv->zv_flags & ZVOL_WRITTEN_TO) != 0) zil_async_to_sync(zv->zv_zilog, ZVOL_OBJ); } - + if (drop_namespace) + mutex_exit(&spa_namespace_lock); mutex_exit(&zv->zv_state_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); @@ -905,6 +922,8 @@ out_opened: if (zv->zv_open_count == 0) zvol_last_close(zv); out_locked: + if (drop_namespace) + mutex_exit(&spa_namespace_lock); mutex_exit(&zv->zv_state_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); |