Status: ok Add support for "faulty" personality. Description... Signed-off-by: Neil Brown ### Diffstat output ./Build.c | 32 +++++++++++++++++++++++++++++++- ./ChangeLog | 1 + ./Create.c | 14 ++++++++++++-- ./Manage.c | 17 +++++++++++++++++ ./ReadMe.c | 22 ++++++++++++++++++++++ ./md.4 | 27 +++++++++++++++++++++++++++ ./mdadm.8 | 40 ++++++++++++++++++++++++++++++++++++++-- ./mdadm.c | 36 ++++++++++++++++++++++++++++++------ ./mdadm.h | 30 ++++++++++++++++++++++++++++-- 9 files changed, 206 insertions(+), 13 deletions(-) diff ./Build.c~current~ ./Build.c --- ./Build.c~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./Build.c 2004-11-02 14:41:37.000000000 +1100 @@ -33,7 +33,7 @@ #define START_MD _IO (MD_MAJOR, 2) #define STOP_MD _IO (MD_MAJOR, 3) -int Build(char *mddev, int mdfd, int chunk, int level, +int Build(char *mddev, int mdfd, int chunk, int level, int layout, int raiddisks, mddev_dev_t devlist, int assume_clean) { @@ -50,6 +50,7 @@ int Build(char *mddev, int mdfd, int chu * SET_ARRAY_INFO, ADD_NEW_DISK, RUN_ARRAY * */ + int verbose = 0; int i; int vers; struct stat stb; @@ -77,6 +78,34 @@ int Build(char *mddev, int mdfd, int chu return 1; } + if (layout == UnSet) + switch(level) { + default: /* no layout */ + layout = 0; + break; + case 10: + layout = 0x102; /* near=2, far=1 */ + if (verbose) + fprintf(stderr, + Name ": layout defaults to n1\n"); + break; + case 5: + case 6: + layout = map_name(r5layout, "default"); + if (verbose) + fprintf(stderr, + Name ": layout defaults to %s\n", map_num(r5layout, layout)); + break; + case LEVEL_FAULTY: + layout = map_name(faultylayout, "default"); + + if (verbose) + fprintf(stderr, + Name ": layout defaults to %s\n", map_num(faultylayout, layout)); + break; + } + + vers = md_get_version(mdfd); /* looks Ok, go for it */ @@ -100,6 +129,7 @@ int Build(char *mddev, int mdfd, int chu if (chunk == 0) chunk = 64; array.chunk_size = chunk*1024; + array.layout = layout; if (ioctl(mdfd, SET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", mddev, strerror(errno)); diff ./ChangeLog~current~ ./ChangeLog --- ./ChangeLog~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./ChangeLog 2004-11-02 14:41:37.000000000 +1100 @@ -3,6 +3,7 @@ Changes Prior to this release - --pid-file (-i) to set a pid file to use with --monitor --daemonise - Fix typo in mdadm man page - Fix coredump when "-s" used with no config file present. + - Support new "faulty" personality which can inject synthetic faults. Changes Prior to 1.7.0 release - Support "--grow --add" to add a device to a linear array, if the diff ./Create.c~current~ ./Create.c --- ./Create.c~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./Create.c 2004-11-02 14:41:37.000000000 +1100 @@ -130,6 +130,13 @@ int Create(char *mddev, int mdfd, fprintf(stderr, Name ": layout defaults to %s\n", map_num(r5layout, layout)); break; + case LEVEL_FAULTY: + layout = map_name(faultylayout, "default"); + + if (verbose) + fprintf(stderr, + Name ": layout defaults to %s\n", map_num(faultylayout, layout)); + break; } if (level == 10) @@ -284,8 +291,11 @@ int Create(char *mddev, int mdfd, array.md_minor = MINOR(stb.st_rdev); array.not_persistent = 0; /*** FIX: Need to do something about RAID-6 here ***/ - if ( (level == 5 || level == 6) && - (insert_point < raiddisks || first_missing < raiddisks) ) + if ( ( (level == 5) && + (insert_point < raiddisks || first_missing < raiddisks) ) + || + ( level == 6 && missing_disks == 2) + ) array.state = 1; /* clean, but one+ drive will be missing */ else array.state = 0; /* not clean, but no errors */ diff ./Manage.c~current~ ./Manage.c --- ./Manage.c~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./Manage.c 2004-11-02 14:41:37.000000000 +1100 @@ -134,6 +134,23 @@ int Manage_resize(char *devname, int fd, return 0; } +int Manage_reconfig(char *devname, int fd, int layout) +{ + mdu_array_info_t info; + if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot get array information for %s: %s\n", + devname, strerror(errno)); + return 1; + } + info.layout = layout; + printf("layout set to %d\n", info.layout); + if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot set layout for %s: %s\n", + devname, strerror(errno)); + return 1; + } + return 0; +} int Manage_subdevs(char *devname, int fd, mddev_dev_t devlist) diff ./ReadMe.c~current~ ./ReadMe.c --- ./ReadMe.c~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./ReadMe.c 2004-11-02 14:41:37.000000000 +1100 @@ -512,6 +512,7 @@ mapping_t pers[] = { { "6", 6}, { "raid10", 10}, { "10", 10}, + { "faulty", -5}, { NULL, 0} }; @@ -525,3 +526,24 @@ mapping_t modes[] = { { "monitor", MONITOR}, { "grow", GROW}, }; + +mapping_t faultylayout[] = { + { "write-transient", WriteTransient }, + { "wt", WriteTransient }, + { "read-transient", ReadTransient }, + { "rt", ReadTransient }, + { "write-persistent", WritePersistent }, + { "wp", WritePersistent }, + { "read-persistent", ReadPersistent }, + { "rp", ReadPersistent }, + { "write-all", WriteAll }, + { "wa", WriteAll }, + { "read-fixable", ReadFixable }, + { "rf", ReadFixable }, + + { "clear", ClearErrors}, + { "flush", ClearFaults}, + { "none", ClearErrors}, + { "default", ClearErrors}, + { NULL, 0} +}; diff ./md.4~current~ ./md.4 --- ./md.4~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./md.4 2004-11-02 14:41:37.000000000 +1100 @@ -166,6 +166,33 @@ real device. If one of these interfaces problems), the multipath driver to attempt to redirect requests to another interface. +.SS FAULTY +The FAULTY md module is provided for testing purposes. A faulty array +has exactly one component device and is normally assembled without a +superblock, so the md array created provides direct access to all of +the data in the component device. + +The FAULTY module may be requested to simulate faults to allow testing +of other md levels or of filesystem. Faults can be chosen to trigger +on read requests or write requests, and can be transient (a subsequent +read/write at the address will probably succeed) or persistant +(subsequent read/write of the same address will fail). Further, read +faults can be "fixable" meaning that they persist until a write +request at the same address. + +Fault types can be requested with a period. In this case the fault +will recur repeatedly after the given number of request of the +relevant time. For example if persistent read faults have a period of +100, then ever 100th read request would generate a fault, and the +faulty sector would be recorded so that subsequent reads on that +sector would also fail. + +There is a limit to the number of faulty sectors that are remembered. +Faults generated after this limit is exhausted are treated as +transient. + +It list of faulty sectors can be flushed, and the active list of +failure modes can be cleared. .SS UNCLEAN SHUTDOWN diff ./mdadm.8~current~ ./mdadm.8 --- ./mdadm.8~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./mdadm.8 2004-11-02 14:41:37.000000000 +1100 @@ -30,14 +30,17 @@ md devices, .BR RAID4 , .BR RAID5 , .BR RAID6 , +.BR MULTIPATH , and -.BR MULTIPATH . +.BR FAULTY . .B MULTIPATH is not a Software RAID mechanism, but does involve multiple devices. For .B MULTIPATH each device is a path to one common physical storage device. +.B FAULTY is also no true RAID, and it only involves one device. It +provides a layer over a true device that can be used to inject faults. .B mdadm is a program that can be used to create, manage, and monitor @@ -246,7 +249,7 @@ Specify rounding factor for linear array Set raid level. When used with .IR --create , options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid4, 4, -raid5, 5, raid6, 6, multipath, mp. Obviously some of these are synonymous. +raid5, 5, raid6, 6, multipath, mp, fautly. Obviously some of these are synonymous. When used with .IR --build , @@ -261,6 +264,39 @@ right-asymmetric, right-symmetric, la, ra, ls, rs. The default is left-symmetric. +This option is also used to set the failure mode for +.IR faulty . +The options are: +write-transient, +wt, +read-transient, +rt, +write-presistent, +wp, +read-persistent, +rp, +write-all, +read-fixable, +rf, +clear, +flush, +none. + +Each mode can be followed by a number which is used as a period +between fault generation. Without a number, the fault is generated +once on the first relevant request. With a number, the fault will be +generated after that many request, and will continue to be generated +every time the period elapses. + +Multiple failure modes can be current simultaneously by using the +"--grow" option to set subsequent failure modes. + +"clear" or "none" will remove any pending or periodic failure modes, +and "flush" will clear any persistant faults. + +To set the parity with "--grow", the level of the array ("faulty") +must be specified before the fault mode is specified. + .TP .BR --layout= same as --parity diff ./mdadm.c~current~ ./mdadm.c --- ./mdadm.c~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./mdadm.c 2004-11-02 14:41:37.000000000 +1100 @@ -260,6 +260,7 @@ int main(int argc, char *argv[]) } continue; + case O(GROW,'l'): /* hack - needed to understand layout */ case O(CREATE,'l'): case O(BUILD,'l'): /* set raid level*/ if (level != UnSet) { @@ -273,7 +274,7 @@ int main(int argc, char *argv[]) optarg); exit(2); } - if (level != 0 && level != -1 && level != 1 && level != -4 && mode == BUILD) { + if (level != 0 && level != -1 && level != 1 && level != -4 && level != -5 && mode == BUILD) { fprintf(stderr, Name ": Raid level %s not permitted with --build.\n", optarg); exit(2); @@ -287,6 +288,8 @@ int main(int argc, char *argv[]) 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); @@ -325,6 +328,23 @@ int main(int argc, char *argv[]) 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) { + fprintf(stderr, Name ": layout %s not understood for faulty.\n", + optarg); + exit(2); + } + layout = mode | (atoi(optarg+ln)<< ModeShift); + } } continue; @@ -347,7 +367,7 @@ int main(int argc, char *argv[]) optarg); exit(2); } - if (raiddisks == 1 && !force) { + if (raiddisks == 1 && !force && level != -5) { fprintf(stderr, Name ": '1' is an unusual number of drives for an array, so it is probably\n" " a mistake. If you really mean it you will need to specify --force before\n" " setting the number of drives.\n"); @@ -733,7 +753,7 @@ int main(int argc, char *argv[]) } break; case BUILD: - rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next, assume_clean); + rv = Build(devlist->devname, mdfd, chunk, level, layout, raiddisks, devlist->next, assume_clean); break; case CREATE: rv = Create(devlist->devname, mdfd, chunk, level, layout, size<0 ? 0 : size, @@ -835,12 +855,16 @@ int main(int argc, char *argv[]) if (rv) break; } - } else if (size >= 0 && raiddisks) { - fprintf(stderr, Name ": can only grow size OR raiddisks, not both\n"); + } else if ((size >= 0) + (raiddisks != 0) + (layout != UnSet) > 1) { + fprintf(stderr, Name ": can change at most one of size, raiddisks, and layout\n"); rv = 1; break; - } else + } else if (layout != UnSet) + rv = Manage_reconfig(devlist->devname, mdfd, layout); + else if (size >= 0 || raiddisks) rv = Manage_resize(devlist->devname, mdfd, size, raiddisks); + else + fprintf(stderr, Name ": no changes to --grow\n"); break; } exit(rv); diff ./mdadm.h~current~ ./mdadm.h --- ./mdadm.h~current~ 2004-11-02 14:41:37.000000000 +1100 +++ ./mdadm.h 2004-11-02 14:41:37.000000000 +1100 @@ -150,7 +150,7 @@ extern void mdstat_wait(int seconds); extern char *map_num(mapping_t *map, int num); extern int map_name(mapping_t *map, char *name); -extern mapping_t r5layout[], pers[], modes[]; +extern mapping_t r5layout[], pers[], modes[], faultylayout[]; extern char *map_dev(int major, int minor); @@ -158,6 +158,7 @@ extern char *map_dev(int major, int mino extern int Manage_ro(char *devname, int fd, int readonly); 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_reconfig(char *devname, int fd, int layout); extern int Manage_subdevs(char *devname, int fd, mddev_dev_t devlist); extern int Grow_Add_device(char *devname, int fd, char *newdev); @@ -171,7 +172,7 @@ extern int Assemble(char *mddev, int mdf char *update, int verbose, int force); -extern int Build(char *mddev, int mdfd, int chunk, int level, +extern int Build(char *mddev, int mdfd, int chunk, int level, int layout, int raiddisks, mddev_dev_t devlist, int assume_clean); @@ -229,3 +230,28 @@ extern char *get_md_name(int dev); extern char DefaultConfFile[]; extern int open_mddev(char *dev, int autof); + + +#define LEVEL_MULTIPATH (-4) +#define LEVEL_LINEAR (-1) +#define LEVEL_FAULTY (-5) + + +/* faulty stuff */ + +#define WriteTransient 0 +#define ReadTransient 1 +#define WritePersistent 2 +#define ReadPersistent 3 +#define WriteAll 4 /* doesn't go to device */ +#define ReadFixable 5 +#define Modes 6 + +#define ClearErrors 31 +#define ClearFaults 30 + +#define AllPersist 100 /* internal use only */ +#define NoPersist 101 + +#define ModeMask 0x1f +#define ModeShift 5