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)
{
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);
}
}
*/
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.
st->update_tail = NULL;
}
+/*
+ * Create and queue update structure about the removed disks.
+ * The update is prepared by super type handler and passed to the monitor
+ * thread.
+ */
+static void remove_disk_from_container(struct supertype *st, struct mdinfo *sd)
+{
+ struct metadata_update *update = NULL;
+ mdu_disk_info_t dk = {
+ .number = -1,
+ .major = sd->disk.major,
+ .minor = sd->disk.minor,
+ .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);
+ st->ss->write_init_super(st);
+ queue_metadata_update(update);
+ st->update_tail = NULL;
+}
+
static void manage_container(struct mdstat_ent *mdstat,
struct supertype *container)
{
- /* The only thing of interest here is if a new device
- * has been added to the container. We add it to the
- * array ignoring any metadata on it.
+ /* Of interest here are:
+ * - if a new device has been added to the container, we
+ * add it to the array ignoring any metadata on it.
+ * - if a device has been removed from the container, we
+ * remove it from the device list and update the metadata.
* FIXME should we look for compatible metadata and take hints
* about spare assignment.... probably not.
*/
* 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|SKIP_GONE_DEVS);
+ mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS);
if (!mdi) {
/* invalidate the current count so we can try again */
container->devcnt = -1;
if (!found) {
cd = *cdp;
*cdp = (*cdp)->next;
+ remove_disk_from_container(container, cd);
free(cd);
} else
cdp = &(*cdp)->next;
}
}
+static int disk_init_and_add(struct mdinfo *disk, struct mdinfo *clone,
+ struct active_array *aa)
+{
+ if (!disk || !clone)
+ return -1;
+
+ *disk = *clone;
+ disk->recovery_fd = sysfs_open(aa->devnum, disk->sys_name, "recovery_start");
+ disk->state_fd = sysfs_open(aa->devnum, disk->sys_name, "state");
+ disk->prev_state = read_dev_state(disk->state_fd);
+ disk->curr_state = disk->prev_state;
+ disk->next = aa->info.devs;
+ aa->info.devs = disk;
+
+ return 0;
+}
+
static void manage_member(struct mdstat_ent *mdstat,
struct active_array *a)
{
* 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;
- a->info.array.chunk_size = mdstat->chunk_size;
// MORE
- if (a->check_degraded) {
+ /* 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 (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;
+ }
+ }
+ }
+
+ if (a->check_degraded && !frozen) {
struct metadata_update *updates = NULL;
struct mdinfo *newdev = NULL;
struct active_array *newa;
free(newd);
continue;
}
- *newd = *d;
- newd->next = newa->info.devs;
- newa->info.devs = newd;
-
- newd->state_fd = sysfs_open(a->devnum, newd->sys_name,
- "state");
- newd->prev_state = read_dev_state(newd->state_fd);
- newd->curr_state = newd->prev_state;
+ disk_init_and_add(newd, d, newa);
}
queue_metadata_update(updates);
updates = NULL;
}
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) {
+ sysfs_set_num(info, NULL, "array_size",
+ a->info.custom_array_size);
+ }
+ out2:
+ sysfs_free(info);
+ if (newa)
+ replace_array(a->container, a, newa);
+ }
}
static int aa_ready(struct active_array *aa)
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;
if (i == di->disk.raid_disk)
break;
- if (di && newd) {
- memcpy(newd, di, sizeof(*newd));
-
- newd->state_fd = sysfs_open(new->devnum,
- newd->sys_name,
- "state");
- newd->recovery_fd = sysfs_open(new->devnum,
- newd->sys_name,
- "recovery_start");
-
- newd->prev_state = read_dev_state(newd->state_fd);
- newd->curr_state = newd->prev_state;
- } else {
+ if (disk_init_and_add(newd, di, new) != 0) {
if (newd)
free(newd);
new->container = NULL;
break;
}
- continue;
}
- sprintf(newd->sys_name, "rd%d", i);
- newd->next = new->info.devs;
- new->info.devs = newd;
}
new->action_fd = sysfs_open(new->devnum, NULL, "sync_action");
new->info.state_fd = sysfs_open(new->devnum, NULL, "array_state");
new->resync_start_fd = sysfs_open(new->devnum, NULL, "resync_start");
new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version");
+ new->sync_completed_fd = sysfs_open(new->devnum, NULL, "sync_completed");
dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
new->action_fd, new->info.state_fd);
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);
/* 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;
{
struct mdstat_ent *mdstat;
sigset_t set;
- int proc_fd;
sigprocmask(SIG_UNBLOCK, NULL, &set);
sigdelset(&set, SIGUSR1);
- sigdelset(&set, SIGHUP);
- sigdelset(&set, SIGALRM);
sigdelset(&set, SIGTERM);
- proc_fd = open("/proc/mounts", O_RDONLY);
do {
read_sock(container);
- if (container->sock < 0 || socket_hup_requested) {
- /* If this fails, we hope it already exists
- * pid file lives in /var/run/mdadm/mdXX.pid
- */
- mkdir("/var", 0600);
- mkdir("/var/run", 0600);
- mkdir("/var/run/mdadm", 0600);
- close(container->sock);
- container->sock = make_control_sock(container->devname);
- make_pidfile(container->devname, 0);
- socket_hup_requested = 0;
- }
- if (container->sock < 0)
- alarm(30);
-
free_mdstat(mdstat);
}
remove_old();
if (sigterm)
wakeup_monitor();
- if (update_queue == NULL) {
- if (container->sock < 0)
- mdstat_wait_fd(proc_fd, &set);
- else
- mdstat_wait_fd(container->sock, &set);
- } else
+ if (update_queue == NULL)
+ mdstat_wait_fd(container->sock, &set);
+ else
/* If an update is happening, just wait for signal */
pselect(0, NULL, NULL, NULL, NULL, &set);
} while(1);