aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@linux.ibm.com>2023-08-22 17:19:32 +0200
committerHeiko Carstens <hca@linux.ibm.com>2023-08-30 11:03:27 +0200
commit789dd8cb1eb1503c8167bf2ffc88f74a70245044 (patch)
treed6cc979765895a8d733be2fa91051da764d70afc /drivers/s390
parent67ce50ce01d8abfa36612bcef9ec56e37b9fc247 (diff)
downloadlinux-789dd8cb1eb1503c8167bf2ffc88f74a70245044.tar.gz
s390/dcssblk: fix lockdep warning
dcssblk_remove_store() holds the dcssblk_devices_sem semaphore while calling del_gendisk(dev_info->gd), which in turn tries to acquire disk->open_mutex. Then there is dcssblk_release(), which is called with disk->open_mutex held, and tries to acquire dcssblk_devices_sem. Lockdep reports this as possible circular locking dependency (CPU0 = dcssblk_remove_store, CPU1 = dcssblk_release): [ 44.948865] Possible unsafe locking scenario: [ 44.948866] CPU0 CPU1 [ 44.948867] ---- ---- [ 44.948868] lock(&dcssblk_devices_sem); [ 44.948870] lock(&disk->open_mutex); [ 44.948872] lock(&dcssblk_devices_sem); [ 44.948874] lock(&disk->open_mutex); [ 44.948876] *** DEADLOCK *** In practice, this deadlock should not happen, since dcssblk_remove_store() checks for dev_info->use_count != 0 after acquiring dcssblk_devices_sem, and breaks out before calling del_gendisk(). dev_info->use_count will be decremented in dcssblk_release(), protected by dcssblk_devices_sem. Still there is no need for dcssblk_remove_store() to hold the dcssblk_devices_sem until after calling del_gendisk(), as this only protects dcssblk internal data. So fix the lockdep warning by releasing dcssblk_devices_sem earlier. Also move the segment_unload() loop up, similar to dcssblk_shared_store() error path, no need to do that after calling del_gendisk(). Also change dcssblk_shared_store() error path, where dcssblk_devices_sem was also released only after calling del_gendisk(), and a similar lockdep warning could be triggered (but also deadlock prevented by check for dev_info->use_count). Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dcssblk.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 06bcb6c7890931..4b7ecd4fd4319c 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -411,13 +411,13 @@ removeseg:
segment_unload(entry->segment_name);
}
list_del(&dev_info->lh);
+ up_write(&dcssblk_devices_sem);
dax_remove_host(dev_info->gd);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
put_disk(dev_info->gd);
- up_write(&dcssblk_devices_sem);
if (device_remove_file_self(dev, attr)) {
device_unregister(dev);
@@ -790,18 +790,17 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
}
list_del(&dev_info->lh);
+ /* unload all related segments */
+ list_for_each_entry(entry, &dev_info->seg_list, lh)
+ segment_unload(entry->segment_name);
+ up_write(&dcssblk_devices_sem);
+
dax_remove_host(dev_info->gd);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
put_disk(dev_info->gd);
- /* unload all related segments */
- list_for_each_entry(entry, &dev_info->seg_list, lh)
- segment_unload(entry->segment_name);
-
- up_write(&dcssblk_devices_sem);
-
device_unregister(&dev_info->dev);
put_device(&dev_info->dev);