]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
FIX: Mdmon crashes after changing RAID level from 1 to 0
authorLukasz Dorau <lukasz.dorau@intel.com>
Thu, 1 Sep 2011 13:10:34 +0000 (15:10 +0200)
committerNeilBrown <neilb@suse.de>
Tue, 6 Sep 2011 05:19:58 +0000 (15:19 +1000)
Description of the bug:
Sometimes mdmon crashes after changing RAID level from 1 to 0 (takeover).

Cause of the bug:
The managemon marks an active_array for removal from monitoring
by assigning a->container to NULL value (in the "manage_member" function).
Sometimes (during stress test) it happens right when the monitor
is in the "read_and_act" function and a->container pointer is in use.
This causes the monitor crashes.

Solution:
The active array has to be marked for removal in another way
than setting NULL pointer when it can be in use.
A new field "to_remove" was added to the "active_array" structure.
It is used in the managemon to mark a container to remove
(instead of the old assigment: a->container = NULL)
and monitor checks it to determine if the array should be removed.
The field "to_remove" should be checked in some other places
to avoid managing of the array which is going to be removed.

Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
managemon.c
mdmon.h
monitor.c

index d020f82d35d2c630a5ac9ce38b5116c0117bf05f..9e0a34d758509b0d00b1a9f6634fab97c974d2e2 100644 (file)
@@ -461,7 +461,7 @@ static void manage_member(struct mdstat_ent *mdstat,
        if (mdstat->level) {
                int level = map_name(pers, mdstat->level);
                if (level == 0 || level == LEVEL_LINEAR) {
-                       a->container = NULL;
+                       a->to_remove = 1;
                        wakeup_monitor();
                        return;
                }
@@ -739,7 +739,7 @@ void manage(struct mdstat_ent *mdstat, struct supertype *container)
                /* Looks like a member of this container */
                for (a = container->arrays; a; a = a->next) {
                        if (mdstat->devnum == a->devnum) {
-                               if (a->container)
+                               if (a->container && a->to_remove == 0)
                                        manage_member(mdstat, a);
                                break;
                        }
diff --git a/mdmon.h b/mdmon.h
index 6d1776f9281e5ab6e0a47ed29ed416ed2d483328..59e1b537f620cf4cd4a64fa5b30f179d0e5c2cc9 100644 (file)
--- a/mdmon.h
+++ b/mdmon.h
@@ -28,6 +28,7 @@ struct active_array {
        struct mdinfo info;
        struct supertype *container;
        struct active_array *next, *replaces;
+       int to_remove;
 
        int action_fd;
        int resync_start_fd;
index 7ac59072144ca5c309625e52a74bfb433a408667..b002e90f757b025470cfb0491d22ee25517d54b2 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -479,7 +479,7 @@ static void reconcile_failed(struct active_array *aa, struct mdinfo *failed)
        struct mdinfo *victim;
 
        for (a = aa; a; a = a->next) {
-               if (!a->container)
+               if (!a->container || a->to_remove)
                        continue;
                victim = find_device(a, failed->disk.major, failed->disk.minor);
                if (!victim)
@@ -539,7 +539,7 @@ static int wait_and_act(struct supertype *container, int nowait)
                /* once an array has been deactivated we want to
                 * ask the manager to discard it.
                 */
-               if (!a->container) {
+               if (!a->container || a->to_remove) {
                        if (discard_this) {
                                ap = &(*ap)->next;
                                continue;
@@ -642,7 +642,7 @@ static int wait_and_act(struct supertype *container, int nowait)
                        /* FIXME check if device->state_fd need to be cleared?*/
                        signal_manager();
                }
-               if (a->container) {
+               if (a->container && !a->to_remove) {
                        is_dirty = read_and_act(a);
                        rv |= 1;
                        dirty_arrays += is_dirty;
@@ -657,7 +657,7 @@ static int wait_and_act(struct supertype *container, int nowait)
 
        /* propagate failures across container members */
        for (a = *aap; a ; a = a->next) {
-               if (!a->container)
+               if (!a->container || a->to_remove)
                        continue;
                for (mdi = a->info.devs ; mdi ; mdi = mdi->next)
                        if (mdi->curr_state & DS_FAULTY)