X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=mdadm.c;h=74a39a88584b9bf4ac9885d9b21f534f8d8175f2;hp=b2ec6f904163203252935898257e17147184c908;hb=1e5c69836d4d0b6dcaef8fc187e6bf2841eb57f6;hpb=fe056d1fb0b1d08c614f574cceaa640abc382544 diff --git a/mdadm.c b/mdadm.c index b2ec6f90..74a39a88 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; @@ -91,8 +88,10 @@ int main(int argc, char *argv[]) char *homehost = NULL; char sys_hostname[256]; + int require_homehost = 1; char *mailaddr = NULL; char *program = NULL; + int increments = 20; int delay = 0; int daemonise = 0; char *pidfile = NULL; @@ -105,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; @@ -132,7 +130,7 @@ int main(int argc, char *argv[]) shortopt, long_options, &option_index)) != -1) { int newmode = mode; - /* firstly, some mode-independant options */ + /* firstly, some mode-independent options */ switch(opt) { case 'h': if (option_index > 0 && @@ -166,7 +164,10 @@ int main(int argc, char *argv[]) continue; case HomeHost: - homehost = optarg; + if (strcasecmp(optarg, "") == 0) + require_homehost = 0; + else + homehost = optarg; continue; case ':': @@ -217,6 +218,7 @@ int main(int argc, char *argv[]) case 'w': case 'W': case Waitclean: + case DetailPlatform: case 'K': if (!mode) newmode = MISC; break; } if (mode && newmode == mode) { @@ -256,6 +258,7 @@ int main(int argc, char *argv[]) dv->writemostly = writemostly; dv->re_add = re_add; dv->used = 0; + dv->content = NULL; dv->next = NULL; *devlistend = dv; devlistend = &dv->next; @@ -308,6 +311,8 @@ int main(int argc, char *argv[]) dv->disposition = devmode; dv->writemostly = writemostly; dv->re_add = re_add; + dv->used = 0; + dv->content = NULL; dv->next = NULL; *devlistend = dv; devlistend = &dv->next; @@ -320,6 +325,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) { @@ -335,9 +341,11 @@ int main(int argc, char *argv[]) } continue; +#if 0 case O(ASSEMBLE,AutoHomeHost): auto_update_home = 1; continue; +#endif case O(INCREMENTAL, 'e'): case O(CREATE,'e'): case O(ASSEMBLE,'e'): @@ -370,7 +378,8 @@ int main(int argc, char *argv[]) case O(GROW,'z'): - case O(CREATE,'z'): /* size */ + case O(CREATE,'z'): + case O(BUILD,'z'): /* size */ if (size >= 0) { fprintf(stderr, Name ": size may only be specified once. " "Second value is %s.\n", optarg); @@ -379,16 +388,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) { @@ -402,7 +431,10 @@ int main(int argc, char *argv[]) optarg); exit(2); } - if (level != 0 && level != -1 && level != 1 && level != -4 && level != -5 && mode == BUILD) { + if (level != 0 && level != LEVEL_LINEAR && level != 1 && + level != LEVEL_MULTIPATH && level != LEVEL_FAULTY && + level != 10 && + mode == BUILD) { fprintf(stderr, Name ": Raid level %s not permitted with --build.\n", optarg); exit(2); @@ -415,9 +447,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); @@ -433,7 +474,6 @@ int main(int argc, char *argv[]) exit(2); case 5: - case 6: layout = map_name(r5layout, optarg); if (layout==UnSet) { fprintf(stderr, Name ": layout %s not understood for raid5.\n", @@ -441,40 +481,33 @@ int main(int argc, char *argv[]) exit(2); } break; + case 6: + layout = map_name(r6layout, optarg); + if (layout==UnSet) { + fprintf(stderr, Name ": layout %s not understood for raid6.\n", + optarg); + exit(2); + } + 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; @@ -640,6 +673,7 @@ int main(int argc, char *argv[]) " 'summaries', 'homehost', 'byteorder', 'devicesize'.\n"); exit(outf == stdout ? 0 : 2); + case O(INCREMENTAL,NoDegraded): case O(ASSEMBLE,NoDegraded): /* --no-degraded */ runstop = -1; /* --stop isn't allowed for --assemble, * so we overload slightly */ @@ -681,6 +715,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 */ @@ -766,6 +808,7 @@ int main(int argc, char *argv[]) case O(MISC,'w'): case O(MISC,'W'): case O(MISC, Waitclean): + case O(MISC, DetailPlatform): if (devmode && devmode != opt && (devmode == 'E' || (opt == 'E' && devmode != 'Q'))) { fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n", @@ -996,8 +1039,8 @@ int main(int argc, char *argv[]) } if (homehost == NULL) - homehost = conf_get_homehost(); - if (homehost && strcmp(homehost, "")==0) { + homehost = conf_get_homehost(&require_homehost); + if (homehost == NULL || strcmp(homehost, "")==0) { if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { sys_hostname[sizeof(sys_hostname)-1] = 0; homehost = sys_hostname; @@ -1036,12 +1079,16 @@ int main(int argc, char *argv[]) array_ident->autof = autof; rv |= Assemble(ss, devlist->devname, array_ident, NULL, backup_file, - readonly, runstop, update, homehost, verbose-quiet, force); + readonly, runstop, update, + homehost, require_homehost, + verbose-quiet, force); } } else if (!scan) rv = Assemble(ss, devlist->devname, &ident, devlist->next, backup_file, - readonly, runstop, update, homehost, verbose-quiet, force); + readonly, runstop, update, + homehost, require_homehost, + verbose-quiet, force); else if (devs_found>0) { if (update && devs_found > 1) { fprintf(stderr, Name ": can only update a single array at a time\n"); @@ -1063,7 +1110,9 @@ int main(int argc, char *argv[]) array_ident->autof = autof; rv |= Assemble(ss, dv->devname, array_ident, NULL, backup_file, - readonly, runstop, update, homehost, verbose-quiet, force); + readonly, runstop, update, + homehost, require_homehost, + verbose-quiet, force); } } else { mddev_ident_t array_list = conf_get_ident(NULL); @@ -1082,16 +1131,21 @@ int main(int argc, char *argv[]) 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; rv |= Assemble(ss, array_list->devname, array_list, NULL, NULL, - readonly, runstop, NULL, homehost, verbose-quiet, force); - if (rv == 0) cnt++; + readonly, runstop, NULL, + homehost, require_homehost, + verbose-quiet, force); + cnt++; } - if (homehost) { + if (homehost && cnt == 0) { /* Maybe we can auto-assemble something. * Repeatedly call Assemble in auto-assemble mode * until it fails @@ -1106,7 +1160,9 @@ int main(int argc, char *argv[]) rv2 = Assemble(ss, NULL, &ident, devlist, NULL, - readonly, runstop, NULL, homehost, verbose-quiet, force); + readonly, runstop, NULL, + homehost, require_homehost, + verbose-quiet, force); if (rv2==0) { cnt++; acnt++; @@ -1119,6 +1175,7 @@ int main(int argc, char *argv[]) } while (rv2!=2); /* Incase there are stacked devices, we need to go around again */ } while (acnt); +#if 0 if (cnt == 0 && auto_update_home && homehost) { /* Nothing found, maybe we need to bootstrap homehost info */ do { @@ -1127,7 +1184,9 @@ int main(int argc, char *argv[]) rv2 = Assemble(ss, NULL, &ident, NULL, NULL, - readonly, runstop, "homehost", homehost, verbose-quiet, force); + readonly, runstop, "homehost", + homehost, require_homehost, + verbose-quiet, force); if (rv2==0) { cnt++; acnt++; @@ -1136,6 +1195,7 @@ int main(int argc, char *argv[]) /* Incase there are stacked devices, we need to go around again */ } while (acnt); } +#endif if (cnt == 0 && rv == 0) { fprintf(stderr, Name ": No arrays found in config file or automatically\n"); rv = 1; @@ -1170,7 +1230,7 @@ int main(int argc, char *argv[]) rv = Build(devlist->devname, chunk, level, layout, raiddisks, devlist->next, assume_clean, bitmap_file, bitmap_chunk, write_behind, - delay, verbose-quiet, autof); + delay, verbose-quiet, autof, size); break; case CREATE: if (delay == 0) delay = DEFAULT_BITMAP_DELAY; @@ -1208,24 +1268,51 @@ int main(int argc, char *argv[]) rv = Examine(devlist, scan?(verbose>1?0:verbose+1):brief, export, scan, SparcAdjust, ss, homehost); + } else if (devmode == DetailPlatform) { + rv = Detail_Platform(ss ? ss->ss : NULL, ss ? scan : 1, verbose); } else { if (devlist == NULL) { - if (devmode=='D' && scan) { - /* apply --detail to all devices in /proc/mdstat */ + if ((devmode=='D' || devmode == Waitclean) && scan) { + /* apply --detail or --wait-clean to + * all devices in /proc/mdstat + */ 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 = get_md_name(e->devnum); + 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) + name = me->path; + else + name = get_md_name(e->devnum); if (!name) { fprintf(stderr, Name ": cannot find device file for %s\n", e->dev); continue; } - rv |= Detail(name, verbose>1?0:verbose+1, - export, test, homehost); + if (devmode == 'D') + rv |= Detail(name, v, + export, test, + homehost); + else + 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 */ /* Due to possible stacking of devices, repeat until @@ -1258,6 +1345,7 @@ int main(int argc, char *argv[]) put_md_name(name); } + free_mdstat(ms); } while (!last && err); if (err) rv |= 1; } else { @@ -1273,7 +1361,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 & 2) == 0); + rv &= ~2; + } continue; case 'Q': rv |= Query(dv->devname); continue; @@ -1282,7 +1379,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) { @@ -1313,17 +1410,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; } @@ -1332,20 +1467,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: @@ -1375,7 +1511,7 @@ int main(int argc, char *argv[]) break; } rv = Incremental(devlist->devname, verbose-quiet, runstop, - ss, homehost, autof); + ss, homehost, require_homehost, autof); break; case AUTODETECT: autodetect();