X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=managemon.c;h=dc3ff7f2f0edd9abbc4fedb7fee827b645aad39a;hp=03de9a89f7ba6784c3642aa15b00894372f5dffe;hb=7801ac209240ca5d5159d2ab990dd8d5573e2195;hpb=edd8d13c0247b8df5876a94c2d61d74d2cf62c7e diff --git a/managemon.c b/managemon.c index 03de9a89..dc3ff7f2 100644 --- a/managemon.c +++ b/managemon.c @@ -159,6 +159,7 @@ static void remove_old(void) if (pending_discard == discard_this) pending_discard = NULL; discard_this = NULL; + wakeup_monitor(); } } @@ -174,7 +175,6 @@ static void replace_array(struct supertype *container, */ remove_old(); while (pending_discard) { - wakeup_monitor(); while (discard_this == NULL) sleep(1); remove_old(); @@ -218,13 +218,32 @@ static void queue_metadata_update(struct metadata_update *mu) *qp = mu; } -void wait_update_handled(void) +static void add_disk_to_container(struct supertype *st, struct mdinfo *sd) { - /* Wait for any pending update to be handled by monitor. - * i.e. wait until update_queue is NULL - */ - while (update_queue) - usleep(100 * 1000); + int dfd; + char nm[20]; + 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, + }; + + dprintf("%s: add %d:%d to container\n", + __func__, sd->disk.major, sd->disk.minor); + + sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); + dfd = dev_open(nm, O_RDWR); + if (dfd < 0) + return; + + st->update_tail = &update; + st->ss->add_to_super(st, &dk, dfd, NULL); + st->ss->write_init_super(st); + queue_metadata_update(update); + st->update_tail = NULL; } static void manage_container(struct mdstat_ent *mdstat, @@ -237,12 +256,48 @@ static void manage_container(struct mdstat_ent *mdstat, * about spare assignment.... probably not. */ if (mdstat->devcnt != container->devcnt) { + struct mdinfo **cdp, *cd, *di, *mdi; + int found; + /* read /sys/block/NAME/md/dev-??/block/dev to find out * what is there, and compare with container->info.devs * To see what is removed and what is added. * These need to be remove from, or added to, the array */ - // FIXME + mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS); + if (!mdi) { + /* invalidate the current count so we can try again */ + container->devcnt = -1; + return; + } + + /* check for removals */ + for (cdp = &container->devs; *cdp; ) { + found = 0; + for (di = mdi->devs; di; di = di->next) + if (di->disk.major == (*cdp)->disk.major && + di->disk.minor == (*cdp)->disk.minor) { + found = 1; + break; + } + if (!found) { + cd = *cdp; + *cdp = (*cdp)->next; + free(cd); + } else + cdp = &(*cdp)->next; + } + + /* check for additions */ + for (di = mdi->devs; di; di = di->next) { + for (cd = container->devs; cd; cd = cd->next) + if (di->disk.major == cd->disk.major && + di->disk.minor == cd->disk.minor) + break; + if (!cd) + add_disk_to_container(container, di); + } + sysfs_free(mdi); container->devcnt = mdstat->devcnt; } } @@ -272,7 +327,7 @@ static void manage_member(struct mdstat_ent *mdstat, struct metadata_update *updates = NULL; struct mdinfo *newdev; struct active_array *newa; - wait_update_handled(); + a->check_degraded = 0; /* The array may not be degraded, this is just a good time @@ -289,9 +344,13 @@ static void manage_member(struct mdstat_ent *mdstat, * and open files for each newdev */ for (d = newdev; d ; d = d->next) { struct mdinfo *newd; - if (sysfs_add_disk(&newa->info, d)) + if (sysfs_add_disk(&newa->info, d) < 0) continue; - newd = newa->info.devs; + newd = malloc(sizeof(*newd)); + *newd = *d; + newd->next = newa->info.devs; + newa->info.devs = newd; + newd->state_fd = sysfs_open(a->devnum, newd->sys_name, "state"); @@ -301,11 +360,32 @@ static void manage_member(struct mdstat_ent *mdstat, } queue_metadata_update(updates); replace_array(a->container, a, newa); - sysfs_set_str(&a->info, NULL, "sync_action", "repair"); + sysfs_set_str(&a->info, NULL, "sync_action", "recover"); } } } +static int aa_ready(struct active_array *aa) +{ + struct mdinfo *d; + int level = aa->info.array.level; + + for (d = aa->info.devs; d; d = d->next) + if (d->state_fd < 0) + return 0; + + if (aa->info.state_fd < 0) + return 0; + + if (level > 0 && (aa->action_fd < 0 || aa->resync_start_fd < 0)) + return 0; + + if (!aa->container) + return 0; + + return 1; +} + static void manage_new(struct mdstat_ent *mdstat, struct supertype *container, struct active_array *victim) @@ -320,9 +400,25 @@ static void manage_new(struct mdstat_ent *mdstat, struct mdinfo *mdi, *di; char *inst; int i; + int failed = 0; + + /* check if array is ready to be monitored */ + if (!mdstat->active) + 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); + return; + } memset(new, 0, sizeof(*new)); new->devnum = mdstat->devnum; @@ -335,19 +431,8 @@ static void manage_new(struct mdstat_ent *mdstat, inst = &mdstat->metadata_version[10+strlen(container->devname)+1]; - mdi = sysfs_read(-1, new->devnum, - GET_LEVEL|GET_CHUNK|GET_DISKS| - GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE); - if (!mdi) { - /* Eeek. Cannot monitor this array. - * Mark it to be ignored by setting container to NULL - */ - new->container = NULL; - replace_array(container, victim, new); - return; - } - new->info.array = mdi->array; + new->info.component_size = mdi->component_size; for (i = 0; i < new->info.array.raid_disks; i++) { struct mdinfo *newd = malloc(sizeof(*newd)); @@ -365,33 +450,45 @@ 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 { - newd->state_fd = -1; - newd->disk.raid_disk = i; - newd->prev_state = DS_REMOVE; - newd->curr_state = DS_REMOVE; + failed++; + free(newd); + 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->resync_start = 0; + new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version"); + get_resync_start(new); dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst), new->action_fd, new->info.state_fd); sysfs_free(mdi); - // finds and compares. - if (container->ss->open_new(container, new, inst) < 0) { - // FIXME close all those files + + /* if everything checks out tell the metadata handler we want to + * manage this instance + */ + if (!aa_ready(new) || container->ss->open_new(container, new, inst) < 0) { + fprintf(stderr, "mdmon: failed to monitor %s\n", + mdstat->metadata_version); new->container = NULL; + free_aa(new); + } else { replace_array(container, victim, new); - return; + if (failed) { + new->check_degraded = 1; + manage_member(mdstat, new); + } } - replace_array(container, victim, new); - return; } void manage(struct mdstat_ent *mdstat, struct supertype *container) @@ -408,7 +505,8 @@ void manage(struct mdstat_ent *mdstat, struct supertype *container) continue; } if (mdstat->metadata_version == NULL || - strncmp(mdstat->metadata_version, "external:/", 10) != 0 || + 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)] @@ -434,8 +532,29 @@ static void handle_message(struct supertype *container, struct metadata_update * struct metadata_update *mu; - if (msg->len == 0) { - wait_update_handled(); + if (msg->len <= 0) + while (update_queue_pending || update_queue) { + check_update_queue(container); + usleep(15*1000); + } + + if (msg->len == 0) { /* ping_monitor */ + int cnt; + + cnt = monitor_loop_cnt; + if (cnt & 1) + cnt += 2; /* wait until next pselect */ + else + cnt += 3; /* wait for 2 pselects */ + wakeup_monitor(); + + while (monitor_loop_cnt - cnt < 0) + usleep(10 * 1000); + } else if (msg->len == -1) { /* ping_manager */ + struct mdstat_ent *mdstat = mdstat_read(1, 0); + + manage(mdstat, container); + free_mdstat(mdstat); } else { mu = malloc(sizeof(*mu)); mu->len = msg->len; @@ -490,26 +609,43 @@ void do_manager(struct supertype *container) sigprocmask(SIG_UNBLOCK, NULL, &set); sigdelset(&set, SIGUSR1); + sigdelset(&set, SIGHUP); do { if (exit_now) exit(0); - mdstat = mdstat_read(1, 0); + /* Can only 'manage' things if 'monitor' is not making + * structural changes to metadata, so need to check + * update_queue + */ + if (update_queue == NULL) { + mdstat = mdstat_read(1, 0); - manage(mdstat, container); + manage(mdstat, container); - read_sock(container); + read_sock(container); - free_mdstat(mdstat); + if (socket_hup_requested) { + close(container->sock); + container->sock = make_control_sock(container->devname); + make_pidfile(container->devname, 0); + socket_hup_requested = 0; + } + free_mdstat(mdstat); + } remove_old(); check_update_queue(container); manager_ready = 1; - mdstat_wait_fd(container->sock, &set); + 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); }