mirror of https://gitee.com/openkylin/linux.git
s390/dasd: Fix locking issue when changing RO attribute
The function dasd_ro_store() calls set_disk_ro() to set the device in question read-only. Since set_disk_ro() might sleep, we can't call it while holding a lock. However, we also can't simply check if the device, block, and gdp references are valid before we call set_disk_ro() because an offline processing might have been started in the meanwhile which will destroy those references. In order to reliably call set_disk_ro() we have to ensure several things: - Still check validity of the mentioned references but additionally check if offline processing is running and bail out accordingly. Also, do this while holding the device lock. - To ensure that the block device is still safe after the lock, increase the open_count while still holding the device lock. Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
9de67725c8
commit
9f9d53e5bd
|
@ -761,6 +761,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct ccw_device *cdev = to_ccwdev(dev);
|
||||
struct dasd_device *device;
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
int rc;
|
||||
|
||||
|
@ -775,10 +776,22 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
|
|||
if (IS_ERR(device))
|
||||
return PTR_ERR(device);
|
||||
|
||||
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
|
||||
val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
|
||||
if (device->block && device->block->gdp)
|
||||
set_disk_ro(device->block->gdp, val);
|
||||
|
||||
if (!device->block || !device->block->gdp ||
|
||||
test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
|
||||
goto out;
|
||||
}
|
||||
/* Increase open_count to avoid losing the block device */
|
||||
atomic_inc(&device->block->open_count);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
|
||||
|
||||
set_disk_ro(device->block->gdp, val);
|
||||
atomic_dec(&device->block->open_count);
|
||||
|
||||
out:
|
||||
dasd_put_device(device);
|
||||
|
||||
return count;
|
||||
|
|
Loading…
Reference in New Issue