]> granicus.if.org Git - zfs/commitdiff
zv_suspend_lock in zvol_open()/zvol_release()
authorBoris Protopopov <bprotopopov@users.noreply.github.com>
Wed, 9 Aug 2017 18:10:47 +0000 (14:10 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 9 Aug 2017 18:10:47 +0000 (11:10 -0700)
Acquire zv_suspend_lock on first open and last close only.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Boris Protopopov <boris.protopopov@actifio.com>
Closes #6342

module/zfs/zvol.c

index 2547602204c03ab00bf384f9a68842dd23164058..40fdf077726c529a5d461d89143bd5172a8a37bf 100644 (file)
@@ -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)