Skip to content

Commit cc1ffe6

Browse files
Guoqing Jiangliu-song-6
authored andcommitted
md: add new workqueue for delete rdev
Since the purpose of call flush_workqueue in new_dev_store is to ensure md_delayed_delete() has completed, so we should check rdev->del_work is pending or not. To suppress lockdep warning, we have to check mddev->del_work while md_delayed_delete is attached to rdev->del_work, so it is not aligned to the purpose of flush workquee. So a new workqueue is needed to avoid the awkward situation, and introduce a new func flush_rdev_wq to flush the new workqueue after check if there was pending work. Also like new_dev_store, ADD_NEW_DISK ioctl has the same purpose to flush workqueue while it holds bdev->bd_mutex, so make the same change applies to the ioctl to avoid similar lock issue. And md_delayed_delete actually wants to delete rdev, so rename the function to rdev_delayed_delete. Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com> Signed-off-by: Song Liu <songliubraving@fb.com>
1 parent 21e0958 commit cc1ffe6

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

drivers/md/md.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static struct module *md_cluster_mod;
8989
static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
9090
static struct workqueue_struct *md_wq;
9191
static struct workqueue_struct *md_misc_wq;
92+
static struct workqueue_struct *md_rdev_misc_wq;
9293

9394
static int remove_and_add_spares(struct mddev *mddev,
9495
struct md_rdev *this);
@@ -2454,7 +2455,7 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
24542455
return err;
24552456
}
24562457

2457-
static void md_delayed_delete(struct work_struct *ws)
2458+
static void rdev_delayed_delete(struct work_struct *ws)
24582459
{
24592460
struct md_rdev *rdev = container_of(ws, struct md_rdev, del_work);
24602461
kobject_del(&rdev->kobj);
@@ -2479,9 +2480,9 @@ static void unbind_rdev_from_array(struct md_rdev *rdev)
24792480
* to delay it due to rcu usage.
24802481
*/
24812482
synchronize_rcu();
2482-
INIT_WORK(&rdev->del_work, md_delayed_delete);
2483+
INIT_WORK(&rdev->del_work, rdev_delayed_delete);
24832484
kobject_get(&rdev->kobj);
2484-
queue_work(md_misc_wq, &rdev->del_work);
2485+
queue_work(md_rdev_misc_wq, &rdev->del_work);
24852486
}
24862487

24872488
/*
@@ -4514,6 +4515,20 @@ null_show(struct mddev *mddev, char *page)
45144515
return -EINVAL;
45154516
}
45164517

4518+
/* need to ensure rdev_delayed_delete() has completed */
4519+
static void flush_rdev_wq(struct mddev *mddev)
4520+
{
4521+
struct md_rdev *rdev;
4522+
4523+
rcu_read_lock();
4524+
rdev_for_each_rcu(rdev, mddev)
4525+
if (work_pending(&rdev->del_work)) {
4526+
flush_workqueue(md_rdev_misc_wq);
4527+
break;
4528+
}
4529+
rcu_read_unlock();
4530+
}
4531+
45174532
static ssize_t
45184533
new_dev_store(struct mddev *mddev, const char *buf, size_t len)
45194534
{
@@ -4541,8 +4556,7 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len)
45414556
minor != MINOR(dev))
45424557
return -EOVERFLOW;
45434558

4544-
flush_workqueue(md_misc_wq);
4545-
4559+
flush_rdev_wq(mddev);
45464560
err = mddev_lock(mddev);
45474561
if (err)
45484562
return err;
@@ -4780,7 +4794,8 @@ action_store(struct mddev *mddev, const char *page, size_t len)
47804794
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
47814795
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
47824796
mddev_lock(mddev) == 0) {
4783-
flush_workqueue(md_misc_wq);
4797+
if (work_pending(&mddev->del_work))
4798+
flush_workqueue(md_misc_wq);
47844799
if (mddev->sync_thread) {
47854800
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
47864801
md_reap_sync_thread(mddev);
@@ -7498,8 +7513,7 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
74987513
}
74997514

75007515
if (cmd == ADD_NEW_DISK)
7501-
/* need to ensure md_delayed_delete() has completed */
7502-
flush_workqueue(md_misc_wq);
7516+
flush_rdev_wq(mddev);
75037517

75047518
if (cmd == HOT_REMOVE_DISK)
75057519
/* need to ensure recovery thread has run */
@@ -9471,6 +9485,10 @@ static int __init md_init(void)
94719485
if (!md_misc_wq)
94729486
goto err_misc_wq;
94739487

9488+
md_rdev_misc_wq = alloc_workqueue("md_rdev_misc", 0, 0);
9489+
if (!md_misc_wq)
9490+
goto err_rdev_misc_wq;
9491+
94749492
if ((ret = register_blkdev(MD_MAJOR, "md")) < 0)
94759493
goto err_md;
94769494

@@ -9492,6 +9510,8 @@ static int __init md_init(void)
94929510
err_mdp:
94939511
unregister_blkdev(MD_MAJOR, "md");
94949512
err_md:
9513+
destroy_workqueue(md_rdev_misc_wq);
9514+
err_rdev_misc_wq:
94959515
destroy_workqueue(md_misc_wq);
94969516
err_misc_wq:
94979517
destroy_workqueue(md_wq);
@@ -9778,6 +9798,7 @@ static __exit void md_exit(void)
97789798
* destroy_workqueue() below will wait for that to complete.
97799799
*/
97809800
}
9801+
destroy_workqueue(md_rdev_misc_wq);
97819802
destroy_workqueue(md_misc_wq);
97829803
destroy_workqueue(md_wq);
97839804
}

0 commit comments

Comments
 (0)