]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - managemon.c
Create: support --readonly flag.
[thirdparty/mdadm.git] / managemon.c
index 860e5785aaf7f4abd9fa8e3418e740b6fbcf5cfa..ef351b3970b28b42f2e0c919a16030354a317f15 100644 (file)
@@ -117,11 +117,16 @@ static void close_aa(struct active_array *aa)
                close(d->state_fd);
        }
 
-       close(aa->action_fd);
-       close(aa->info.state_fd);
-       close(aa->resync_start_fd);
-       close(aa->metadata_fd);
-       close(aa->sync_completed_fd);
+       if (aa->action_fd >= 0)
+               close(aa->action_fd);
+       if (aa->info.state_fd >= 0)
+               close(aa->info.state_fd);
+       if (aa->resync_start_fd >= 0)
+               close(aa->resync_start_fd);
+       if (aa->metadata_fd >= 0)
+               close(aa->metadata_fd);
+       if (aa->sync_completed_fd >= 0)
+               close(aa->sync_completed_fd);
 }
 
 static void free_aa(struct active_array *aa)
@@ -142,7 +147,7 @@ static void free_aa(struct active_array *aa)
 
 static struct active_array *duplicate_aa(struct active_array *aa)
 {
-       struct active_array *newa = malloc(sizeof(*newa));
+       struct active_array *newa = xmalloc(sizeof(*newa));
        struct mdinfo **dp1, **dp2;
 
        *newa = *aa;
@@ -157,7 +162,7 @@ static struct active_array *duplicate_aa(struct active_array *aa)
                if ((*dp1)->state_fd < 0)
                        continue;
 
-               d = malloc(sizeof(*d));
+               d = xmalloc(sizeof(*d));
                *d = **dp1;
                *dp2 = d;
                dp2 = & d->next;
@@ -320,16 +325,15 @@ static void remove_disk_from_container(struct supertype *st, struct mdinfo *sd)
                .raid_disk = -1,
                .state = 0,
        };
-       /* nothing to do if super type handler does not support
-        * remove disk primitive
-        */
-       if (!st->ss->remove_from_super)
-               return;
        dprintf("%s: remove %d:%d from container\n",
                __func__, sd->disk.major, sd->disk.minor);
 
        st->update_tail = &update;
        st->ss->remove_from_super(st, &dk);
+       /* FIXME this write_init_super shouldn't be here.
+        * We have it after add_to_super to write to new device,
+        * but with 'remove' we don't ant to write to that device!
+        */
        st->ss->write_init_super(st);
        queue_metadata_update(update);
        st->update_tail = NULL;
@@ -387,12 +391,8 @@ static void manage_container(struct mdstat_ent *mdstat,
                                    di->disk.minor == cd->disk.minor)
                                        break;
                        if (!cd) {
-                               struct mdinfo *newd = malloc(sizeof(*newd));
+                               struct mdinfo *newd = xmalloc(sizeof(*newd));
 
-                               if (!newd) {
-                                       container->devcnt = -1;
-                                       continue;
-                               }
                                *newd = *di;
                                add_disk_to_container(container, newd);
                        }
@@ -410,7 +410,13 @@ static int disk_init_and_add(struct mdinfo *disk, struct mdinfo *clone,
 
        *disk = *clone;
        disk->recovery_fd = sysfs_open(aa->devnum, disk->sys_name, "recovery_start");
+       if (disk->recovery_fd < 0)
+               return -1;
        disk->state_fd = sysfs_open(aa->devnum, disk->sys_name, "state");
+       if (disk->state_fd < 0) {
+               close(disk->recovery_fd);
+               return -1;
+       }
        disk->prev_state = read_dev_state(disk->state_fd);
        disk->curr_state = disk->prev_state;
        disk->next = aa->info.devs;
@@ -437,6 +443,11 @@ static void manage_member(struct mdstat_ent *mdstat,
         */
        char buf[64];
        int frozen;
+       struct supertype *container = a->container;
+
+       if (container == NULL)
+               /* Raced with something */
+               return;
 
        // FIXME
        a->info.array.raid_disks = mdstat->raid_disks;
@@ -448,7 +459,41 @@ static void manage_member(struct mdstat_ent *mdstat,
        else
                frozen = 1; /* can't read metadata_version assume the worst */
 
-       if (a->check_degraded && !frozen) {
+       /* 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 (level == 0 || level == LEVEL_LINEAR) {
+                       a->to_remove = 1;
+                       wakeup_monitor();
+                       return;
+               }
+               else if (a->info.array.level != level && level > 0) {
+                       struct active_array *newa = duplicate_aa(a);
+                       if (newa) {
+                               newa->info.array.level = level;
+                               replace_array(container, a, newa);
+                               a = newa;
+                       }
+               }
+       }
+
+       /* we are after monitor kick,
+        * so container field can be cleared - check it again
+        */
+       if (a->container == NULL)
+               return;
+
+       /* We don't check the array while any update is pending, as it
+        * might container a change (such as a spare assignment) which
+        * could affect our decisions.
+        */
+       if (a->check_degraded && !frozen &&
+           update_queue == NULL && update_queue_pending == NULL) {
                struct metadata_update *updates = NULL;
                struct mdinfo *newdev = NULL;
                struct active_array *newa;
@@ -459,23 +504,24 @@ static void manage_member(struct mdstat_ent *mdstat,
                /* The array may not be degraded, this is just a good time
                 * to check.
                 */
-               newdev = a->container->ss->activate_spare(a, &updates);
+               newdev = container->ss->activate_spare(a, &updates);
                if (!newdev)
                        return;
 
                newa = duplicate_aa(a);
                if (!newa)
                        goto out;
-               /* Cool, we can add a device or several. */
+               /* prevent the kernel from activating the disk(s) before we
+                * finish adding them
+                */
+               sysfs_set_str(&a->info, NULL, "sync_action", "frozen");
 
                /* Add device to array and set offset/size/slot.
                 * and open files for each newdev */
                for (d = newdev; d ; d = d->next) {
                        struct mdinfo *newd;
 
-                       newd = malloc(sizeof(*newd));
-                       if (!newd)
-                               continue;
+                       newd = xmalloc(sizeof(*newd));
                        if (sysfs_add_disk(&newa->info, d, 0) < 0) {
                                free(newd);
                                continue;
@@ -484,7 +530,7 @@ static void manage_member(struct mdstat_ent *mdstat,
                }
                queue_metadata_update(updates);
                updates = NULL;
-               replace_array(a->container, a, newa);
+               replace_array(container, a, newa);
                sysfs_set_str(&a->info, NULL, "sync_action", "recover");
  out:
                while (newdev) {
@@ -503,6 +549,7 @@ static void manage_member(struct mdstat_ent *mdstat,
                 * 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,
@@ -524,15 +571,18 @@ static void manage_member(struct mdstat_ent *mdstat,
                                if (!newa)
                                        break;
                        }
-                       newd = malloc(sizeof(*newd));
-                       if (!newd)
-                               continue;
+                       newd = xmalloc(sizeof(*newd));
                        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);
+                       replace_array(container, a, newa);
        }
 }
 
@@ -572,25 +622,23 @@ 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)
+       if (!mdstat->active || !mdstat->level)
+               return;
+       if (strcmp(mdstat->level, "raid0") == 0 ||
+           strcmp(mdstat->level, "linear") == 0)
                return;
 
        mdi = sysfs_read(-1, mdstat->devnum,
                         GET_LEVEL|GET_CHUNK|GET_DISKS|GET_COMPONENT|
                         GET_DEGRADED|GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE);
 
-       new = malloc(sizeof(*new));
 
-       if (!new || !mdi) {
-               if (mdi)
-                       sysfs_free(mdi);
-               if (new)
-                       free(new);
+       if (!mdi)
                return;
-       }
-       memset(new, 0, sizeof(*new));
+       new = xcalloc(1, sizeof(*new));
 
        new->devnum = mdstat->devnum;
        strcpy(new->info.sys_name, devnum2devname(new->devnum));
@@ -606,7 +654,7 @@ static void manage_new(struct mdstat_ent *mdstat,
        new->info.component_size = mdi->component_size;
 
        for (i = 0; i < new->info.array.raid_disks; i++) {
-               struct mdinfo *newd = malloc(sizeof(*newd));
+               struct mdinfo *newd = xmalloc(sizeof(*newd));
 
                for (di = mdi->devs; di; di = di->next)
                        if (i == di->disk.raid_disk)
@@ -633,6 +681,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
@@ -671,7 +742,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;
                        }
@@ -711,7 +782,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
                manage(mdstat, container);
                free_mdstat(mdstat);
        } else if (!sigterm) {
-               mu = malloc(sizeof(*mu));
+               mu = xmalloc(sizeof(*mu));
                mu->len = msg->len;
                mu->buf = msg->buf;
                msg->buf = NULL;