X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=Incremental.c;h=75d95ccc497a4a3c7fcb364b15a71cc9478b6238;hb=1ab97c976b3f1cdc6d36d72a42ae863188555732;hp=0a75e3431a08ab5f3465099169b1ef3a4e3e2b8d;hpb=ed503f89e4216dfd55d713e6b2bc08f148206f12;p=thirdparty%2Fmdadm.git diff --git a/Incremental.c b/Incremental.c index 0a75e343..75d95ccc 100644 --- a/Incremental.c +++ b/Incremental.c @@ -2,7 +2,7 @@ * Incremental.c - support --incremental. Part of: * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2006-2012 Neil Brown + * Copyright (C) 2006-2013 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -44,9 +44,9 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol, struct supertype *st, int verbose); static int Incremental_container(struct supertype *st, char *devname, - struct context *c); + struct context *c, char *only); -int Incremental(char *devname, struct context *c, +int Incremental(struct mddev_dev *devlist, struct context *c, struct supertype *st) { /* Add this device to an array, creating the array if necessary @@ -91,6 +91,7 @@ int Incremental(char *devname, struct context *c, struct mdinfo *sra = NULL, *d; struct mddev_ident *match; char chosen_name[1024]; + char *md_devname; int rv = 1; struct map_ent *mp, *map = NULL; int dfd = -1, mdfd = -1; @@ -102,6 +103,8 @@ int Incremental(char *devname, struct context *c, struct dev_policy *policy = NULL; struct map_ent target_array; int have_target; + char *devname = devlist->devname; + int journal_device_missing = 0; struct createinfo *ci = conf_get_create_info(); @@ -128,17 +131,16 @@ int Incremental(char *devname, struct context *c, if (must_be_container(dfd)) { if (!st) st = super_by_fd(dfd, NULL); - if (st) - st->ignore_hw_compat = 1; if (st && st->ss->load_container) rv = st->ss->load_container(st, dfd, NULL); close(dfd); if (!rv && st->ss->container_content) { if (map_lock(&map)) - pr_err("failed to get " - "exclusive lock on mapfile\n"); - rv = Incremental_container(st, devname, c); + pr_err("failed to get exclusive lock on mapfile\n"); + if (c->export) + printf("MD_DEVNAME=%s\n", devname); + rv = Incremental_container(st, devname, c, NULL); map_unlock(&map); return rv; } @@ -150,7 +152,20 @@ int Incremental(char *devname, struct context *c, /* 1/ Check if device is permitted by mdadm.conf */ - if (!conf_test_dev(devname)) { + for (;devlist; devlist = devlist->next) + if (conf_test_dev(devlist->devname)) + break; + if (!devlist) { + devlist = conf_get_devs(); + for (;devlist; devlist = devlist->next) { + struct stat st2; + if (stat(devlist->devname, &st2) == 0 && + (st2.st_mode & S_IFMT) == S_IFBLK && + st2.st_rdev == stb.st_rdev) + break; + } + } + if (!devlist) { if (c->verbose >= 0) pr_err("%s not permitted by mdadm.conf.\n", devname); @@ -179,18 +194,19 @@ int Incremental(char *devname, struct context *c, policy = disk_policy(&dinfo); have_target = policy_check_path(&dinfo, &target_array); - if (st == NULL && (st = guess_super(dfd)) == NULL) { + if (st == NULL && (st = guess_super_type(dfd, guess_array)) == NULL) { if (c->verbose >= 0) pr_err("no recognisable superblock on %s.\n", devname); rv = try_spare(devname, &dfd, policy, have_target ? &target_array : NULL, - st, c->verbose); + NULL, c->verbose); goto out; } - st->ignore_hw_compat = 1; + st->ignore_hw_compat = 0; + if (st->ss->compare_super == NULL || - st->ss->load_super(st, dfd, NULL)) { + st->ss->load_super(st, dfd, c->verbose >= 0 ? devname : NULL)) { if (c->verbose >= 0) pr_err("no RAID superblock on %s.\n", devname); @@ -212,8 +228,7 @@ int Incremental(char *devname, struct context *c, if (match && match->devname && strcasecmp(match->devname, "") == 0) { if (c->verbose >= 0) - pr_err("array containing %s is explicitly" - " ignored by mdadm.conf\n", + pr_err("array containing %s is explicitly ignored by mdadm.conf\n", devname); goto out; } @@ -234,8 +249,7 @@ int Incremental(char *devname, struct context *c, if (!match && !conf_test_metadata(st->ss->name, policy, (trustworthy == LOCAL))) { if (c->verbose >= 1) - pr_err("%s has metadata type %s for which " - "auto-assembly is disabled\n", + pr_err("%s has metadata type %s for which auto-assembly is disabled\n", devname, st->ss->name); goto out; } @@ -272,8 +286,7 @@ int Incremental(char *devname, struct context *c, /* 4/ Check if array exists. */ if (map_lock(&map)) - pr_err("failed to get exclusive lock on " - "mapfile\n"); + pr_err("failed to get exclusive lock on mapfile\n"); /* Now check we can get O_EXCL. If not, probably "mdadm -A" has * taken over */ @@ -300,6 +313,12 @@ int Incremental(char *devname, struct context *c, if (mdfd < 0) { + /* Skip the clustered ones. This should be started by + * clustering resource agents + */ + if (info.array.state & (1 << MD_SB_CLUSTERED)) + goto out; + /* Couldn't find an existing array, maybe make a new one */ mdfd = create_mddev(match ? match->devname : NULL, name_to_use, c->autof, trustworthy, chosen_name); @@ -335,8 +354,7 @@ int Incremental(char *devname, struct context *c, * So reject it. */ ioctl(mdfd, STOP_ARRAY, NULL); - pr_err("You have an old buggy kernel which cannot support\n" - " --incremental reliably. Aborting.\n"); + pr_err("You have an old buggy kernel which cannot support\n --incremental reliably. Aborting.\n"); rv = 2; goto out_unlock; } @@ -403,8 +421,7 @@ int Incremental(char *devname, struct context *c, st2 = dup_super(st); if (st2->ss->load_super(st2, dfd2, NULL) || st->ss->compare_super(st, st2) != 0) { - pr_err("metadata mismatch between %s and " - "chosen array %s\n", + pr_err("metadata mismatch between %s and chosen array %s\n", devname, chosen_name); close(dfd2); rv = 2; @@ -427,6 +444,10 @@ int Incremental(char *devname, struct context *c, /* add disk needs to know about containers */ if (st->ss->external) sra->array.level = LEVEL_CONTAINER; + + if (info.array.state & (1 << MD_SB_CLUSTERED)) + info.disk.state |= (1 << MD_DISK_CLUSTER_ADD); + err = add_disk(mdfd, st, sra, &info); if (err < 0 && errno == EBUSY) { /* could be another device present with the same @@ -459,6 +480,15 @@ int Incremental(char *devname, struct context *c, info.array.working_disks ++; } + if (strncmp(chosen_name, "/dev/md/", 8) == 0) + md_devname = chosen_name+8; + else + md_devname = chosen_name; + if (c->export) { + printf("MD_DEVICE=%s\n", fd2devnm(mdfd)); + printf("MD_DEVNAME=%s\n", md_devname); + printf("MD_FOREIGN=%s\n", trustworthy == FOREIGN ? "yes" : "no"); + } /* 7/ Is there enough devices to possibly start the array? */ /* 7a/ if not, finish with success. */ @@ -466,7 +496,7 @@ int Incremental(char *devname, struct context *c, char devnm[32]; /* Try to assemble within the container */ sysfs_uevent(sra, "change"); - if (c->verbose >= 0) + if (!c->export && c->verbose >= 0) pr_err("container %s now has %d device%s\n", chosen_name, info.array.working_disks, info.array.working_disks == 1?"":"s"); @@ -478,13 +508,8 @@ int Incremental(char *devname, struct context *c, close(mdfd); sysfs_free(sra); if (!rv) - rv = Incremental_container(st, chosen_name, c); + rv = Incremental_container(st, chosen_name, c, NULL); map_unlock(&map); - if (rv == 1) - /* Don't fail the whole -I if a subarray didn't - * have enough devices to start yet - */ - rv = 0; /* after spare is added, ping monitor for external metadata * so that it can eg. try to rebuild degraded array */ if (st->ss->external) @@ -500,10 +525,15 @@ int Incremental(char *devname, struct context *c, sra = sysfs_read(mdfd, NULL, (GET_DEVS | GET_STATE | GET_OFFSET | GET_SIZE)); active_disks = count_active(st, sra, mdfd, &avail, &info); + + journal_device_missing = (info.journal_device_required) && (info.journal_clean == 0); + if (enough(info.array.level, info.array.raid_disks, info.array.layout, info.array.state & 1, avail) == 0) { - if (c->verbose >= 0) + if (c->export) { + printf("MD_STARTED=no\n"); + } else if (c->verbose >= 0) pr_err("%s attached to %s, not enough to start (%d).\n", devname, chosen_name, active_disks); rv = 0; @@ -517,7 +547,9 @@ int Incremental(char *devname, struct context *c, /* + start the array (auto-readonly). */ if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) { - if (c->verbose >= 0) + if (c->export) { + printf("MD_STARTED=already\n"); + } else if (c->verbose >= 0) pr_err("%s attached to %s which is already active.\n", devname, chosen_name); rv = 0; @@ -525,10 +557,12 @@ int Incremental(char *devname, struct context *c, } map_unlock(&map); - if (c->runstop > 0 || active_disks >= info.array.working_disks) { + if (c->runstop > 0 || (!journal_device_missing && active_disks >= info.array.working_disks)) { struct mdinfo *dsk; /* Let's try to start it */ + if (journal_device_missing) + pr_err("Trying to run with missing journal device\n"); if (info.reshape_active && !(info.reshape_active & RESHAPE_NO_BACKUP)) { pr_err("%s: This array is being reshaped and cannot be started\n", chosen_name); @@ -563,8 +597,14 @@ int Incremental(char *devname, struct context *c, else rv = sysfs_set_str(sra, NULL, "array_state", "read-auto"); + /* Array might be O_EXCL which will interfere with + * fsck and mount. So re-open without O_EXCL. + */ + reopen_mddev(mdfd); if (rv == 0) { - if (c->verbose >= 0) + if (c->export) { + printf("MD_STARTED=yes\n"); + } else if (c->verbose >= 0) pr_err("%s attached to %s, which has been started.\n", devname, chosen_name); rv = 0; @@ -587,7 +627,11 @@ int Incremental(char *devname, struct context *c, rv = 1; } } else { - if (c->verbose >= 0) + if (c->export) { + printf("MD_STARTED=unsafe\n"); + } else if (journal_device_missing) { + pr_err("Journal device is missing, not safe to start yet.\n"); + } else if (c->verbose >= 0) pr_err("%s attached to %s, not enough to start safely.\n", devname, chosen_name); rv = 0; @@ -600,8 +644,7 @@ out: close(mdfd); if (policy) dev_policy_free(policy); - if (sra) - sysfs_free(sra); + sysfs_free(sra); return rv; out_unlock: map_unlock(&map); @@ -623,7 +666,7 @@ static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra, * without thinking more */ for (d = sra->devs; d ; d = d->next) { - char dn[10]; + char dn[24]; // 2*11 bytes for ints (including sign) + colon + null byte int dfd; struct mdinfo info; sprintf(dn, "%d:%d", d->disk.major, d->disk.minor); @@ -687,8 +730,11 @@ static int count_active(struct supertype *st, struct mdinfo *sra, close(dfd); if (ok != 0) continue; + info.array.raid_disks = raid_disks; st->ss->getinfo_super(st, &info, devmap + raid_disks * devnum); + if (info.disk.raid_disk == MD_DISK_ROLE_JOURNAL) + bestinfo->journal_clean = 1; if (!avail) { raid_disks = info.array.raid_disks; avail = xcalloc(raid_disks, 1); @@ -738,6 +784,7 @@ static int count_active(struct supertype *st, struct mdinfo *sra, replcnt++; st->ss->free_super(st); } + if (!avail) return 0; /* We need to reject any device that thinks the best device is @@ -760,6 +807,14 @@ static int count_active(struct supertype *st, struct mdinfo *sra, if (avail[i]) cnt++; } + /* Also need to reject any spare device with an event count that + * is too high + */ + for (d = sra->devs; d; d = d->next) { + if (!(d->disk.state & (1<events > max_events) + d->disk.state |= (1 << MD_DISK_REMOVED); + } free(best); free(devmap); return cnt + replcnt; @@ -823,8 +878,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, */ if (map_lock(&map)) { - pr_err("failed to get exclusive lock on " - "mapfile\n"); + pr_err("failed to get exclusive lock on mapfile\n"); return 1; } for (mp = map ; mp ; mp = mp->next) { @@ -870,8 +924,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, sra->text_version); if (!st2) { if (verbose > 1) - pr_err("not adding %s to %s" - " as metadata not recognised.\n", + pr_err("not adding %s to %s as metadata not recognised.\n", devname, mp->path); goto next; } @@ -935,8 +988,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, sizeof(target->uuid)) == 0 && sra->array.failed_disks > 0) { /* This is our target!! */ - if (chosen) - sysfs_free(chosen); + sysfs_free(chosen); chosen = sra; sra = NULL; /* skip to end so we don't check any more */ @@ -953,8 +1005,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, if (domain_test(dl, pol, st2->ss->name) != 1) { /* domain test fails */ if (verbose > 1) - pr_err("not adding %s to %s as" - " it is not in a compatible domain\n", + pr_err("not adding %s to %s as it is not in a compatible domain\n", devname, mp->path); goto next; @@ -969,8 +1020,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, sra = NULL; } next: - if (sra) - sysfs_free(sra); + sysfs_free(sra); if (st != st2) free(st2); if (dl) @@ -981,12 +1031,13 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, int mdfd = open_dev(chosen->sys_name); if (mdfd >= 0) { struct mddev_dev devlist; - char devname[20]; + char chosen_devname[24]; // 2*11 for int (including signs) + colon + null devlist.next = NULL; devlist.used = 0; devlist.writemostly = 0; - devlist.devname = devname; - sprintf(devname, "%d:%d", major(stb.st_rdev), + devlist.failfast = 0; + devlist.devname = chosen_devname; + sprintf(chosen_devname, "%d:%d", major(stb.st_rdev), minor(stb.st_rdev)); devlist.disposition = 'a'; close(dfd); @@ -1091,6 +1142,7 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol, if (st2 == NULL || st2->ss->load_super(st2, fd, NULL) < 0) goto next; + st2->ignore_hw_compat = 0; if (!st) { /* Check domain policy again, this time referring to metadata */ @@ -1226,8 +1278,7 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol, !policy_action_allows(pol, st?st->ss->name:NULL, act_spare_same_slot)) { if (verbose > 1) - pr_err("%s is not bare, so not " - "considering as a spare\n", + pr_err("%s is not bare, so not considering as a spare\n", devname); return 1; } @@ -1270,7 +1321,7 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol, return rv; } -int IncrementalScan(int verbose) +int IncrementalScan(struct context *c, char *devnm) { /* look at every device listed in the 'map' file. * If one is found that is not running then: @@ -1282,18 +1333,60 @@ int IncrementalScan(int verbose) struct map_ent *me; struct mddev_ident *devs, *mddev; int rv = 0; + char container[32]; + char *only = NULL; map_read(&mapl); devs = conf_get_ident(NULL); +restart: for (me = mapl ; me ; me = me->next) { mdu_array_info_t array; mdu_bitmap_file_t bmf; struct mdinfo *sra; - int mdfd = open_dev(me->devnm); + int mdfd; + + if (devnm && strcmp(devnm, me->devnm) != 0) + continue; + if (me->metadata[0] == '/') { + char *sl; + + if (!devnm) + continue; + + /* member array, need to work on container */ + strncpy(container, me->metadata+1, 32); + container[31] = 0; + sl = strchr(container, '/'); + if (sl) + *sl = 0; + only = devnm; + devnm = container; + goto restart; + } + mdfd = open_dev(me->devnm); if (mdfd < 0) continue; + if (!isdigit(me->metadata[0])) { + /* must be a container */ + struct supertype *st = super_by_fd(mdfd, NULL); + int ret = 0; + struct map_ent *map = NULL; + + if (st && st->ss->load_container) + ret = st->ss->load_container(st, mdfd, NULL); + close(mdfd); + if (!ret && st && st->ss->container_content) { + if (map_lock(&map)) + pr_err("failed to get exclusive lock on mapfile\n"); + ret = Incremental_container(st, me->path, c, only); + map_unlock(&map); + } + if (ret) + rv = 1; + continue; + } if (ioctl(mdfd, GET_ARRAY_INFO, &array) == 0 || errno != ENODEV) { close(mdfd); @@ -1318,7 +1411,7 @@ int IncrementalScan(int verbose) close(bmfd); } } - if (verbose >= 0) { + if (c->verbose >= 0) { if (added == 0) pr_err("Added bitmap %s to %s\n", mddev->bitmap_file, me->path); @@ -1334,7 +1427,7 @@ int IncrementalScan(int verbose) if (sra) { if (sysfs_set_str(sra, NULL, "array_state", "read-auto") == 0) { - if (verbose >= 0) + if (c->verbose >= 0) pr_err("started array %s\n", me->path ?: me->devnm); } else { @@ -1375,7 +1468,7 @@ static char *container2devname(char *devname) } static int Incremental_container(struct supertype *st, char *devname, - struct context *c) + struct context *c, char *only) { /* Collect the contents of this container and for each * array, choose a device name and assemble the array. @@ -1394,6 +1487,7 @@ static int Incremental_container(struct supertype *st, char *devname, int sfd; int ra_blocked = 0; int ra_all = 0; + int result = 0; st->ss->getinfo_super(st, &info, NULL); @@ -1401,7 +1495,9 @@ static int Incremental_container(struct supertype *st, char *devname, info.container_enough > 0) /* pass */; else { - if (c->verbose) + if (c->export) { + printf("MD_STARTED=no\n"); + } else if (c->verbose) pr_err("not enough devices to start the container\n"); return 0; } @@ -1422,8 +1518,12 @@ static int Incremental_container(struct supertype *st, char *devname, list = st->ss->container_content(st, NULL); /* when nothing to activate - quit */ - if (list == NULL) + if (list == NULL) { + if (c->export) { + printf("MD_STARTED=nothing\n"); + } return 0; + } for (ra = list ; ra ; ra = ra->next) { int mdfd; char chosen_name[1024]; @@ -1446,7 +1546,7 @@ static int Incremental_container(struct supertype *st, char *devname, strcpy(chosen_name, mp->path); else strcpy(chosen_name, mp->devnm); - } else { + } else if (!only) { /* Check in mdadm.conf for container == devname and * member == ra->text_version after second slash. @@ -1489,10 +1589,9 @@ static int Incremental_container(struct supertype *st, char *devname, if (match && match->devname && strcasecmp(match->devname, "") == 0) { if (c->verbose > 0) - pr_err("array %s/%s is " - "explicitly ignored by mdadm.conf\n", + pr_err("array %s/%s is explicitly ignored by mdadm.conf\n", match->container, match->member); - return 2; + continue; } if (match) trustworthy = LOCAL; @@ -1503,6 +1602,8 @@ static int Incremental_container(struct supertype *st, char *devname, trustworthy, chosen_name); } + if (only && (!mp || strcmp(mp->devnm, only) != 0)) + continue; if (mdfd < 0) { pr_err("failed to open %s: %s.\n", @@ -1511,9 +1612,30 @@ static int Incremental_container(struct supertype *st, char *devname, } assemble_container_content(st, mdfd, ra, c, - chosen_name); + chosen_name, &result); close(mdfd); } + if (c->export && result) { + char sep = '='; + printf("MD_STARTED"); + if (result & INCR_NO) { + printf("%cno", sep); + sep = ','; + } + if (result & INCR_UNSAFE) { + printf("%cunsafe", sep); + sep = ','; + } + if (result & INCR_ALREADY) { + printf("%calready", sep); + sep = ','; + } + if (result & INCR_YES) { + printf("%cyes", sep); + sep = ','; + } + printf("\n"); + } /* don't move spares to container with volume being activated when all volumes are blocked */ @@ -1600,32 +1722,34 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) char buf[32]; if (!id_path) - dprintf(Name ": incremental removal without --path " - "lacks the possibility to re-add new device in this " - "port\n"); + dprintf("incremental removal without --path lacks the possibility to re-add new device in this port\n"); if (strchr(devname, '/')) { - pr_err("incremental removal requires a " - "kernel device name, not a file: %s\n", devname); + pr_err("incremental removal requires a kernel device name, not a file: %s\n", devname); return 1; } ent = mdstat_by_component(devname); if (!ent) { - pr_err("%s does not appear to be a component " - "of any array\n", devname); + if (verbose >= 0) + pr_err("%s does not appear to be a component of any array\n", devname); return 1; } sysfs_init(&mdi, -1, ent->devnm); - if (sysfs_get_str(&mdi, NULL, "array_state", - buf, sizeof(buf)) > 0) { - if (strncmp(buf, "active", 6) == 0 || - strncmp(buf, "clean", 5) == 0) - sysfs_set_str(&mdi, NULL, - "array_state", "read-auto"); + mdfd = open_dev_excl(ent->devnm); + if (mdfd > 0) { + close(mdfd); + if (sysfs_get_str(&mdi, NULL, "array_state", + buf, sizeof(buf)) > 0) { + if (strncmp(buf, "active", 6) == 0 || + strncmp(buf, "clean", 5) == 0) + sysfs_set_str(&mdi, NULL, + "array_state", "read-auto"); + } } mdfd = open_dev(ent->devnm); if (mdfd < 0) { - pr_err("Cannot open array %s!!\n", ent->dev); + if (verbose >= 0) + pr_err("Cannot open array %s!!\n", ent->devnm); free_mdstat(ent); return 1; } @@ -1647,11 +1771,11 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) struct mdstat_ent *mdstat = mdstat_read(0, 0); struct mdstat_ent *memb; for (memb = mdstat ; memb ; memb = memb->next) - if (is_container_member(memb, ent->dev)) { + if (is_container_member(memb, ent->devnm)) { int subfd = open_dev(memb->devnm); if (subfd >= 0) { rv |= Manage_subdevs( - memb->dev, subfd, + memb->devnm, subfd, &devlist, verbose, 0, NULL, 0); close(subfd); @@ -1659,7 +1783,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) } free_mdstat(mdstat); } else - rv |= Manage_subdevs(ent->dev, mdfd, &devlist, + rv |= Manage_subdevs(ent->devnm, mdfd, &devlist, verbose, 0, NULL, 0); if (rv & 2) { /* Failed due to EBUSY, try to stop the array. @@ -1667,8 +1791,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) */ int devid = devnm2devid(ent->devnm); run_udisks("--unmount", map_dev(major(devid),minor(devid), 0)); - rv = Manage_runstop(ent->dev, mdfd, -1, - verbose, 1); + rv = Manage_stop(ent->devnm, mdfd, verbose, 1); if (rv) /* At least we can try to trigger a 'remove' */ sysfs_uevent(&mdi, "remove"); @@ -1678,7 +1801,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) } } else { devlist.disposition = 'r'; - rv = Manage_subdevs(ent->dev, mdfd, &devlist, + rv = Manage_subdevs(ent->devnm, mdfd, &devlist, verbose, 0, NULL, 0); } close(mdfd);