]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - managemon.c
Merge branch 'master' in devel-3.0
[thirdparty/mdadm.git] / managemon.c
index 730334cd6d278a2770caeebb6e52d0185f256b63..e02c77ea964ef8fa6746ec05f06dc3835f312eb2 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * mdmon - monitor external metadata arrays
+ *
+ * Copyright (C) 2007-2008 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2007-2008 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
 /*
  * The management thread for monitoring active md arrays.
@@ -222,7 +241,9 @@ static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
 {
        int dfd;
        char nm[20];
+       struct supertype *st2;
        struct metadata_update *update = NULL;
+       struct mdinfo info;
        mdu_disk_info_t dk = {
                .number = -1,
                .major = sd->disk.major,
@@ -234,11 +255,33 @@ static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
        dprintf("%s: add %d:%d to container\n",
                __func__, sd->disk.major, sd->disk.minor);
 
+       sd->next = st->devs;
+       st->devs = sd;
+
        sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
        dfd = dev_open(nm, O_RDWR);
        if (dfd < 0)
                return;
 
+       /* Check the metadata and see if it is already part of this
+        * array
+        */
+       st2 = dup_super(st);
+       if (st2->ss->load_super(st2, dfd, NULL) == 0) {
+               st2->ss->getinfo_super(st, &info);
+               if (st->ss->compare_super(st, st2) == 0 &&
+                   info.disk.raid_disk >= 0) {
+                       /* Looks like a good member of array.
+                        * Just accept it.
+                        * mdadm will incorporate any parts into
+                        * active arrays.
+                        */
+                       st2->ss->free_super(st2);
+                       return;
+               }
+       }
+       st2->ss->free_super(st2);
+
        st->update_tail = &update;
        st->ss->add_to_super(st, &dk, dfd, NULL);
        st->ss->write_init_super(st);
@@ -264,7 +307,7 @@ static void manage_container(struct mdstat_ent *mdstat,
                 * To see what is removed and what is added.
                 * These need to be remove from, or added to, the array
                 */
-               mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS);
+               mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS|SKIP_GONE_DEVS);
                if (!mdi) {
                        /* invalidate the current count so we can try again */
                        container->devcnt = -1;
@@ -294,8 +337,16 @@ static void manage_container(struct mdstat_ent *mdstat,
                                if (di->disk.major == cd->disk.major &&
                                    di->disk.minor == cd->disk.minor)
                                        break;
-                       if (!cd)
-                               add_disk_to_container(container, di);
+                       if (!cd) {
+                               struct mdinfo *newd = malloc(sizeof(*newd));
+
+                               if (!newd) {
+                                       container->devcnt = -1;
+                                       continue;
+                               }
+                               *newd = *di;
+                               add_disk_to_container(container, newd);
+                       }
                }
                sysfs_free(mdi);
                container->devcnt = mdstat->devcnt;
@@ -441,7 +492,7 @@ static void manage_new(struct mdstat_ent *mdstat,
                        if (i == di->disk.raid_disk)
                                break;
 
-               if (di) {
+               if (di && newd) {
                        memcpy(newd, di, sizeof(*newd));
 
                        newd->state_fd = sysfs_open(new->devnum,
@@ -450,13 +501,16 @@ static void manage_new(struct mdstat_ent *mdstat,
 
                        newd->prev_state = read_dev_state(newd->state_fd);
                        newd->curr_state = newd->prev_state;
-               } else if (failed + 1 > new->info.array.failed_disks) {
-                       /* we cannot properly monitor without all working disks */
-                       new->container = NULL;
-                       break;
                } else {
+                       if (newd)
+                               free(newd);
+
                        failed++;
-                       free(newd);
+                       if (failed > new->info.array.failed_disks) {
+                               /* we cannot properly monitor without all working disks */
+                               new->container = NULL;
+                               break;
+                       }
                        continue;
                }
                sprintf(newd->sys_name, "rd%d", i);
@@ -504,13 +558,7 @@ void manage(struct mdstat_ent *mdstat, struct supertype *container)
                        manage_container(mdstat, container);
                        continue;
                }
-               if (mdstat->metadata_version == NULL ||
-                   strncmp(mdstat->metadata_version, "external:", 9) != 0 ||
-                   !is_subarray(mdstat->metadata_version+9) ||
-                   strncmp(mdstat->metadata_version+10, container->devname,
-                           strlen(container->devname)) != 0 ||
-                   mdstat->metadata_version[10+strlen(container->devname)]
-                     != '/')
+               if (!is_container_member(mdstat, container->devname))
                        /* Not for this array */
                        continue;
                /* Looks like a member of this container */
@@ -555,7 +603,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
 
                manage(mdstat, container);
                free_mdstat(mdstat);
-       } else {
+       } else if (!sigterm) {
                mu = malloc(sizeof(*mu));
                mu->len = msg->len;
                mu->buf = msg->buf;
@@ -612,6 +660,7 @@ void do_manager(struct supertype *container)
        sigdelset(&set, SIGUSR1);
        sigdelset(&set, SIGHUP);
        sigdelset(&set, SIGALRM);
+       sigdelset(&set, SIGTERM);
        proc_fd = open("/proc/mounts", O_RDONLY);
 
        do {
@@ -647,6 +696,9 @@ void do_manager(struct supertype *container)
 
                manager_ready = 1;
 
+               if (sigterm)
+                       wakeup_monitor();
+
                if (update_queue == NULL) {
                        if (container->sock < 0)
                                mdstat_wait_fd(proc_fd, &set);