]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdadm: Introduce new array state 'broken' for raid0/linear
authorGuilherme G. Piccoli <gpiccoli@canonical.com>
Tue, 3 Sep 2019 19:49:01 +0000 (16:49 -0300)
committerJes Sorensen <jsorensen@fb.com>
Mon, 30 Sep 2019 19:08:09 +0000 (15:08 -0400)
Currently if a md raid0/linear array gets one or more members removed while
being mounted, kernel keeps showing state 'clean' in the 'array_state'
sysfs attribute. Despite udev signaling the member device is gone, 'mdadm'
cannot issue the STOP_ARRAY ioctl successfully, given the array is mounted.

Nothing else hints that something is wrong (except that the removed devices
don't show properly in the output of mdadm 'detail' command). There is no
other property to be checked, and if user is not performing reads/writes
to the array, even kernel log is quiet and doesn't give a clue about the
missing member.

This patch is the mdadm counterpart of kernel new array state 'broken'.
The 'broken' state mimics the state 'clean' in every aspect, being useful
only to distinguish if an array has some member missing. All necessary
paths in mdadm were changed to deal with 'broken' state, and in case the
tool runs in a kernel that is not updated, it'll work normally, i.e., it
doesn't require the 'broken' state in order to work.
Also, this patch changes the way the array state is showed in the 'detail'
command (for raid0/linear only) - now it takes the 'array_state' sysfs
attribute into account instead of only rely in the MD_SB_CLEAN flag.

Cc: Jes Sorensen <jes.sorensen@gmail.com>
Cc: NeilBrown <neilb@suse.de>
Cc: Song Liu <songliubraving@fb.com>
Signed-off-by: Guilherme G. Piccoli <gpiccoli@canonical.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
Detail.c
Monitor.c
maps.c
mdadm.h
mdmon.h
monitor.c

index ad60434f0aaeedbff681dc8622843fe9c390d724..3e61e372fe9f16b6c1897afb693dd016ec3f516a 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -81,6 +81,7 @@ int Detail(char *dev, struct context *c)
        int external;
        int inactive;
        int is_container = 0;
        int external;
        int inactive;
        int is_container = 0;
+       char *arrayst;
 
        if (fd < 0) {
                pr_err("cannot open %s: %s\n",
 
        if (fd < 0) {
                pr_err("cannot open %s: %s\n",
@@ -485,9 +486,18 @@ int Detail(char *dev, struct context *c)
                        else
                                st = ", degraded";
 
                        else
                                st = ", degraded";
 
+                       if (array.state & (1 << MD_SB_CLEAN)) {
+                               if ((array.level == 0) ||
+                                   (array.level == LEVEL_LINEAR))
+                                       arrayst = map_num(sysfs_array_states,
+                                                         sra->array_state);
+                               else
+                                       arrayst = "clean";
+                       } else
+                               arrayst = "active";
+
                        printf("             State : %s%s%s%s%s%s \n",
                        printf("             State : %s%s%s%s%s%s \n",
-                              (array.state & (1 << MD_SB_CLEAN)) ?
-                              "clean" : "active", st,
+                              arrayst, st,
                               (!e || (e->percent < 0 &&
                                       e->percent != RESYNC_PENDING &&
                                       e->percent != RESYNC_DELAYED)) ?
                               (!e || (e->percent < 0 &&
                                       e->percent != RESYNC_PENDING &&
                                       e->percent != RESYNC_DELAYED)) ?
index 036103fb0f6bd94c2856a8eaed5c88b9e91d28b4..b527165b803acc2eb3a9d84132f44a39f64aeba1 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -1055,8 +1055,11 @@ int Wait(char *dev)
        }
 }
 
        }
 }
 
+/* The state "broken" is used only for RAID0/LINEAR - it's the same as
+ * "clean", but used in case the array has one or more members missing.
+ */
 static char *clean_states[] = {
 static char *clean_states[] = {
-       "clear", "inactive", "readonly", "read-auto", "clean", NULL };
+       "clear", "inactive", "readonly", "read-auto", "clean", "broken", NULL };
 
 int WaitClean(char *dev, int verbose)
 {
 
 int WaitClean(char *dev, int verbose)
 {
@@ -1116,7 +1119,8 @@ int WaitClean(char *dev, int verbose)
                        rv = read(state_fd, buf, sizeof(buf));
                        if (rv < 0)
                                break;
                        rv = read(state_fd, buf, sizeof(buf));
                        if (rv < 0)
                                break;
-                       if (sysfs_match_word(buf, clean_states) <= 4)
+                       if (sysfs_match_word(buf, clean_states) <
+                           (int)ARRAY_SIZE(clean_states) - 1)
                                break;
                        rv = sysfs_wait(state_fd, &delay);
                        if (rv < 0 && errno != EINTR)
                                break;
                        rv = sysfs_wait(state_fd, &delay);
                        if (rv < 0 && errno != EINTR)
diff --git a/maps.c b/maps.c
index 02a047422fb25257e969a74c8bf3a6f51eedb251..49b7f2c2d274bdd4143fc09193df61dbf202d2eb 100644 (file)
--- a/maps.c
+++ b/maps.c
@@ -150,6 +150,7 @@ mapping_t sysfs_array_states[] = {
        { "read-auto", ARRAY_READ_AUTO },
        { "clean", ARRAY_CLEAN },
        { "write-pending", ARRAY_WRITE_PENDING },
        { "read-auto", ARRAY_READ_AUTO },
        { "clean", ARRAY_CLEAN },
        { "write-pending", ARRAY_WRITE_PENDING },
+       { "broken", ARRAY_BROKEN },
        { NULL, ARRAY_UNKNOWN_STATE }
 };
 
        { NULL, ARRAY_UNKNOWN_STATE }
 };
 
diff --git a/mdadm.h b/mdadm.h
index 43b07d574c86f66c11a819dd623016e14b7a1df8..c88ceab01875efef7da1c5ad99b030412d2cd7e6 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -373,6 +373,7 @@ struct mdinfo {
                ARRAY_ACTIVE,
                ARRAY_WRITE_PENDING,
                ARRAY_ACTIVE_IDLE,
                ARRAY_ACTIVE,
                ARRAY_WRITE_PENDING,
                ARRAY_ACTIVE_IDLE,
+               ARRAY_BROKEN,
                ARRAY_UNKNOWN_STATE,
        } array_state;
        struct md_bb bb;
                ARRAY_UNKNOWN_STATE,
        } array_state;
        struct md_bb bb;
diff --git a/mdmon.h b/mdmon.h
index 818367cbb14c95755d8384702abcc155d41d0e96..b3d72ac37b67f186c87ab1849b7693b6b924a936 100644 (file)
--- a/mdmon.h
+++ b/mdmon.h
@@ -21,7 +21,7 @@
 extern const char Name[];
 
 enum array_state { clear, inactive, suspended, readonly, read_auto,
 extern const char Name[];
 
 enum array_state { clear, inactive, suspended, readonly, read_auto,
-                  clean, active, write_pending, active_idle, bad_word};
+                  clean, active, write_pending, active_idle, broken, bad_word};
 
 enum sync_action { idle, reshape, resync, recover, check, repair, bad_action };
 
 
 enum sync_action { idle, reshape, resync, recover, check, repair, bad_action };
 
index 81537ed37300159c6d260e68c0d9798fca01c446..e0d3be679daf25324db8e0672da16802c9c46b43 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -26,7 +26,7 @@
 
 static char *array_states[] = {
        "clear", "inactive", "suspended", "readonly", "read-auto",
 
 static char *array_states[] = {
        "clear", "inactive", "suspended", "readonly", "read-auto",
-       "clean", "active", "write-pending", "active-idle", NULL };
+       "clean", "active", "write-pending", "active-idle", "broken", NULL };
 static char *sync_actions[] = {
        "idle", "reshape", "resync", "recover", "check", "repair", NULL
 };
 static char *sync_actions[] = {
        "idle", "reshape", "resync", "recover", "check", "repair", NULL
 };
@@ -476,7 +476,7 @@ static int read_and_act(struct active_array *a, fd_set *fds)
                a->next_state = clean;
                ret |= ARRAY_DIRTY;
        }
                a->next_state = clean;
                ret |= ARRAY_DIRTY;
        }
-       if (a->curr_state == clean) {
+       if ((a->curr_state == clean) || (a->curr_state == broken)) {
                a->container->ss->set_array_state(a, 1);
        }
        if (a->curr_state == active ||
                a->container->ss->set_array_state(a, 1);
        }
        if (a->curr_state == active ||