diff --git a/ANNOUNCE-1.7.0 b/ANNOUNCE-1.7.0 new file mode 100644 index 0000000..86c4aac --- /dev/null +++ b/ANNOUNCE-1.7.0 @@ -0,0 +1,46 @@ +Subject: ANNOUNCE: mdadm 1.7.0 - A tool for managing Soft RAID under Linux + + +I am pleased to announce the availability of + mdadm version 1.7.0 +It is available at + http://www.cse.unsw.edu.au/~neilb/source/mdadm/ +and + http://www.{countrycode}.kernel.org/pub/linux/utils/raid/mdadm/ + +as a source tar-ball and (at the first site) as an SRPM, and as an RPM for i386. + +mdadm is a tool for creating, managing and monitoring +device arrays using the "md" driver in Linux, also +known as Software RAID arrays. + +Release 1.7.0 adds: + - Support "--grow --add" to add a device to a linear array, if the + kernel supports it. Not documented yet. + - Restore support for uclibc which was broken recently. + - Several improvements to the output of --detail, including + reporting "resyncing" or "recovering" in the state. + - Close filedescriptor at end of --detail (exit would have closed it + anyway, so this isn't abig deal). + - Report "Sync checkpoint" in --examine output if appropriate. + - Add --update=resync for --assemble mode to for a resync when the + array is assembled. + - Add support for "raid10", which is under development in 2.6. + Not documented yet. + - --monitor now reads spare-group and spares info from config file + even when names of arrays to scan are given on the command line + +It is expected that the next full release of mdadm will be 2.0.0 +and it will have substantially re-written handling for superblocks and +array creation. In particular, it will be able to work with the new +superblock format (version 1) supported by 2.6. +Prior to that, some point releases (1.7.1, 1.7.2 ...) may be released +so that the changes can be tested by interrested parties. + +Development of mdadm is sponsored by CSE@UNSW: + The School of Computer Science and Engineering +at + The University of New South Wales + +NeilBrown 11 August 2004 + diff --git a/Assemble.c b/Assemble.c index 0d22251..3f22ae9 100644 --- a/Assemble.c +++ b/Assemble.c @@ -320,6 +320,11 @@ int Assemble(char *mddev, int mdfd, } else if (i >= super.raid_disks && super.disks[i].number == 0) super.disks[i].state = 0; } + if (strcmp(update, "resync") == 0) { + /* make sure resync happens */ + super.state &= ~(1<>8)&255) > raiddisks) { + fprintf(stderr, Name ": that layout requires at least %d devices\n", + (layout&255) * ((layout>>8)&255)); + return 1; + } + switch(level) { case 4: case 5: + case 10: case 6: case 0: case -1: /* linear */ diff --git a/Detail.c b/Detail.c index 5028ae2..7655668 100644 --- a/Detail.c +++ b/Detail.c @@ -47,6 +47,9 @@ int Detail(char *dev, int brief, int test) char *devices = NULL; int spares = 0; struct stat stb; + int is_26 = get_linux_version() >= 2006000; + int is_rebuilding = 0; + int failed = 0; mdp_super_t super; int have_super = 0; @@ -83,6 +86,34 @@ int Detail(char *dev, int brief, int test) if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode)) stb.st_rdev = 0; rv = 0; + + /* try to load a superblock */ + for (d= 0; d= array.raid_disks && + disk.major == 0 && + disk.minor == 0) + continue; + if ((dv=map_dev(disk.major, disk.minor))) { + if (!have_super && (disk.state & (1<=0 && + load_super(fd2, &super) ==0 && + (unsigned long)super.ctime == (unsigned long)array.ctime && + (unsigned int)super.level == (unsigned int)array.level) + have_super = 1; + if (fd2 >= 0) close(fd2); + } + } + } + /* Ok, we have some info to print... */ c = map_num(pers, array.level); if (brief) @@ -132,7 +163,8 @@ int Detail(char *dev, int brief, int test) printf(" State : %s%s%s\n", (array.state&(1<percent >= 0) ? ", recovering": ""); + (!e || e->percent < 0) ? "" : + (e->resync) ? ", resyncing": ", recovering"); printf(" Active Devices : %d\n", array.active_disks); printf("Working Devices : %d\n", array.working_disks); printf(" Failed Devices : %d\n", array.failed_disks); @@ -142,24 +174,40 @@ int Detail(char *dev, int brief, int test) c = map_num(r5layout, array.layout); printf(" Layout : %s\n", c?c:"-unknown-"); } + if (array.level == 10) { + printf(" Layout : near=%d, far=%d\n", + array.layout&255, (array.layout>>8)&255); + } switch (array.level) { case 0: case 4: case 5: - printf(" Chunk Size : %dK\n", array.chunk_size/1024); + case 10: + case 6: + printf(" Chunk Size : %dK\n\n", array.chunk_size/1024); break; case -1: - printf(" Rounding : %dK\n", array.chunk_size/1024); + printf(" Rounding : %dK\n\n", array.chunk_size/1024); break; default: break; } - printf("\n"); - - if (e && e->percent >= 0) + if (e && e->percent >= 0) { printf(" Rebuild Status : %d%% complete\n\n", e->percent); + is_rebuilding = 1; + } free_mdstat(ms); + if (have_super) { + printf(" UUID : "); + if (super.minor_version >= 90) + printf("%08x:%08x:%08x:%08x", super.set_uuid0, super.set_uuid1, + super.set_uuid2, super.set_uuid3); + else + printf("%08x", super.set_uuid0); + printf("\n Events : %d.%d\n\n", super.events_hi, super.events_lo); + } + printf(" Number Major Minor RaidDevice State\n"); } for (d= 0; d= 0) + failed++; + } if (disk.state & (1<= 0) + printf(" rebuilding"); + } else if (is_rebuilding && failed) { + /* Taking a bit of a risk here, we remove the + * device from the array, and then put it back. + * If this fails, we are rebuilding + */ + int err = ioctl(fd, HOT_REMOVE_DISK, MKDEV(disk.major, disk.minor)); + if (err == 0) ioctl(fd, HOT_ADD_DISK, MKDEV(disk.major, disk.minor)); + if (err && errno == EBUSY) + printf(" rebuilding"); + } + } } + if (disk.state == 0) spares++; if (test && d < array.raid_disks && disk.state & (1<=0 && - load_super(fd, &super) ==0 && - (unsigned long)super.ctime == (unsigned long)array.ctime && - (unsigned int)super.level == (unsigned int)array.level) - have_super = 1; - } } if (!brief) printf("\n"); } if (spares && brief) printf(" spares=%d", spares); - if (have_super) { - if (brief) printf(" UUID="); - else printf(" UUID : "); + if (have_super && brief) { + printf(" UUID="); if (super.minor_version >= 90) printf("%08x:%08x:%08x:%08x", super.set_uuid0, super.set_uuid1, super.set_uuid2, super.set_uuid3); else printf("%08x", super.set_uuid0); - if (!brief) - printf("\n Events : %d.%d\n", super.events_hi, super.events_lo); } if (brief && devices) printf("\n devices=%s", devices); if (brief) printf("\n"); if (test && (rv&2)) rv &= ~1; + close(fd); return rv; } diff --git a/Examine.c b/Examine.c index 1f23745..7dec8d8 100644 --- a/Examine.c +++ b/Examine.c @@ -174,11 +174,20 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) printf (" --- adjusting superblock for 2.2/sparc compatability ---\n"); } printf(" Events : %d.%d\n", super.events_hi, super.events_lo); + if (super.events_hi == super.cp_events_hi && + super.events_lo == super.cp_events_lo && + super.recovery_cp > 0 && + (super.state & (1<>8) & 255); + switch(super.level) { case 0: case 4: @@ -209,6 +218,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) if ((dv=map_dev(dp->major, dp->minor))) printf(" %s", dv); printf("\n"); + if (d == -1) printf("\n"); } } if (SparcAdjust == 2) { diff --git a/Grow.c b/Grow.c new file mode 100644 index 0000000..82283bc --- /dev/null +++ b/Grow.c @@ -0,0 +1,192 @@ +/* + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001-2004 Neil Brown + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * 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 + */ +#include "mdadm.h" +#include "dlink.h" + +#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) +#error no endian defined +#endif +#include "md_u.h" +#include "md_p.h" + +int Grow_Add_device(char *devname, int fd, char *newdev) +{ + /* Add a device to an active array. + * Currently, just extend a linear array. + * This requires writing a new superblock on the + * new device, calling the kernel to add the device, + * and if that succeeds, update the superblock on + * all other devices. + * This means that we need to *find* all other devices. + */ + mdu_array_info_t array; + mdu_disk_info_t disk; + mdp_super_t super; + struct stat stb; + int nfd, fd2; + int d, nd; + + + if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) { + fprintf(stderr, Name ": cannot get array info for %s\n", devname); + return 1; + } + + if (array.level != -1) { + fprintf(stderr, Name ": can only add devices to linear arrays\n"); + return 1; + } + + nfd = open(newdev, O_RDWR|O_EXCL); + if (nfd < 0) { + fprintf(stderr, Name ": cannot open %s\n", newdev); + return 1; + } + fstat(nfd, &stb); + if ((stb.st_mode & S_IFMT) != S_IFBLK) { + fprintf(stderr, Name ": %s is not a block device!\n", newdev); + close(nfd); + return 1; + } + /* now check out all the devices and make sure we can read the superblock */ + for (d=0 ; d < array.raid_disks ; d++) { + mdu_disk_info_t disk; + char *dv; + + disk.number = d; + if (ioctl(fd, GET_DISK_INFO, &disk) < 0) { + fprintf(stderr, Name ": cannot get device detail for device %d\n", + d); + return 1; + } + dv = map_dev(disk.major, disk.minor); + if (!dv) { + fprintf(stderr, Name ": cannot find device file for device %d\n", + d); + return 1; + } + fd2 = open(dv, O_RDWR); + if (!fd2) { + fprintf(stderr, Name ": cannot open device file %s\n", dv); + return 1; + } + if (load_super(fd2, &super)) { + fprintf(stderr, Name ": cannot find super block on %s\n", dv); + close(fd2); + return 1; + } + close(fd2); + } + /* Ok, looks good. Lets update the superblock and write it out to + * newdev. + */ + + memset(&super.disks[d], 0, sizeof(super.disks[d])); + super.disks[d].number = d; + super.disks[d].major = MAJOR(stb.st_rdev); + super.disks[d].minor = MINOR(stb.st_rdev); + super.disks[d].raid_disk = d; + super.disks[d].state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + + super.this_disk = super.disks[d]; + super.sb_csum = calc_sb_csum(&super); + if (store_super(nfd, &super)) { + fprintf(stderr, Name ": Cannot store new superblock on %s\n", newdev); + close(nfd); + return 1; + } + disk.number = d; + disk.major = MAJOR(stb.st_rdev); + disk.minor = MINOR(stb.st_rdev); + disk.raid_disk = d; + disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + close(nfd); + if (ioctl(fd, ADD_NEW_DISK, &disk) != 0) { + fprintf(stderr, Name ": Cannot add new disk to this array\n"); + return 1; + } + /* Well, that seems to have worked. + * Now go through and update all superblocks + */ + + if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) { + fprintf(stderr, Name ": cannot get array info for %s\n", devname); + return 1; + } + + nd = d; + for (d=0 ; d < array.raid_disks ; d++) { + mdu_disk_info_t disk; + char *dv; + + disk.number = d; + if (ioctl(fd, GET_DISK_INFO, &disk) < 0) { + fprintf(stderr, Name ": cannot get device detail for device %d\n", + d); + return 1; + } + dv = map_dev(disk.major, disk.minor); + if (!dv) { + fprintf(stderr, Name ": cannot find device file for device %d\n", + d); + return 1; + } + fd2 = open(dv, O_RDWR); + if (fd2 < 0) { + fprintf(stderr, Name ": cannot open device file %s\n", dv); + return 1; + } + if (load_super(fd2, &super)) { + fprintf(stderr, Name ": cannot find super block on %s\n", dv); + close(fd); + return 1; + } + super.raid_disks = nd+1; + super.nr_disks = nd+1; + super.active_disks = nd+1; + super.working_disks = nd+1; + memset(&super.disks[nd], 0, sizeof(super.disks[nd])); + super.disks[nd].number = nd; + super.disks[nd].major = MAJOR(stb.st_rdev); + super.disks[nd].minor = MINOR(stb.st_rdev); + super.disks[nd].raid_disk = nd; + super.disks[nd].state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + + super.this_disk = super.disks[d]; + super.sb_csum = calc_sb_csum(&super); + if (store_super(fd2, &super)) { + fprintf(stderr, Name ": Cannot store new superblock on %s\n", dv); + close(fd2); + return 1; + } + close(fd2); + } + + return 0; +} diff --git a/Makefile b/Makefile index af2aa7c..a35c6f7 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ # define "CXFLAGS" to give extra flags to CC. # e.g. make CXFLAGS=-O to optimise TCC = tcc -UCLIBC_GCC = i386-uclibc-gcc +UCLIBC_GCC = $(shell for nm in i386-uclibc-linux-gcc i386-uclibc-gcc; do which $$nm > /dev/null && { echo $$nm ; exit; } ; done; echo false No uclibc found ) CC = gcc CXFLAGS = -ggdb @@ -55,8 +55,8 @@ MAN8DIR = $(MANDIR)/man8 KLIBC=/home/src/klibc/klibc-0.77 -OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Monitor.o dlink.o Kill.o Query.o -SRCS = mdadm.c config.c mdstat.c ReadMe.c util.c Manage.c Assemble.c Build.c Create.c Detail.c Examine.c Monitor.c dlink.c Kill.c Query.c +OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o +SRCS = mdadm.c config.c mdstat.c ReadMe.c util.c Manage.c Assemble.c Build.c Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c all : mdadm mdadm.man md.man mdadm.conf.man diff --git a/Monitor.c b/Monitor.c index 021a967..ce0087c 100644 --- a/Monitor.c +++ b/Monitor.c @@ -163,6 +163,7 @@ int Monitor(mddev_dev_t devlist, } else { mddev_dev_t dv; for (dv=devlist ; dv; dv=dv->next) { + mddev_ident_t mdlist = conf_get_ident(config, dv->devname); struct state *st = malloc(sizeof *st); if (st == NULL) continue; @@ -174,6 +175,11 @@ int Monitor(mddev_dev_t devlist, st->percent = -2; st->expected_spares = -1; st->spare_group = NULL; + if (mdlist) { + st->expected_spares = mdlist->spare_disks; + if (mdlist->spare_group) + st->spare_group = strdup(mdlist->spare_group); + } statelist = st; } } @@ -216,7 +222,8 @@ int Monitor(mddev_dev_t devlist, close(fd); continue; } - if (array.level != 1 && array.level != 5 && array.level != -4) { + if (array.level != 1 && array.level != 5 && array.level != -4 && + array.level != 6 && array.level != 10) { if (!st->err) alert("DeviceDisappeared", dev, "Wrong-Level", mailaddr, alert_cmd); diff --git a/ReadMe.c b/ReadMe.c index 6ba33ba..21a6543 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -29,7 +29,7 @@ #include "mdadm.h" -char Version[] = Name " - v1.6.0 - 4 June 2004\n"; +char Version[] = Name " - v1.7.0 - 11 August 2004\n"; /* * File: ReadMe.c * @@ -216,7 +216,7 @@ char OptionHelp[] = " --layout= : same as --parity\n" " --raid-devices= -n : number of active devices in array\n" " --spare-devices= -x: number of spares (eXtras) devices in initial array\n" -" --size= -z : Size (in K) of each drive in RAID1/4/5/6 - optional\n" +" --size= -z : Size (in K) of each drive in RAID1/4/5/6/10 - optional\n" " --force -f : Honour devices as listed on command line. Don't\n" " : insert a missing drive for RAID5.\n" " --auto(=p) -a : Automatically allocate new (partitioned) md array if needed.\n" @@ -284,7 +284,7 @@ char Help_create[] = " --layout= : same as --parity\n" " --raid-devices= -n : number of active devices in array\n" " --spare-devices= -x: number of spares (eXtras) devices in initial array\n" -" --size= -z : Size (in K) of each drive in RAID1/4/5/6 - optional\n" +" --size= -z : Size (in K) of each drive in RAID1/4/5/6/10 - optional\n" " --force -f : Honour devices as listed on command line. Don't\n" " : insert a missing drive for RAID5.\n" " --run -R : insist of running the array even if not all\n" @@ -508,6 +508,8 @@ mapping_t pers[] = { { "mp", -4}, { "raid6", 6}, { "6", 6}, + { "raid10", 10}, + { "10", 10}, { NULL, 0} }; diff --git a/config.c b/config.c index 1671d26..550bb80 100644 --- a/config.c +++ b/config.c @@ -364,7 +364,7 @@ void arrayline(char *line) } if (mis.devname == NULL) fprintf(stderr, Name ": ARRAY line with no device\n"); - else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor < 0) + else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor == UnSet) fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname); else { mi = malloc(sizeof(*mi)); diff --git a/inventory b/inventory new file mode 100644 index 0000000..fac793b --- /dev/null +++ b/inventory @@ -0,0 +1,43 @@ + +ANNOUNCE-1.0.0 +ANNOUNCE-1.1.0 +ANNOUNCE-1.2.0 +ANNOUNCE-1.3.0 +ANNOUNCE-1.4.0 +ANNOUNCE-1.5.0 +ANNOUNCE-1.6.0 +ANNOUNCE-1.7.0 +Assemble.c +Build.c +COPYING +ChangeLog +Create.c +Detail.c +Examine.c +Grow.c +INSTALL +Kill.c +Makefile +Manage.c +Monitor.c +Query.c +ReadMe.c +TODO +config.c +dlink.c +dlink.h +inventory +makedist +md.4 +md_p.h +md_u.h +mdadm.8 +mdadm.c +mdadm.conf-example +mdadm.conf.5 +mdadm.h +mdadm.spec +mdassemble.c +mdstat.c +raid5extend.c +util.c diff --git a/makedist b/makedist index 0c307f9..fb14ad4 100755 --- a/makedist +++ b/makedist @@ -21,9 +21,13 @@ grep "^Version: *$version$" mdadm.spec > /dev/null 2>&1 || if [ -f ANNOUNCE-$version ] then : else - echo ANNONCE-$version does not exist + echo ANNOUNCE-$version does not exist exit 1 fi +if grep "^ANNOUNCE-$version\$" inventory +then : +else { cat inventory ; echo ANNOUNCE-$version ; } | sort -o inventory +fi echo version = $version base=mdadm-$version.tgz @@ -38,6 +42,12 @@ then ( cd .. ; ln -s mdadm mdadm-$version ; tar chvf - --exclude="TAGS" --exclude='*~' --exclude=.patches --exclude='*,v' --exclude='*.o' --exclude mdadm --exclude=mdadm'.[^ch0-9]' --exclude=RCS mdadm-$version ; rm mdadm-$version ) | gzip --best > $target/$base chmod a+r $target/$base ls -l $target/$base + if tar tzf $target/$base | sed 's,[^/]*/,,' | sort | diff -u inventory - + then : correct files found + else echo "Extra files, or invertory is out-of-date" + rm $target/$base + exit 1 + fi rpm -ta $target/$base find /home/neilb/src/RPM -name "*mdadm-$version-*" \ diff --git a/md_p.h b/md_p.h index bd9ccb1..aeaf878 100644 --- a/md_p.h +++ b/md_p.h @@ -131,11 +131,16 @@ typedef struct mdp_superblock_s { #if __BYTE_ORDER == __BIG_ENDIAN __u32 events_hi; /* 7 high-order of superblock update count */ __u32 events_lo; /* 8 low-order of superblock update count */ + __u32 cp_events_hi; /* 9 high-order of checkpoint update count */ + __u32 cp_events_lo; /* 10 low-order of checkpoint update count */ #else __u32 events_lo; /* 7 low-order of superblock update count */ __u32 events_hi; /* 8 high-order of superblock update count */ + __u32 cp_events_lo; /* 9 low-order of checkpoint update count */ + __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ #endif - __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 9]; + __u32 recovery_cp; /* 11 recovery checkpoint sector count */ + __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 12]; /* * Personality information diff --git a/mdadm.8 b/mdadm.8 index 6e20b7e..b9f5bfa 100644 --- a/mdadm.8 +++ b/mdadm.8 @@ -1,5 +1,5 @@ .\" -*- nroff -*- -.TH MDADM 8 "" v1.6.0 +.TH MDADM 8 "" v1.7.0 .SH NAME mdadm \- manage MD devices .I aka @@ -407,6 +407,7 @@ Update the superblock on each device while assembling the array. The argument given to this flag can be one of .BR sparc2.2 , .BR summaries , +.BR resync , or .BR super-minor . @@ -428,6 +429,15 @@ field on each superblock to match the minor number of the array being assembled. This is not needed on 2.6 and later kernels as they make this adjustment automatically. +The +.B resync +option will cause the array to be marked +.I dirty +meaning that any redundancy in the array (e.g. parity for raid5, +copies for raid1) may be incorrect. This will cause the raid system +to perform a "resync" pass to make sure that all redundant information +is correct. + The .B summaries option will correct the summaries in the superblock. That is the diff --git a/mdadm.c b/mdadm.c index 827f334..e181673 100644 --- a/mdadm.c +++ b/mdadm.c @@ -235,6 +235,8 @@ int main(int argc, char *argv[]) int daemonise = 0; int oneshot = 0; + int copies; + int mdfd = -1; ident.uuid_set=0; @@ -361,6 +363,10 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": Must give one of -a/-r/-f for subsequent devices at %s\n", optarg); exit(2); } + if (devs_found > 0 && mode == 'G' && !devmode) { + fprintf(stderr, Name ": Must give one of -a for devices do add: %s\n", optarg); + exit(2); + } dv = malloc(sizeof(*dv)); if (dv == NULL) { fprintf(stderr, Name ": malloc failed\n"); @@ -441,7 +447,7 @@ int main(int argc, char *argv[]) continue; case O(CREATE,'p'): /* raid5 layout */ - if (layout >= 0) { + if (layout != UnSet) { fprintf(stderr,Name ": layout may only be sent once. " "Second value was %s\n", optarg); exit(2); @@ -464,6 +470,21 @@ int main(int argc, char *argv[]) exit(2); } break; + + case 10: + /* 'f' or 'n' followed by a number <= raid_disks */ + if ((optarg[0] != 'n' && optarg[0] != 'f') || + (copies = strtoul(optarg+1, &cp, 10)) < 1 || + copies > 200 || + *cp) { + fprintf(stderr, Name ": layout for raid10 must be 'nNN' or 'fNN' where NN is a number, not %s\n", optarg); + exit(2); + } + if (optarg[0] == 'n') + layout = 256 + copies; + else + layout = 1 + (copies<<8); + break; } continue; @@ -596,12 +617,15 @@ int main(int argc, char *argv[]) exit(2); } update = optarg; - if (strcmp(update, "sparc2.2")==0) continue; + if (strcmp(update, "sparc2.2")==0) + continue; if (strcmp(update, "super-minor") == 0) continue; if (strcmp(update, "summaries")==0) continue; - fprintf(stderr, Name ": '--update %s' invalid. Only 'sparc2.2', 'super-minor' or 'summaries' supported\n",update); + if (strcmp(update, "resync")==0) + continue; + fprintf(stderr, Name ": '--update %s' invalid. Only 'sparc2.2', 'super-minor', 'resync' or 'summaries' supported\n",update); exit(2); case O(ASSEMBLE,'c'): /* config file */ @@ -663,6 +687,7 @@ int main(int argc, char *argv[]) /* now the general management options. Some are applicable * to other modes. None have arguments. */ + case O(GROW,'a'): case O(MANAGE,'a'): /* add a drive */ devmode = 'a'; continue; @@ -944,16 +969,24 @@ int main(int argc, char *argv[]) case GROW: if (devs_found > 1) { - fprintf(stderr, Name ": Only one device may be given for --grow\n"); - rv = 1; - break; - } - if (size >= 0 && raiddisks) { + + /* must be '-a'. */ + if (size >= 0 || raiddisks) { + fprintf(stderr, Name ": --size, --raiddisks, and --add are exclusing in --grow mode\n"); + rv = 1; + break; + } + for (dv=devlist->next; dv ; dv=dv->next) { + rv = Grow_Add_device(devlist->devname, mdfd, dv->devname); + if (rv) + break; + } + } else if (size >= 0 && raiddisks) { fprintf(stderr, Name ": can only grow size OR raiddisks, not both\n"); rv = 1; break; - } - rv = Manage_resize(devlist->devname, mdfd, size, raiddisks); + } else + rv = Manage_resize(devlist->devname, mdfd, size, raiddisks); break; } exit(rv); diff --git a/mdadm.h b/mdadm.h index 90d3a09..831e267 100644 --- a/mdadm.h +++ b/mdadm.h @@ -136,6 +136,7 @@ struct mdstat_ent { char *level; char *pattern; /* U or up, _ for down */ int percent; /* -1 if no resync */ + int resync; /* 1 if resync, 0 if recovery */ struct mdstat_ent *next; }; @@ -159,6 +160,7 @@ extern int Manage_runstop(char *devname, int fd, int runstop); extern int Manage_resize(char *devname, int fd, long long size, int raid_disks); extern int Manage_subdevs(char *devname, int fd, mddev_dev_t devlist); +extern int Grow_Add_device(char *devname, int fd, char *newdev); extern int Assemble(char *mddev, int mdfd, diff --git a/mdadm.spec b/mdadm.spec index 7465b34..f55d933 100644 --- a/mdadm.spec +++ b/mdadm.spec @@ -1,6 +1,6 @@ Summary: mdadm is used for controlling Linux md devices (aka RAID arrays) Name: mdadm -Version: 1.6.0 +Version: 1.7.0 Release: 1 Source: http://www.cse.unsw.edu.au/~neilb/source/mdadm/mdadm-%{version}.tgz URL: http://www.cse.unsw.edu.au/~neilb/source/mdadm/ diff --git a/mdassemble b/mdassemble deleted file mode 100755 index cd8f042..0000000 Binary files a/mdassemble and /dev/null differ diff --git a/mdstat.c b/mdstat.c index 3204d2e..9a73279 100644 --- a/mdstat.c +++ b/mdstat.c @@ -153,6 +153,7 @@ struct mdstat_ent *mdstat_read(int hold) ent->next = NULL; ent->percent = -1; ent->active = -1; + ent->resync = 0; ent->dev = strdup(line); ent->devnum = devnum; @@ -179,6 +180,11 @@ struct mdstat_ent *mdstat_read(int hold) w[l-1] == '%' && (eq=strchr(w, '=')) != NULL ) { ent->percent = atoi(eq+1); + if (strncmp(w,"resync", 4)==0) + ent->resync = 1; + } else if (ent->percent == -1 && + strncmp(w, "resync", 4)==0) { + ent->resync = 1; } else if (ent->percent == -1 && w[0] >= '0' && w[0] <= '9' && diff --git a/t b/t deleted file mode 100644 index baf4ab5..0000000 --- a/t +++ /dev/null @@ -1 +0,0 @@ -ARRAY /dev/fred auto=parti /dev/fred diff --git a/test b/test deleted file mode 100644 index fac0f33..0000000 --- a/test +++ /dev/null @@ -1,2 +0,0 @@ -dev partitions -array /dev/md0 super-minor=6 diff --git a/util.c b/util.c index 2f4ad96..5ef59c0 100644 --- a/util.c +++ b/util.c @@ -121,6 +121,8 @@ int get_linux_version() int enough(int level, int raid_disks, int avail_disks) { switch (level) { + case 10: return 1; /* a lie, but it is hard to tell */ + case -4: return avail_disks>= 1; case -1: @@ -375,6 +377,32 @@ int map_name(mapping_t *map, char *name) return UnSet; } + +int is_standard(char *dev) +{ + /* tests if dev is a "standard" md dev name. + * i.e if the last component is "/dNN" or "/mdNN", + * where NN is a string of digits + */ + dev = strrchr(dev, '/'); + if (!dev) + return 0; + if (strncmp(dev, "/d",2)==0) + dev += 2; + else if (strncmp(dev, "/md", 3)==0) + dev += 3; + else + return 0; + if (!*dev) + return 0; + while (isdigit(*dev)) + dev++; + if (*dev) + return 0; + return 1; +} + + /* * convert a major/minor pair for a block device into a name in /dev, if possible. * On the first call, walk /dev collecting name. @@ -421,31 +449,6 @@ int add_dev(const char *name, const struct stat *stb, int flag) return 0; } -int is_standard(char *dev) -{ - /* tests if dev is a "standard" md dev name. - * i.e if the last component is "/dNN" or "/mdNN", - * where NN is a string of digits - */ - dev = strrchr(dev, '/'); - if (!dev) - return 0; - if (strncmp(dev, "/d",2)==0) - dev += 2; - else if (strncmp(dev, "/md", 3)==0) - dev += 3; - else - return 0; - if (!*dev) - return 0; - while (isdigit(*dev)) - dev++; - if (*dev) - return 0; - return 1; -} - - /* * Find a block device with the right major/minor number. * Avoid /dev/mdNN and /dev/md/dNN is possible