Skip to content

Commit 1378a68

Browse files
gerald-schaeferMartin Schwidefsky
authored andcommitted
s390/dcssblk: fix possible deadlock in remove vs. per-device attributes
dcssblk_remove_store() holds the dcssblk_devices_sem semaphore while calling device_unregister(), which in turn tries to acquire the kernfs kn->dev_map rwsem for the device sysfs subtree. The same rwsem is also acquired when using the per-device sysfs attributes in the device sub-tree, and the attribute handlers then also acquire the dcssblk_devices_sem. This can lead to a deadlock when removing a DCSS while concurrently reading from / writing to one of its sysfs attributes. The following lockdep warning hinted towards the issue (CPU0 = dcssblk_remove_store, CPU1 = dcssblk_shared_store): [ 76.496047] Possible unsafe locking scenario: [ 76.496054] CPU0 CPU1 [ 76.496059] ---- ---- [ 76.496087] lock(&dcssblk_devices_sem); [ 76.496090] lock(s_active#175); [ 76.496106] lock(&dcssblk_devices_sem); [ 76.496110] lock(s_active#175); [ 76.496115] *** DEADLOCK *** Fix this by releasing the dcssblk_devices_sem semaphore, which only protects internal DCSS data, before calling device_unregister(). Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
1 parent 4f37590 commit 1378a68

File tree

1 file changed

+3
-2
lines changed

1 file changed

+3
-2
lines changed

drivers/s390/block/dcssblk.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,15 +756,16 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
756756
blk_cleanup_queue(dev_info->dcssblk_queue);
757757
dev_info->gd->queue = NULL;
758758
put_disk(dev_info->gd);
759-
device_unregister(&dev_info->dev);
760759

761760
/* unload all related segments */
762761
list_for_each_entry(entry, &dev_info->seg_list, lh)
763762
segment_unload(entry->segment_name);
764763

765-
put_device(&dev_info->dev);
766764
up_write(&dcssblk_devices_sem);
767765

766+
device_unregister(&dev_info->dev);
767+
put_device(&dev_info->dev);
768+
768769
rc = count;
769770
out_buf:
770771
kfree(local_buf);

0 commit comments

Comments
 (0)