Skip to content

Commit b0ee9b7

Browse files
committed
md: add legacy_async_del_gendisk mode
JIRA: https://issues.redhat.com/browse/RHEL-94433 JIRA: https://issues.redhat.com/browse/RHEL-20191 JIRA: https://issues.redhat.com/browse/RHEL-9656 commit 25db5f2 Author: Xiao Ni <xni@redhat.com> Date: Wed Aug 13 11:29:29 2025 +0800 md: add legacy_async_del_gendisk mode commit 9e59d60 ("md: call del_gendisk in control path") changes the async way to sync way of calling del_gendisk. But it breaks mdadm --assemble command. The assemble command runs like this: 1. create the array 2. stop the array 3. access the sysfs files after stopping The sync way calls del_gendisk in step 2, so all sysfs files are removed. Now to avoid breaking mdadm assemble command, this patch adds the parameter legacy_async_del_gendisk that can be used to choose which way. The default is async way. In future, we plan to change default to sync way in kernel 7.0. Then users need to upgrade to mdadm 4.5+ which removes step 2. Fixes: 9e59d60 ("md: call del_gendisk in control path") Reported-by: Mikulas Patocka <mpatocka@redhat.com> Closes: https://lore.kernel.org/linux-raid/CAMw=ZnQ=ET2St-+hnhsuq34rRPnebqcXqP1QqaHW5Bh4aaaZ4g@mail.gmail.com/T/#t Suggested-and-reviewed-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Xiao Ni <xni@redhat.com> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de> Link: https://lore.kernel.org/linux-raid/20250813032929.54978-1-xni@redhat.com Signed-off-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Nigel Croxon <ncroxon@redhat.com>
1 parent 3dc6645 commit b0ee9b7

File tree

1 file changed

+42
-14
lines changed

1 file changed

+42
-14
lines changed

drivers/md/md.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ static int start_readonly;
340340
* so all the races disappear.
341341
*/
342342
static bool create_on_open = true;
343+
static bool legacy_async_del_gendisk = true;
343344

344345
/*
345346
* We have a system wide 'event count' that is incremented
@@ -878,15 +879,18 @@ void mddev_unlock(struct mddev *mddev)
878879
export_rdev(rdev, mddev);
879880
}
880881

881-
/* Call del_gendisk after release reconfig_mutex to avoid
882-
* deadlock (e.g. call del_gendisk under the lock and an
883-
* access to sysfs files waits the lock)
884-
* And MD_DELETED is only used for md raid which is set in
885-
* do_md_stop. dm raid only uses md_stop to stop. So dm raid
886-
* doesn't need to check MD_DELETED when getting reconfig lock
887-
*/
888-
if (test_bit(MD_DELETED, &mddev->flags))
889-
del_gendisk(mddev->gendisk);
882+
if (!legacy_async_del_gendisk) {
883+
/*
884+
* Call del_gendisk after release reconfig_mutex to avoid
885+
* deadlock (e.g. call del_gendisk under the lock and an
886+
* access to sysfs files waits the lock)
887+
* And MD_DELETED is only used for md raid which is set in
888+
* do_md_stop. dm raid only uses md_stop to stop. So dm raid
889+
* doesn't need to check MD_DELETED when getting reconfig lock
890+
*/
891+
if (test_bit(MD_DELETED, &mddev->flags))
892+
del_gendisk(mddev->gendisk);
893+
}
890894
}
891895
EXPORT_SYMBOL_GPL(mddev_unlock);
892896

@@ -5844,6 +5848,13 @@ static void md_kobj_release(struct kobject *ko)
58445848
{
58455849
struct mddev *mddev = container_of(ko, struct mddev, kobj);
58465850

5851+
if (legacy_async_del_gendisk) {
5852+
if (mddev->sysfs_state)
5853+
sysfs_put(mddev->sysfs_state);
5854+
if (mddev->sysfs_level)
5855+
sysfs_put(mddev->sysfs_level);
5856+
del_gendisk(mddev->gendisk);
5857+
}
58475858
put_disk(mddev->gendisk);
58485859
}
58495860

@@ -6047,6 +6058,9 @@ static int md_alloc_and_put(dev_t dev, char *name)
60476058
{
60486059
struct mddev *mddev = md_alloc(dev, name);
60496060

6061+
if (legacy_async_del_gendisk)
6062+
pr_warn("md: async del_gendisk mode will be removed in future, please upgrade to mdadm-4.5+\n");
6063+
60506064
if (IS_ERR(mddev))
60516065
return PTR_ERR(mddev);
60526066
mddev_put(mddev);
@@ -6457,10 +6471,22 @@ static void md_clean(struct mddev *mddev)
64576471
mddev->persistent = 0;
64586472
mddev->level = LEVEL_NONE;
64596473
mddev->clevel[0] = 0;
6460-
/* if UNTIL_STOP is set, it's cleared here */
6461-
mddev->hold_active = 0;
6462-
/* Don't clear MD_CLOSING, or mddev can be opened again. */
6463-
mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
6474+
6475+
/*
6476+
* For legacy_async_del_gendisk mode, it can stop the array in the
6477+
* middle of assembling it, then it still can access the array. So
6478+
* it needs to clear MD_CLOSING. If not legacy_async_del_gendisk,
6479+
* it can't open the array again after stopping it. So it doesn't
6480+
* clear MD_CLOSING.
6481+
*/
6482+
if (legacy_async_del_gendisk && mddev->hold_active) {
6483+
clear_bit(MD_CLOSING, &mddev->flags);
6484+
} else {
6485+
/* if UNTIL_STOP is set, it's cleared here */
6486+
mddev->hold_active = 0;
6487+
/* Don't clear MD_CLOSING, or mddev can be opened again. */
6488+
mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
6489+
}
64646490
mddev->sb_flags = 0;
64656491
mddev->ro = MD_RDWR;
64666492
mddev->metadata_type[0] = 0;
@@ -6684,7 +6710,8 @@ static int do_md_stop(struct mddev *mddev, int mode)
66846710

66856711
export_array(mddev);
66866712
md_clean(mddev);
6687-
set_bit(MD_DELETED, &mddev->flags);
6713+
if (!legacy_async_del_gendisk)
6714+
set_bit(MD_DELETED, &mddev->flags);
66886715
}
66896716
md_new_event();
66906717
sysfs_notify_dirent_safe(mddev->sysfs_state);
@@ -10418,6 +10445,7 @@ module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
1041810445
module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
1041910446
module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
1042010447
module_param(create_on_open, bool, S_IRUSR|S_IWUSR);
10448+
module_param(legacy_async_del_gendisk, bool, 0600);
1042110449

1042210450
MODULE_LICENSE("GPL");
1042310451
MODULE_DESCRIPTION("MD RAID framework");

0 commit comments

Comments
 (0)