]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
md: don't report active array_state until after revalidate_disk() completes.
authorNeilBrown <neilb@suse.com>
Tue, 20 Aug 2019 00:21:09 +0000 (10:21 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 5 Oct 2019 11:14:15 +0000 (13:14 +0200)
commit 9d4b45d6af442237560d0bb5502a012baa5234b7 upstream.

Until revalidate_disk() has completed, the size of a new md array will
appear to be zero.
So we shouldn't report, through array_state, that the array is active
until that time.
udev rules check array_state to see if the array is ready.  As soon as
it appear to be zero, fsck can be run.  If it find the size to be
zero, it will fail.

So add a new flag to provide an interlock between do_md_run() and
array_state_show().  This flag is set while do_md_run() is active and
it prevents array_state_show() from reporting that the array is
active.

Before do_md_run() is called, ->pers will be NULL so array is
definitely not active.
After do_md_run() is called, revalidate_disk() will have run and the
array will be completely ready.

We also move various sysfs_notify*() calls out of md_run() into
do_md_run() after MD_NOT_READY is cleared.  This ensure the
information is ready before the notification is sent.

Prior to v4.12, array_state_show() was called with the
mddev->reconfig_mutex held, which provided exclusion with do_md_run().

Note that MD_NOT_READY cleared twice.  This is deliberate to cover
both success and error paths with minimal noise.

Fixes: b7b17c9b67e5 ("md: remove mddev_lock() from md_attr_show()")
Cc: stable@vger.kernel.org (v4.12++)
Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/md/md.c
drivers/md/md.h

index b3bfac5f2bdb6deb82136b48cef93771fa43e1fd..25223530f60270440b646e0a6d605551b2121bc9 100644 (file)
@@ -4105,7 +4105,7 @@ array_state_show(struct mddev *mddev, char *page)
 {
        enum array_state st = inactive;
 
-       if (mddev->pers)
+       if (mddev->pers && !test_bit(MD_NOT_READY, &mddev->flags))
                switch(mddev->ro) {
                case 1:
                        st = readonly;
@@ -5660,9 +5660,6 @@ int md_run(struct mddev *mddev)
                md_update_sb(mddev, 0);
 
        md_new_event(mddev);
-       sysfs_notify_dirent_safe(mddev->sysfs_state);
-       sysfs_notify_dirent_safe(mddev->sysfs_action);
-       sysfs_notify(&mddev->kobj, NULL, "degraded");
        return 0;
 
 abort:
@@ -5676,6 +5673,7 @@ static int do_md_run(struct mddev *mddev)
 {
        int err;
 
+       set_bit(MD_NOT_READY, &mddev->flags);
        err = md_run(mddev);
        if (err)
                goto out;
@@ -5696,9 +5694,14 @@ static int do_md_run(struct mddev *mddev)
 
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
+       clear_bit(MD_NOT_READY, &mddev->flags);
        mddev->changed = 1;
        kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
+       sysfs_notify_dirent_safe(mddev->sysfs_state);
+       sysfs_notify_dirent_safe(mddev->sysfs_action);
+       sysfs_notify(&mddev->kobj, NULL, "degraded");
 out:
+       clear_bit(MD_NOT_READY, &mddev->flags);
        return err;
 }
 
index 7c930c0911932f5c594195f4d471ab76b0a73df8..6ad1f93a8c17e6f4470773e9f80667b7104f0952 100644 (file)
@@ -236,6 +236,9 @@ enum mddev_flags {
        MD_UPDATING_SB,         /* md_check_recovery is updating the metadata
                                 * without explicitly holding reconfig_mutex.
                                 */
+       MD_NOT_READY,           /* do_md_run() is active, so 'array_state'
+                                * must not report that array is ready yet
+                                */
 };
 
 enum mddev_sb_flags {