zv_suspend_lock in zvol_open()/zvol_release()

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
This commit is contained in:
Boris Protopopov 2017-08-09 14:10:47 -04:00 committed by Tony Hutter
parent d1ed1be3cd
commit 1667816089
1 changed files with 41 additions and 23 deletions

View File

@ -1347,9 +1347,9 @@ zvol_open(struct block_device *bdev, fmode_t flag)
{ {
zvol_state_t *zv; zvol_state_t *zv;
int error = 0; 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); mutex_enter(&zvol_state_lock);
/* /*
@ -1364,23 +1364,31 @@ zvol_open(struct block_device *bdev, fmode_t flag)
return (SET_ERROR(-ENXIO)); 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); mutex_enter(&zv->zv_state_lock);
/* /*
* make sure zvol is not suspended during first open * 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) { 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 { } else {
rw_exit(&zv->zv_suspend_lock); drop_suspend = B_FALSE;
} }
mutex_exit(&zvol_state_lock); 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) { if (zv->zv_open_count == 0) {
error = zvol_first_open(zv); error = zvol_first_open(zv);
if (error) if (error)
@ -1417,28 +1425,38 @@ static int
zvol_release(struct gendisk *disk, fmode_t mode) zvol_release(struct gendisk *disk, fmode_t mode)
{ {
zvol_state_t *zv; 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); mutex_enter(&zvol_state_lock);
zv = disk->private_data; 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_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 * 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) if (zv->zv_open_count == 1) {
drop_suspend = B_TRUE; if (!rw_tryenter(&zv->zv_suspend_lock, RW_READER)) {
else mutex_exit(&zv->zv_state_lock);
rw_exit(&zv->zv_suspend_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--; zv->zv_open_count--;
if (zv->zv_open_count == 0) if (zv->zv_open_count == 0)