]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - managemon.c
Merge branch 'master' into devel-3.2
[thirdparty/mdadm.git] / managemon.c
index 8684e27369aec7c9f44e1c3fe5b975554beb750a..d6c57f78bd28a038d92dcad390272a79fbd82429 100644 (file)
@@ -120,6 +120,8 @@ static void close_aa(struct active_array *aa)
        close(aa->action_fd);
        close(aa->info.state_fd);
        close(aa->resync_start_fd);
+       close(aa->metadata_fd);
+       close(aa->sync_completed_fd);
 }
 
 static void free_aa(struct active_array *aa)
@@ -215,10 +217,16 @@ static void free_updates(struct metadata_update **update)
 {
        while (*update) {
                struct metadata_update *this = *update;
+               void **space_list = this->space_list;
 
                *update = this->next;
                free(this->buf);
                free(this->space);
+               while (space_list) {
+                       void *space = space_list;
+                       space_list = *space_list;
+                       free(space);
+               }
                free(this);
        }
 }
@@ -276,7 +284,7 @@ static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
         */
        st2 = dup_super(st);
        if (st2->ss->load_super(st2, dfd, NULL) == 0) {
-               st2->ss->getinfo_super(st, &info);
+               st2->ss->getinfo_super(st, &info, NULL);
                if (st->ss->compare_super(st, st2) == 0 &&
                    info.disk.raid_disk >= 0) {
                        /* Looks like a good member of array.
@@ -417,24 +425,51 @@ static void manage_member(struct mdstat_ent *mdstat,
         * We do not need to look for device state changes here, that
         * is dealt with by the monitor.
         *
-        * We just look for changes which suggest that a reshape is
-        * being requested.
-        * Unfortunately decreases in raid_disks don't show up in
-        * mdstat until the reshape completes FIXME.
+        * If a reshape is being requested, monitor will have noticed
+        * that sync_action changed and will have set check_reshape.
+        * We just need to see if new devices have appeared.  All metadata
+        * updates will already have been processed.
         *
-        * Actually, we also want to handle degraded arrays here by
+        * We also want to handle degraded arrays here by
         * trying to find and assign a spare.
         * We do that whenever the monitor tells us too.
         */
+       char buf[64];
+       int frozen;
+
        // FIXME
        a->info.array.raid_disks = mdstat->raid_disks;
        // MORE
 
+       /* honor 'frozen' */
+       if (sysfs_get_str(&a->info, NULL, "metadata_version", buf, sizeof(buf)) > 0)
+               frozen = buf[9] == '-';
+       else
+               frozen = 1; /* can't read metadata_version assume the worst */
+
+       /* If sync_action is not 'idle' then don't try recovery now */
+       if (!frozen
+           && sysfs_get_str(&a->info, NULL, "sync_action", buf, sizeof(buf)) > 0
+           && strncmp(buf, "idle", 4) != 0)
+               frozen = 1;
+
+       if (mdstat->level) {
+               int level = map_name(pers, mdstat->level);
+               if (a->info.array.level != level && level >= 0) {
+                       struct active_array *newa = duplicate_aa(a);
+                       if (newa) {
+                               newa->info.array.level = level;
+                               replace_array(a->container, a, newa);
+                               a = newa;
+                       }
+               }
+       }
+
        /* We don't check the array while any update is pending, as it
-        * might container a change (such as a spare assignment) which 
+        * might container a change (such as a spare assignment) which
         * could affect our decisions.
         */
-       if (a->check_degraded &&
+       if (a->check_degraded && !frozen &&
            update_queue == NULL && update_queue_pending == NULL) {
                struct metadata_update *updates = NULL;
                struct mdinfo *newdev = NULL;
@@ -481,6 +516,52 @@ static void manage_member(struct mdstat_ent *mdstat,
                }
                free_updates(&updates);
        }
+
+       if (a->check_reshape) {
+               /* mdadm might have added some devices to the array.
+                * We want to disk_init_and_add any such device to a
+                * duplicate_aa and replace a with that.
+                * mdstat doesn't have enough info so we sysfs_read
+                * and look for new stuff.
+                */
+               struct mdinfo *info, *d, *d2, *newd;
+               unsigned long long array_size;
+               struct active_array *newa = NULL;
+               a->check_reshape = 0;
+               info = sysfs_read(-1, mdstat->devnum,
+                                 GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE);
+               if (!info)
+                       goto out2;
+               for (d = info->devs; d; d = d->next) {
+                       if (d->disk.raid_disk < 0)
+                               continue;
+                       for (d2 = a->info.devs; d2; d2 = d2->next)
+                               if (d2->disk.raid_disk ==
+                                   d->disk.raid_disk)
+                                       break;
+                       if (d2)
+                               /* already have this one */
+                               continue;
+                       if (!newa) {
+                               newa = duplicate_aa(a);
+                               if (!newa)
+                                       break;
+                       }
+                       newd = malloc(sizeof(*newd));
+                       if (!newd)
+                               continue;
+                       disk_init_and_add(newd, d, newa);
+               }
+               if (sysfs_get_ll(info, NULL, "array_size", &array_size) == 0
+                   && a->info.custom_array_size > array_size*2) {
+                       sysfs_set_num(info, NULL, "array_size",
+                                     a->info.custom_array_size/2);
+               }
+       out2:
+               sysfs_free(info);
+               if (newa)
+                       replace_array(a->container, a, newa);
+       }
 }
 
 static int aa_ready(struct active_array *aa)
@@ -519,6 +600,7 @@ static void manage_new(struct mdstat_ent *mdstat,
        char *inst;
        int i;
        int failed = 0;
+       char buf[40];
 
        /* check if array is ready to be monitored */
        if (!mdstat->active)
@@ -547,7 +629,7 @@ static void manage_new(struct mdstat_ent *mdstat,
 
        new->container = container;
 
-       inst = &mdstat->metadata_version[10+strlen(container->devname)+1];
+       inst = to_subarray(mdstat, container->devname);
 
        new->info.array = mdi->array;
        new->info.component_size = mdi->component_size;
@@ -580,6 +662,29 @@ static void manage_new(struct mdstat_ent *mdstat,
        dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
                new->action_fd, new->info.state_fd);
 
+       /* reshape_position is set by mdadm in sysfs
+        * read this information for new arrays only (empty victim)
+        */
+       if ((victim == NULL) &&
+           (sysfs_get_str(mdi, NULL, "sync_action", buf, 40) > 0) &&
+           (strncmp(buf, "reshape", 7) == 0)) {
+               if (sysfs_get_ll(mdi, NULL, "reshape_position",
+                       &new->last_checkpoint) != 0)
+                       new->last_checkpoint = 0;
+               else {
+                       int data_disks = mdi->array.raid_disks;
+                       if (mdi->array.level == 4 || mdi->array.level == 5)
+                               data_disks--;
+                       if (mdi->array.level == 6)
+                               data_disks -= 2;
+
+                       new->last_checkpoint /= data_disks;
+               }
+               dprintf("mdmon: New monitored array is under reshape.\n"
+                       "       Last checkpoint is: %llu\n",
+                       new->last_checkpoint);
+       }
+
        sysfs_free(mdi);
 
        /* if everything checks out tell the metadata handler we want to
@@ -663,6 +768,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
                mu->buf = msg->buf;
                msg->buf = NULL;
                mu->space = NULL;
+               mu->space_list = NULL;
                mu->next = NULL;
                if (container->ss->prepare_update)
                        container->ss->prepare_update(container, mu);
@@ -692,7 +798,13 @@ void read_sock(struct supertype *container)
                /* read and validate the message */
                if (receive_message(fd, &msg, tmo) == 0) {
                        handle_message(container, &msg);
-                       if (ack(fd, tmo) < 0)
+                       if (msg.len == 0) {
+                               /* ping reply with version */
+                               msg.buf = Version;
+                               msg.len = strlen(Version) + 1;
+                               if (send_message(fd, &msg, tmo) < 0)
+                                       terminate = 1;
+                       } else if (ack(fd, tmo) < 0)
                                terminate = 1;
                } else
                        terminate = 1;