Skip to content

Commit 4934b64

Browse files
YuKuai-huaweiliu-song-6
authored andcommitted
md: fix 'delete_mutex' deadlock
Commit 3ce94ce ("md: fix duplicate filename for rdev") introduce a new lock 'delete_mutex', and trigger a new deadlock: t1: remove rdev t2: sysfs writer rdev_attr_store rdev_attr_store mddev_lock state_store md_kick_rdev_from_array lock delete_mutex list_add mddev->deleting unlock delete_mutex mddev_unlock mddev_lock ... lock delete_mutex kobject_del // wait for sysfs writers to be done mddev_unlock lock delete_mutex // wait for delete_mutex, deadlock 'delete_mutex' is used to protect the list 'mddev->deleting', turns out that this list can be protected by 'reconfig_mutex' directly, and this lock can be removed. Fix this problem by removing the lock, and use 'reconfig_mutex' to protect the list. mddev_unlock() will move this list to a local list to be handled after 'reconfig_mutex' is dropped. Fixes: 3ce94ce ("md: fix duplicate filename for rdev") Signed-off-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/r/20230621142933.1395629-1-yukuai1@huaweicloud.com
1 parent a1d7671 commit 4934b64

2 files changed

Lines changed: 10 additions & 22 deletions

File tree

drivers/md/md.c

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,6 @@ void mddev_init(struct mddev *mddev)
643643
{
644644
mutex_init(&mddev->open_mutex);
645645
mutex_init(&mddev->reconfig_mutex);
646-
mutex_init(&mddev->delete_mutex);
647646
mutex_init(&mddev->bitmap_info.mutex);
648647
INIT_LIST_HEAD(&mddev->disks);
649648
INIT_LIST_HEAD(&mddev->all_mddevs);
@@ -749,26 +748,15 @@ static void mddev_free(struct mddev *mddev)
749748

750749
static const struct attribute_group md_redundancy_group;
751750

752-
static void md_free_rdev(struct mddev *mddev)
751+
void mddev_unlock(struct mddev *mddev)
753752
{
754753
struct md_rdev *rdev;
755754
struct md_rdev *tmp;
755+
LIST_HEAD(delete);
756756

757-
mutex_lock(&mddev->delete_mutex);
758-
if (list_empty(&mddev->deleting))
759-
goto out;
757+
if (!list_empty(&mddev->deleting))
758+
list_splice_init(&mddev->deleting, &delete);
760759

761-
list_for_each_entry_safe(rdev, tmp, &mddev->deleting, same_set) {
762-
list_del_init(&rdev->same_set);
763-
kobject_del(&rdev->kobj);
764-
export_rdev(rdev, mddev);
765-
}
766-
out:
767-
mutex_unlock(&mddev->delete_mutex);
768-
}
769-
770-
void mddev_unlock(struct mddev *mddev)
771-
{
772760
if (mddev->to_remove) {
773761
/* These cannot be removed under reconfig_mutex as
774762
* an access to the files will try to take reconfig_mutex
@@ -808,7 +796,11 @@ void mddev_unlock(struct mddev *mddev)
808796
} else
809797
mutex_unlock(&mddev->reconfig_mutex);
810798

811-
md_free_rdev(mddev);
799+
list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
800+
list_del_init(&rdev->same_set);
801+
kobject_del(&rdev->kobj);
802+
export_rdev(rdev, mddev);
803+
}
812804

813805
md_wakeup_thread(mddev->thread);
814806
wake_up(&mddev->sb_wait);
@@ -2488,9 +2480,7 @@ static void md_kick_rdev_from_array(struct md_rdev *rdev)
24882480
* reconfig_mutex is held, hence it can't be called under
24892481
* reconfig_mutex and it's delayed to mddev_unlock().
24902482
*/
2491-
mutex_lock(&mddev->delete_mutex);
24922483
list_add(&rdev->same_set, &mddev->deleting);
2493-
mutex_unlock(&mddev->delete_mutex);
24942484
}
24952485

24962486
static void export_array(struct mddev *mddev)

drivers/md/md.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,11 +531,9 @@ struct mddev {
531531

532532
/*
533533
* Temporarily store rdev that will be finally removed when
534-
* reconfig_mutex is unlocked.
534+
* reconfig_mutex is unlocked, protected by reconfig_mutex.
535535
*/
536536
struct list_head deleting;
537-
/* Protect the deleting list */
538-
struct mutex delete_mutex;
539537

540538
bool has_superblocks:1;
541539
bool fail_last_dev:1;

0 commit comments

Comments
 (0)