summaryrefslogtreecommitdiffstats
path: root/module/zfs/zvol.c
diff options
context:
space:
mode:
authorBoris Protopopov <[email protected]>2017-08-09 14:10:47 -0400
committerBrian Behlendorf <[email protected]>2017-08-09 11:10:47 -0700
commit5146d802b4e371cab1d6db79bea482c056be7bf2 (patch)
tree028280638f8fa27f3708553dba5d06e43a747c7e /module/zfs/zvol.c
parent520faf5ddcb1a9536f53438963d1c96678040466 (diff)
zv_suspend_lock in zvol_open()/zvol_release()
Acquire zv_suspend_lock on first open and last close only. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Boris Protopopov <[email protected]> Closes #6342
Diffstat (limited to 'module/zfs/zvol.c')
-rw-r--r--module/zfs/zvol.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 254760220..40fdf0777 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -1304,9 +1304,9 @@ zvol_open(struct block_device *bdev, fmode_t flag)
{
zvol_state_t *zv;
int error = 0;
- boolean_t drop_suspend = B_FALSE;
+ boolean_t drop_suspend = B_TRUE;
- ASSERT(!mutex_owned(&zvol_state_lock));
+ ASSERT(!MUTEX_HELD(&zvol_state_lock));
mutex_enter(&zvol_state_lock);
/*
@@ -1321,23 +1321,31 @@ zvol_open(struct block_device *bdev, fmode_t flag)
return (SET_ERROR(-ENXIO));
}
- /* take zv_suspend_lock before zv_state_lock */
- rw_enter(&zv->zv_suspend_lock, RW_READER);
-
mutex_enter(&zv->zv_state_lock);
-
/*
* make sure zvol is not suspended during first open
- * (hold zv_suspend_lock), otherwise, drop the lock
+ * (hold zv_suspend_lock) and respect proper lock acquisition
+ * ordering - zv_suspend_lock before zv_state_lock
*/
if (zv->zv_open_count == 0) {
- drop_suspend = B_TRUE;
+ if (!rw_tryenter(&zv->zv_suspend_lock, RW_READER)) {
+ mutex_exit(&zv->zv_state_lock);
+ rw_enter(&zv->zv_suspend_lock, RW_READER);
+ mutex_enter(&zv->zv_state_lock);
+ /* check to see if zv_suspend_lock is needed */
+ if (zv->zv_open_count != 0) {
+ rw_exit(&zv->zv_suspend_lock);
+ drop_suspend = B_FALSE;
+ }
+ }
} else {
- rw_exit(&zv->zv_suspend_lock);
+ drop_suspend = B_FALSE;
}
-
mutex_exit(&zvol_state_lock);
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
+ ASSERT(zv->zv_open_count != 0 || RW_READ_HELD(&zv->zv_suspend_lock));
+
if (zv->zv_open_count == 0) {
error = zvol_first_open(zv);
if (error)
@@ -1374,28 +1382,38 @@ static int
zvol_release(struct gendisk *disk, fmode_t mode)
{
zvol_state_t *zv;
- boolean_t drop_suspend = B_FALSE;
+ boolean_t drop_suspend = B_TRUE;
- ASSERT(!mutex_owned(&zvol_state_lock));
+ ASSERT(!MUTEX_HELD(&zvol_state_lock));
mutex_enter(&zvol_state_lock);
zv = disk->private_data;
- ASSERT(zv && zv->zv_open_count > 0);
-
- /* take zv_suspend_lock before zv_state_lock */
- rw_enter(&zv->zv_suspend_lock, RW_READER);
mutex_enter(&zv->zv_state_lock);
- mutex_exit(&zvol_state_lock);
-
+ ASSERT(zv->zv_open_count > 0);
/*
* make sure zvol is not suspended during last close
- * (hold zv_suspend_lock), otherwise, drop the lock
+ * (hold zv_suspend_lock) and respect proper lock acquisition
+ * ordering - zv_suspend_lock before zv_state_lock
*/
- if (zv->zv_open_count == 1)
- drop_suspend = B_TRUE;
- else
- rw_exit(&zv->zv_suspend_lock);
+ if (zv->zv_open_count == 1) {
+ if (!rw_tryenter(&zv->zv_suspend_lock, RW_READER)) {
+ mutex_exit(&zv->zv_state_lock);
+ rw_enter(&zv->zv_suspend_lock, RW_READER);
+ mutex_enter(&zv->zv_state_lock);
+ /* check to see if zv_suspend_lock is needed */
+ if (zv->zv_open_count != 1) {
+ rw_exit(&zv->zv_suspend_lock);
+ drop_suspend = B_FALSE;
+ }
+ }
+ } else {
+ drop_suspend = B_FALSE;
+ }
+ mutex_exit(&zvol_state_lock);
+
+ ASSERT(MUTEX_HELD(&zv->zv_state_lock));
+ ASSERT(zv->zv_open_count != 1 || RW_READ_HELD(&zv->zv_suspend_lock));
zv->zv_open_count--;
if (zv->zv_open_count == 0)