X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=mdadm.c;h=d5e34c074c034f99d289124422ab38d944e8feee;hb=e259df4e63f553c1271fa7d7612c110d2518e572;hp=0478ce96a1b099bb2a0caaa88014716053f7ca95;hpb=e0fe762a63889495695b773ad63d329a526fa4ed;p=thirdparty%2Fmdadm.git diff --git a/mdadm.c b/mdadm.c index 0478ce96..d5e34c07 100644 --- a/mdadm.c +++ b/mdadm.c @@ -1,7 +1,7 @@ /* * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2001-2006 Neil Brown + * Copyright (C) 2001-2009 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -19,12 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Neil Brown - * Email: - * Paper: Neil Brown - * School of Computer Science and Engineering - * The University of New South Wales - * Sydney, 2052 - * Australia + * Email: * * Additions for bitmap and write-behind RAID options, Copyright (C) 2003-2004, * Paul Clements, SteelEye Technology, Inc. @@ -46,8 +41,10 @@ int main(int argc, char *argv[]) int chunk = 0; long long size = -1; + long long array_size = -1; int level = UnSet; int layout = UnSet; + char *layout_str = NULL; int raiddisks = 0; int max_disks = MD_SB_DISKS; /* just a default */ int sparedisks = 0; @@ -94,6 +91,7 @@ int main(int argc, char *argv[]) int require_homehost = 1; char *mailaddr = NULL; char *program = NULL; + int increments = 20; int delay = 0; int daemonise = 0; char *pidfile = NULL; @@ -106,7 +104,6 @@ int main(int argc, char *argv[]) int rebuild_map = 0; int auto_update_home = 0; - int copies; int print_help = 0; FILE *outf; @@ -154,13 +151,10 @@ int main(int argc, char *argv[]) continue; case 'b': - if (mode == ASSEMBLE || mode == BUILD || mode == CREATE || mode == GROW) + if (mode == ASSEMBLE || mode == BUILD || mode == CREATE || mode == GROW || + mode == INCREMENTAL || mode == MANAGE) break; /* b means bitmap */ brief = 1; - if (optarg) { - fprintf(stderr, Name ": -b cannot have any extra immediately after it, sorry.\n"); - exit(2); - } continue; case 'Y': export++; @@ -270,7 +264,8 @@ int main(int argc, char *argv[]) continue; } /* No mode yet, and this is the second device ... */ - fprintf(stderr, Name ": An option must be given to set the mode before a second device is listed\n"); + fprintf(stderr, Name ": An option must be given to set the mode before a second device\n" + " (%s) is listed\n", optarg); exit(2); } if (option_index >= 0) @@ -328,6 +323,7 @@ int main(int argc, char *argv[]) * could depend on the mode */ #define O(a,b) ((a<<8)|b) switch (O(mode,opt)) { + case O(GROW,'c'): case O(CREATE,'c'): case O(BUILD,'c'): /* chunk or rounding */ if (chunk) { @@ -390,16 +386,36 @@ int main(int argc, char *argv[]) if (strcmp(optarg, "max")==0) size = 0; else { - size = strtoll(optarg, &c, 10); - if (!optarg[0] || *c || size < 4) { + size = parse_size(optarg); + if (size < 8) { fprintf(stderr, Name ": invalid size: %s\n", optarg); exit(2); } + /* convert sectors to K */ + size /= 2; } continue; - case O(GROW,'l'): /* hack - needed to understand layout */ + case O(GROW,'Z'): /* array size */ + if (array_size >= 0) { + fprintf(stderr, Name ": array-size may only be specified once. " + "Second value is %s.\n", optarg); + exit(2); + } + if (strcmp(optarg, "max") == 0) + array_size = 0; + else { + array_size = parse_size(optarg); + if (array_size <= 0) { + fprintf(stderr, Name ": invalid array size: %s\n", + optarg); + exit(2); + } + } + continue; + + case O(GROW,'l'): case O(CREATE,'l'): case O(BUILD,'l'): /* set raid level*/ if (level != UnSet) { @@ -429,9 +445,18 @@ int main(int argc, char *argv[]) ident.level = level; continue; + case O(GROW, 'p'): /* new layout */ + if (layout_str) { + fprintf(stderr,Name ": layout may only be sent once. " + "Second value was %s\n", optarg); + exit(2); + } + layout_str = optarg; + /* 'Grow' will parse the value */ + continue; + case O(CREATE,'p'): /* raid5 layout */ case O(BUILD,'p'): /* faulty layout */ - case O(GROW, 'p'): /* faulty reconfig */ if (layout != UnSet) { fprintf(stderr,Name ": layout may only be sent once. " "Second value was %s\n", optarg); @@ -464,38 +489,23 @@ int main(int argc, char *argv[]) break; case 10: - /* 'f', 'o' or 'n' followed by a number <= raid_disks */ - if ((optarg[0] != 'n' && optarg[0] != 'f' && optarg[0] != 'o') || - (copies = strtoul(optarg+1, &cp, 10)) < 1 || - copies > 200 || - *cp) { + layout = parse_layout_10(optarg); + if (layout < 0) { fprintf(stderr, Name ": layout for raid10 must be 'nNN', 'oNN' or 'fNN' where NN is a number, not %s\n", optarg); exit(2); } - if (optarg[0] == 'n') - layout = 256 + copies; - else if (optarg[0] == 'o') - layout = 0x10000 + (copies<<8) + 1; - else - layout = 1 + (copies<<8); break; - case -5: /* Faulty - * modeNNN - */ - - { - int ln = strcspn(optarg, "0123456789"); - char *m = strdup(optarg); - int mode; - m[ln] = 0; - mode = map_name(faultylayout, m); - if (mode == UnSet) { + case LEVEL_FAULTY: + /* Faulty + * modeNNN + */ + layout = parse_layout_faulty(optarg); + if (layout == -1) { fprintf(stderr, Name ": layout %s not understood for faulty.\n", optarg); exit(2); } - layout = mode | (atoi(optarg+ln)<< ModeShift); - } + break; } continue; @@ -703,6 +713,14 @@ int main(int argc, char *argv[]) program = optarg; continue; + case O(MONITOR,'r'): /* rebuild increments */ + increments = atoi(optarg); + if (increments>99 || increments<1) { + fprintf(stderr, Name ": please specify positive integer between 1 and 99 as rebuild increments.\n"); + exit(2); + } + continue; + case O(MONITOR,'d'): /* delay in seconds */ case O(GROW, 'd'): case O(BUILD,'d'): /* delay for bitmap updates */ @@ -854,7 +872,8 @@ int main(int argc, char *argv[]) continue; } /* probable typo */ - fprintf(stderr, Name ": bitmap file must contain a '/', or be 'internal', or 'none'\n"); + fprintf(stderr, Name ": bitmap file must contain a '/', or be 'internal', or 'none'\n" + " not '%s'\n", optarg); exit(2); case O(GROW,BitmapChunk): @@ -1027,6 +1046,12 @@ int main(int argc, char *argv[]) } } + if ((mode != MISC || devmode != 'E') && + geteuid() != 0) { + fprintf(stderr, Name ": must be super-user to perform this action\n"); + exit(1); + } + ident.autof = autof; rv = 0; @@ -1095,9 +1120,10 @@ int main(int argc, char *argv[]) verbose-quiet, force); } } else { - mddev_ident_t array_list = conf_get_ident(NULL); + mddev_ident_t a, array_list = conf_get_ident(NULL); mddev_dev_t devlist = conf_get_devs(); int cnt = 0; + int failures, successes; if (devlist == NULL) { fprintf(stderr, Name ": No devices listed in conf file were found.\n"); exit(1); @@ -1110,21 +1136,38 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": --backup_file not meaningful with a --scan assembly.\n"); exit(1); } - for (; array_list; array_list = array_list->next) { - if (array_list->devname && - strcasecmp(array_list->devname, "") == 0) - continue; - if (array_list->autof == 0) - array_list->autof = autof; + for (a = array_list; a ; a = a->next) { + a->assembled = 0; + if (a->autof == 0) + a->autof = autof; + } + do { + failures = 0; + successes = 0; + rv = 0; + for (a = array_list; a ; a = a->next) { + int r; + if (a->assembled) + continue; + if (a->devname && + strcasecmp(a->devname, "") == 0) + continue; - rv |= Assemble(ss, array_list->devname, - array_list, - NULL, NULL, - readonly, runstop, NULL, - homehost, require_homehost, - verbose-quiet, force); - cnt++; - } + r = Assemble(ss, a->devname, + a, + NULL, NULL, + readonly, runstop, NULL, + homehost, require_homehost, + verbose-quiet, force); + if (r == 0) { + a->assembled = 1; + successes++; + } else + failures++; + rv |= r; + cnt++; + } + } while (failures && successes); if (homehost && cnt == 0) { /* Maybe we can auto-assemble something. * Repeatedly call Assemble in auto-assemble mode @@ -1259,11 +1302,18 @@ int main(int argc, char *argv[]) struct mdstat_ent *ms = mdstat_read(0, 1); struct mdstat_ent *e; struct map_ent *map = NULL; + int members; int v = verbose>1?0:verbose+1; + for (members = 0; members <= 1; members++) { for (e=ms ; e ; e=e->next) { char *name; struct map_ent *me; + int member = e->metadata_version && + strncmp(e->metadata_version, + "external:/", 10) == 0; + if (members != member) + continue; me = map_by_devnum(&map, e->devnum); if (me && me->path && strcmp(me->path, "/unknown") != 0) @@ -1281,9 +1331,10 @@ int main(int argc, char *argv[]) export, test, homehost); else - rv |= WaitClean(name, v); + rv |= WaitClean(name, -1, v); put_md_name(name); } + } free_mdstat(ms); } else if (devmode == 'S' && scan) { /* apply --stop to all devices in /proc/mdstat */ @@ -1333,7 +1384,16 @@ int main(int argc, char *argv[]) export, test, homehost); continue; case 'K': /* Zero superblock */ - rv |= Kill(dv->devname, force, quiet,0); + if (ss) + rv |= Kill(dv->devname, ss, force, quiet,0); + else { + int q = quiet; + do { + rv |= Kill(dv->devname, NULL, force, q, 0); + q = 1; + } while (rv == 0); + rv &= ~2; + } continue; case 'Q': rv |= Query(dv->devname); continue; @@ -1342,7 +1402,7 @@ int main(int argc, char *argv[]) case 'W': rv |= Wait(dv->devname); continue; case Waitclean: - rv |= WaitClean(dv->devname, verbose-quiet); continue; + rv |= WaitClean(dv->devname, -1, verbose-quiet); continue; } mdfd = open_mddev(dv->devname, 1); if (mdfd>=0) { @@ -1373,17 +1433,55 @@ int main(int argc, char *argv[]) rv = 1; break; } + if (delay == 0) { + if (get_linux_version() > 20616) + /* mdstat responds to poll */ + delay = 1000; + else + delay = 60; + } rv= Monitor(devlist, mailaddr, program, delay?delay:60, daemonise, scan, oneshot, - dosyslog, test, pidfile); + dosyslog, test, pidfile, increments); break; case GROW: + if (array_size >= 0) { + /* alway impose array size first, independent of + * anything else + * Do not allow level or raid_disks changes at the + * same time as that can be irreversibly destructive. + */ + struct mdinfo sra; + int err; + if (raiddisks || level != UnSet) { + fprintf(stderr, Name ": cannot change array size in same operation " + "as changing raiddisks or level.\n" + " Change size first, then check that data is still intact.\n"); + rv = 1; + break; + } + sysfs_init(&sra, mdfd, 0); + if (array_size == 0) + err = sysfs_set_str(&sra, NULL, "array_size", "default"); + else + err = sysfs_set_num(&sra, NULL, "array_size", array_size / 2); + if (err < 0) { + if (errno == E2BIG) + fprintf(stderr, Name ": --array-size setting" + " is too large.\n"); + else + fprintf(stderr, Name ": current kernel does" + " not support setting --array-size\n"); + rv = 1; + break; + } + } if (devs_found > 1) { /* must be '-a'. */ - if (size >= 0 || raiddisks) { - fprintf(stderr, Name ": --size, --raiddisks, and --add are exclusing in --grow mode\n"); + if (size >= 0 || raiddisks || chunk || layout_str != NULL || bitmap_file) { + fprintf(stderr, Name ": --add cannot be used with other geometry changes in --grow mode\n"); rv = 1; break; } @@ -1392,20 +1490,21 @@ int main(int argc, char *argv[]) if (rv) break; } - } else if ((size >= 0) + (raiddisks != 0) + (layout != UnSet) + (bitmap_file != NULL)> 1) { - fprintf(stderr, Name ": can change at most one of size, raiddisks, bitmap, and layout\n"); - rv = 1; - break; - } else if (layout != UnSet) - rv = Manage_reconfig(devlist->devname, mdfd, layout); - else if (size >= 0 || raiddisks) - rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file, - size, level, layout, chunk, raiddisks); - else if (bitmap_file) { - if (delay == 0) delay = DEFAULT_BITMAP_DELAY; + } else if (bitmap_file) { + if (size >= 0 || raiddisks || chunk || layout_str != NULL) { + fprintf(stderr, Name ": --bitmap changes cannot be used with other geometry changes in --grow mode\n"); + rv = 1; + break; + } + if (delay == 0) + delay = DEFAULT_BITMAP_DELAY; rv = Grow_addbitmap(devlist->devname, mdfd, bitmap_file, bitmap_chunk, delay, write_behind, force); - } else + } else if (size >= 0 || raiddisks != 0 || layout_str != NULL + || chunk != 0 || level != UnSet) { + rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file, + size, level, layout_str, chunk, raiddisks); + } else if (array_size < 0) fprintf(stderr, Name ": no changes to --grow\n"); break; case INCREMENTAL: