From 82d9eba687c952a9919f756203706285d6c42f07 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 3 May 2005 23:44:40 +0000 Subject: [PATCH] super1 Signed-off-by: Neil Brown Fix raid5 creation with new code. Signed-off-by: Neil Brown --- Assemble.c | 38 +-- Create.c | 47 ++-- Detail.c | 18 +- Examine.c | 27 +- Grow.c | 18 +- Kill.c | 12 +- Makefile | 4 +- Query.c | 10 +- config.c | 10 +- mdadm.c | 19 +- mdadm.h | 30 ++- super0.c | 44 +++- super1.c | 720 +++++++++++++++++++++++++++++++++++++++++++++++++++++ util.c | 62 ++--- 14 files changed, 910 insertions(+), 149 deletions(-) create mode 100644 super1.c diff --git a/Assemble.c b/Assemble.c index 3c098617..7cab81a5 100644 --- a/Assemble.c +++ b/Assemble.c @@ -29,7 +29,7 @@ #include "mdadm.h" -int Assemble(struct superswitch *ss, char *mddev, int mdfd, +int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, mddev_dev_t devlist, int readonly, int runstop, @@ -164,7 +164,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, } devices = malloc(num_devs * sizeof(*devices)); - if (!ss && ident->ss) ss = ident->ss; + if (!st && ident->st) st = ident->st; if (verbose) fprintf(stderr, Name ": looking for devices for %s\n", @@ -174,7 +174,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, char *devname; int dfd; struct stat stb; - struct superswitch *tss = ss; + struct supertype *tst = st; devname = devlist->devname; devlist = devlist->next; @@ -205,16 +205,16 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, fprintf(stderr, Name ": %s is not a block device.\n", devname); close(dfd); - } else if (!tss && (tss = guess_super(dfd, NULL)) == NULL) { + } else if (!tst && (tst = guess_super(dfd)) == NULL) { if (inargv || verbose) fprintf(stderr, Name ": no recogniseable superblock\n"); - } else if (tss->load_super(dfd, &super, NULL)) { + } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { if (inargv || verbose) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); close(dfd); } else { - tss->getinfo_super(&info, super); + tst->ss->getinfo_super(&info, super); close(dfd); } @@ -258,8 +258,8 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, free(first_super); return 1; } - ss = tss; /* commit to this format, if haven't already */ - if (ss->compare_super(&first_super, super)) { + st = tst; /* commit to this format, if haven't already */ + if (st->ss->compare_super(&first_super, super)) { fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", devname); free(super); @@ -274,13 +274,13 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, fstat(mdfd, &stb2); info.array.md_minor = minor(stb2.st_rdev); - ss->update_super(&info, super, update, devname, verbose); + st->ss->update_super(&info, super, update, devname, verbose); dfd = open(devname, O_RDWR|O_EXCL, 0); if (dfd < 0) fprintf(stderr, Name ": Cannot open %s for superblock update\n", devname); - else if (ss->store_super(dfd, super)) + else if (st->ss->store_super(dfd, super)) fprintf(stderr, Name ": Could not re-write superblock on %s.\n", devname); if (dfd >= 0) @@ -341,7 +341,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, return 1; } - ss->getinfo_super(&info, first_super); + st->ss->getinfo_super(&info, first_super); /* now we have some devices that might be suitable. * I wonder how many @@ -399,7 +399,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, devices[chosen_drive].events = 0; continue; } - if (ss->load_super(fd, &super, NULL)) { + if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); @@ -407,9 +407,9 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, continue; } info.events = devices[most_recent].events; - ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); + st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); - if (ss->store_super(fd, super)) { + if (st->ss->store_super(fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); @@ -446,7 +446,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, devices[j].devname, strerror(errno)); return 1; } - if (ss->load_super(fd, &super, NULL)) { + if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", devices[j].devname); @@ -458,7 +458,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); return 1; } - ss->getinfo_super(&info, super); + st->ss->getinfo_super(&info, super); for (i=0; iupdate_super(&info, super, "assemble", NULL, 0)) { + st->ss->update_super(&info, super, "assemble", NULL, 0)) { if (force) { fprintf(stderr, Name ": " "clearing FAULTY flag for device %d in %s for %s\n", @@ -498,7 +498,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, } if (force && okcnt == info.array.raid_disks-1) { /* FIXME check event count */ - change += ss->update_super(&info, super, "force", + change += st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, 0); } @@ -510,7 +510,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd, devices[chosen_drive].devname); return 1; } - if (ss->store_super(fd, super)) { + if (st->ss->store_super(fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); diff --git a/Create.c b/Create.c index 15a7de87..331835db 100644 --- a/Create.c +++ b/Create.c @@ -31,7 +31,7 @@ #include "md_u.h" #include "md_p.h" -int Create(struct superswitch *ss, char *mddev, int mdfd, +int Create(struct supertype *st, char *mddev, int mdfd, int chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks, int subdevs, mddev_dev_t devlist, int runstop, int verbose, int force) @@ -49,7 +49,7 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, * abort. * * SET_ARRAY_INFO and ADD_NEW_DISK, and - * if runstop==run, or raiddisks diskswere used, + * if runstop==run, or raiddisks disks were used, * RUN_ARRAY */ unsigned long long minsize=0, maxsize=0; @@ -59,16 +59,18 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, mddev_dev_t dv; int fail=0, warn=0; struct stat stb; - int first_missing = MD_SB_DISKS*2; + int first_missing = subdevs * 2; int missing_disks = 0; - int insert_point = MD_SB_DISKS*2; /* where to insert a missing drive */ + int insert_point = subdevs * 2; /* where to insert a missing drive */ void *super; int pass; + int vers; + int rv; mdu_array_info_t array; - - if (md_get_version(mdfd) < 9000) { + vers = md_get_version(mdfd); + if (vers < 9000) { fprintf(stderr, Name ": Create requires md driver version 0.90.0 or later\n"); return 1; } @@ -97,12 +99,6 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, Name ": at least 2 raid-devices needed for level 4 or 5\n"); return 1; } - if (raiddisks+sparedisks > MD_SB_DISKS) { - fprintf(stderr, - Name ": too many devices requested: %d+%d > %d\n", - raiddisks, sparedisks, MD_SB_DISKS); - return 1; - } if (subdevs > raiddisks+sparedisks) { fprintf(stderr, Name ": You have listed more devices (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks); return 1; @@ -211,15 +207,16 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, ldsize = dsize; dsize <<= 9; } - if (ldsize < MD_RESERVED_SECTORS*2LL*512LL) { + freesize = st->ss->avail_size(ldsize); + if (freesize == 0) { fprintf(stderr, Name ": %s is too small: %luK\n", dname, (unsigned long)(ldsize>>10)); fail = 1; close(fd); continue; } - freesize = MD_NEW_SIZE_SECTORS((ldsize>>9)); - freesize /= 2; + + freesize /= 2; /* convert to K */ if (size && freesize < size) { fprintf(stderr, Name ": %s is smaller that given size." @@ -342,14 +339,25 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, array.nr_disks = array.working_disks + array.failed_disks; array.layout = layout; array.chunk_size = chunk*1024; + printf("VERS = %d\n", vers); + + if (!st->ss->init_super(&super, &array)) + return 1; - if (ioctl(mdfd, SET_ARRAY_INFO, NULL)) { + if ((vers % 100) >= 1) { /* can use different versions */ + mdu_array_info_t inf; + memset(&inf, 0, sizeof(inf)); + inf.major_version = st->ss->major; + inf.minor_version = st->minor_version; + rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); + } else + rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); + if (rv) { fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", mddev, strerror(errno)); return 1; } - ss->init_super(&super, &array); for (pass=1; pass <=2 ; pass++) { @@ -387,12 +395,13 @@ int Create(struct superswitch *ss, char *mddev, int mdfd, disk.minor = minor(stb.st_rdev); close(fd); } + if (disk.state != 1) switch(pass){ case 1: - ss->add_to_super(super, &disk); + st->ss->add_to_super(super, &disk); break; case 2: - ss->write_init_super(super, &disk, dv->devname); + st->ss->write_init_super(st, super, &disk, dv->devname); if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", diff --git a/Detail.c b/Detail.c index 2f3fc7ff..8d7a5ffc 100644 --- a/Detail.c +++ b/Detail.c @@ -50,7 +50,7 @@ int Detail(char *dev, int brief, int test) int is_26 = get_linux_version() >= 2006000; int is_rebuilding = 0; int failed = 0; - struct superswitch *ss = NULL; + struct supertype *st = NULL; void *super = NULL; int rv = test ? 4 : 1; @@ -83,7 +83,7 @@ int Detail(char *dev, int brief, int test) close(fd); return rv; } - ss = super_by_version(array.major_version); + st = super_by_version(array.major_version, array.minor_version); if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode)) stb.st_rdev = 0; @@ -106,10 +106,10 @@ int Detail(char *dev, int brief, int test) * to get more info */ int fd2 = open(dv, O_RDONLY); - if (fd2 >=0 && ss && - ss->load_super(fd2, &super, NULL) == 0) { + if (fd2 >=0 && st && + st->ss->load_super(st, fd2, &super, NULL) == 0) { struct mdinfo info; - ss->getinfo_super(&info, super); + st->ss->getinfo_super(&info, super); if (info.array.ctime != array.ctime || info.array.level != array.level) { free(super); @@ -205,8 +205,8 @@ int Detail(char *dev, int brief, int test) } free_mdstat(ms); - if (super && ss) - ss->detail_super(super); + if (super && st) + st->ss->detail_super(super); printf(" Number Major Minor RaidDevice State\n"); } @@ -278,8 +278,8 @@ int Detail(char *dev, int brief, int test) if (!brief) printf("\n"); } if (spares && brief) printf(" spares=%d", spares); - if (super && brief && ss) - ss->brief_detail_super(super); + if (super && brief && st) + st->ss->brief_detail_super(super); if (brief && devices) printf("\n devices=%s", devices); if (brief) printf("\n"); diff --git a/Examine.c b/Examine.c index 8081b660..da859930 100644 --- a/Examine.c +++ b/Examine.c @@ -35,7 +35,7 @@ #endif #include "md_u.h" #include "md_p.h" -int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) +int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust, struct supertype *forcest) { /* Read the raid superblock from a device and @@ -60,7 +60,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) struct array { void *super; - struct superswitch *ss; + struct supertype *st; struct mdinfo info; void *devs; struct array *next; @@ -68,7 +68,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) } *arrays = NULL; for (; devlist ; devlist=devlist->next) { - struct superswitch *ss; + struct supertype *st = forcest; fd = open(devlist->devname, O_RDONLY); if (fd < 0) { @@ -78,9 +78,10 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) err = 1; } else { - ss = guess_super(fd, devlist->devname); - if (ss) - err = ss->load_super(fd, &super, (brief||scan)?NULL:devlist->devname); + if (!st) + st = guess_super(fd); + if (st) + err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname); else err = 1; close(fd); @@ -90,13 +91,13 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) if (err) rv =1; if (SparcAdjust) - ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0); + st->ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0); /* Ok, its good enough to try, though the checksum could be wrong */ if (brief) { struct array *ap; char *d; for (ap=arrays; ap; ap=ap->next) { - if (ss == ap->ss && ss->compare_super(&ap->super, super)==0) + if (st->ss == ap->st->ss && st->ss->compare_super(&ap->super, super)==0) break; } if (!ap) { @@ -105,11 +106,11 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) ap->devs = dl_head(); ap->next = arrays; ap->spares = 0; - ap->ss = ss; + ap->st = st; arrays = ap; - ss->getinfo_super(&ap->info, super); + st->ss->getinfo_super(&ap->info, super); } else { - ss->getinfo_super(&ap->info, super); + st->ss->getinfo_super(&ap->info, super); free(super); } if (!(ap->info.disk.state & MD_DISK_SYNC)) @@ -118,7 +119,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) dl_add(ap->devs, d); } else { printf("%s:\n",devlist->devname); - ss->examine_super(super); + st->ss->examine_super(super); free(super); } } @@ -127,7 +128,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) for (ap=arrays; ap; ap=ap->next) { char sep='='; char *d; - ap->ss->brief_examine_super(ap->super); + ap->st->ss->brief_examine_super(ap->super); if (ap->spares) printf(" spares=%d", ap->spares); printf(" devices"); for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { diff --git a/Grow.c b/Grow.c index ec2eb55a..41c7dc03 100644 --- a/Grow.c +++ b/Grow.c @@ -51,7 +51,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev) struct stat stb; int nfd, fd2; int d, nd; - struct superswitch *ss = NULL; + struct supertype *st = NULL; if (ioctl(fd, GET_ARRAY_INFO, &info.array) < 0) { @@ -59,8 +59,8 @@ int Grow_Add_device(char *devname, int fd, char *newdev) return 1; } - ss = super_by_version(info.array.major_version); - if (!ss) { + st = super_by_version(info.array.major_version, info.array.minor_version); + if (!st) { fprintf(stderr, Name ": cannot handle arrays with superblock version %d\n", info.array.major_version); return 1; } @@ -105,7 +105,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev) } if (super) free(super); super= NULL; - if (ss->load_super(fd2, &super, NULL)) { + if (st->ss->load_super(st, fd2, &super, NULL)) { fprintf(stderr, Name ": cannot find super block on %s\n", dv); close(fd2); return 1; @@ -121,9 +121,9 @@ int Grow_Add_device(char *devname, int fd, char *newdev) info.disk.minor = minor(stb.st_rdev); info.disk.raid_disk = d; info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); - ss->update_super(&info, super, "grow", newdev, 0); + st->ss->update_super(&info, super, "grow", newdev, 0); - if (ss->store_super(nfd, super)) { + if (st->ss->store_super(nfd, super)) { fprintf(stderr, Name ": Cannot store new superblock on %s\n", newdev); close(nfd); return 1; @@ -165,7 +165,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev) fprintf(stderr, Name ": cannot open device file %s\n", dv); return 1; } - if (ss->load_super(fd2, &super, NULL)) { + if (st->ss->load_super(st, fd2, &super, NULL)) { fprintf(stderr, Name ": cannot find super block on %s\n", dv); close(fd); return 1; @@ -179,9 +179,9 @@ int Grow_Add_device(char *devname, int fd, char *newdev) info.disk.minor = minor(stb.st_rdev); info.disk.raid_disk = nd; info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); - ss->update_super(&info, super, "grow", dv, 0); + st->ss->update_super(&info, super, "grow", dv, 0); - if (ss->store_super(fd2, super)) { + if (st->ss->store_super(fd2, super)) { fprintf(stderr, Name ": Cannot store new superblock on %s\n", dv); close(fd2); return 1; diff --git a/Kill.c b/Kill.c index b20c28e0..ba99c6e5 100644 --- a/Kill.c +++ b/Kill.c @@ -43,7 +43,7 @@ int Kill(char *dev, int force) void *super; int fd, rv = 0; - struct superswitch *ss; + struct supertype *st; fd = open(dev, O_RDWR|O_EXCL); if (fd < 0) { @@ -51,20 +51,20 @@ int Kill(char *dev, int force) dev); return 1; } - ss = guess_super(fd, dev); - if (ss == NULL) { + st = guess_super(fd); + if (st == NULL) { fprintf(stderr, Name ": Unrecognised md component device - %s\n", dev); return 1; } - rv = ss->load_super(fd, &super, dev); + rv = st->ss->load_super(st, fd, &super, dev); if (force && rv >= 2) rv = 0; /* ignore bad data in superblock */ if (rv== 0 || (force && rv >= 2)) { mdu_array_info_t info; info.major_version = -1; /* zero superblock */ free(super); - ss->init_super(&super, &info); - if (ss->store_super(fd, super)) { + st->ss->init_super(&super, &info); + if (st->ss->store_super(fd, super)) { fprintf(stderr, Name ": Could not zero superblock on %s\n", dev); rv = 1; diff --git a/Makefile b/Makefile index 38cfcdee..cec6ed64 100644 --- a/Makefile +++ b/Makefile @@ -58,9 +58,9 @@ MAN5DIR = $(MANDIR)/man5 MAN8DIR = $(MANDIR)/man8 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 mdopen.o super0.o + Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o mdopen.o super0.o super1.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 mdopen.c super0.c + Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c mdopen.c super0.c super1.c ASSEMBLE_SRCS := mdassemble.c Assemble.c config.c dlink.c util.c ifdef MDASSEMBLE_AUTO diff --git a/Query.c b/Query.c index 88df3214..4c2c7bff 100644 --- a/Query.c +++ b/Query.c @@ -44,7 +44,7 @@ int Query(char *dev) struct mdinfo info; mdu_array_info_t array; void *super; - struct superswitch *ss = NULL; + struct supertype *st = NULL; unsigned long long larray_size; unsigned long array_size; @@ -95,16 +95,16 @@ int Query(char *dev) array.raid_disks, array.spare_disks, array.spare_disks==1?"":"s"); } - ss = guess_super(fd, dev); - if (ss) { - superror = ss->load_super(fd, &super, dev); + st = guess_super(fd); + if (st) { + superror = st->ss->load_super(st, fd, &super, dev); superrno = errno; } else superror = -1; close(fd); if (superror == 0) { /* array might be active... */ - ss->getinfo_super(&info, super); + st->ss->getinfo_super(&info, super); mddev = get_md_name(info.array.md_minor); disc.number = info.disk.number; activity = "undetected"; diff --git a/config.c b/config.c index f3a749c0..7383e193 100644 --- a/config.c +++ b/config.c @@ -332,12 +332,10 @@ void arrayline(char *line) /* style of metadata on the devices. */ int i; - for(i=0; superlist[i]; i++) - if (superlist[i]->match_metadata_desc(w+9)) { - mis.ss = superlist[i]; - break; - } - if (!mis.ss) + for(i=0; superlist[i] && !mis.st; i++) + mis.st = superlist[i]->match_metadata_desc(w+9); + + if (!mis.st) fprintf(stderr, Name ": metadata format %s unknown, ignored.\n", w+9); } else if (strncasecmp(w, "auto=", 5) == 0 ) { /* whether to create device special files as needed */ diff --git a/mdadm.c b/mdadm.c index b738fadd..1bdc55d1 100644 --- a/mdadm.c +++ b/mdadm.c @@ -81,7 +81,7 @@ int main(int argc, char *argv[]) int daemonise = 0; char *pidfile = NULL; int oneshot = 0; - struct superswitch *ss = NULL; + struct supertype *ss = NULL; int copies; @@ -281,11 +281,9 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": metadata information already given\n"); exit(2); } - for(i=0; superlist[i]; i++) - if (superlist[i]->match_metadata_desc(optarg)) { - ss = superlist[i]; - break; - } + for(i=0; !ss && superlist[i]; i++) + ss = superlist[i]->match_metadata_desc(optarg); + if (!ss) { fprintf(stderr, Name ": unrecognised metadata identifier: %s\n", optarg); exit(2); @@ -818,11 +816,8 @@ int main(int argc, char *argv[]) break; case CREATE: if (ss == NULL) { - for(i=0; superlist[i]; i++) - if (superlist[i]->match_metadata_desc("default")) { - ss = superlist[i]; - break; - } + for(i=0; !ss && superlist[i]; i++) + ss = superlist[i]->match_metadata_desc("default"); } if (!ss) { fprintf(stderr, Name ": internal error - no default metadata style\n"); @@ -846,7 +841,7 @@ int main(int argc, char *argv[]) fprintf(stderr, Name ": No devices listed in %s\n", configfile?configfile:DefaultConfFile); exit(1); } - rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust); + rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust, ss); } else { if (devlist == NULL) { if ((devmode == 'S' ||devmode=='D') && scan) { diff --git a/mdadm.h b/mdadm.h index 491d9075..d42e853c 100644 --- a/mdadm.h +++ b/mdadm.h @@ -116,7 +116,7 @@ typedef struct mddev_ident_s { int level; unsigned int raid_disks; unsigned int spare_disks; - struct superswitch *ss; + struct supertype *st; int autof; /* 1 for normal, 2 for partitioned */ char *spare_group; @@ -173,17 +173,24 @@ extern struct superswitch { void (*getinfo_super)(struct mdinfo *info, void *sbv); int (*update_super)(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose); __u64 (*event_super)(void *sbv); - void (*init_super)(void **sbp, mdu_array_info_t *info); + int (*init_super)(void **sbp, mdu_array_info_t *info); void (*add_to_super)(void *sbv, mdu_disk_info_t *dinfo); int (*store_super)(int fd, void *sbv); - int (*write_init_super)(void *sbv, mdu_disk_info_t *dinfo, char *devname); + int (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname); int (*compare_super)(void **firstp, void *secondv); - int (*load_super)(int fd, void **sbp, char *devname); - int (*match_metadata_desc)(char *arg); -} super0, *superlist[]; + int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname); + struct supertype * (*match_metadata_desc)(char *arg); + __u64 (*avail_size)(__u64 size); + int major; +} super0, super1, *superlist[]; + +struct supertype { + struct superswitch *ss; + int minor_version; +}; -extern struct superswitch *super_by_version(int vers); -extern struct superswitch *guess_super(int fd, char *dev); +extern struct supertype *super_by_version(int vers, int minor); +extern struct supertype *guess_super(int fd); extern int Manage_ro(char *devname, int fd, int readonly); @@ -195,7 +202,7 @@ extern int Manage_subdevs(char *devname, int fd, extern int Grow_Add_device(char *devname, int fd, char *newdev); -extern int Assemble(struct superswitch *ss, char *mddev, int mdfd, +extern int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, mddev_dev_t devlist, @@ -208,14 +215,15 @@ extern int Build(char *mddev, int mdfd, int chunk, int level, int layout, mddev_dev_t devlist, int assume_clean); -extern int Create(struct superswitch *ss, char *mddev, int mdfd, +extern int Create(struct supertype *st, char *mddev, int mdfd, int chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks, int subdevs, mddev_dev_t devlist, int runstop, int verbose, int force); extern int Detail(char *dev, int brief, int test); extern int Query(char *dev); -extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust); +extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust, + struct supertype *forcest); extern int Monitor(mddev_dev_t devlist, char *mailaddr, char *alert_cmd, int period, int daemonise, int scan, int oneshot, diff --git a/super0.c b/super0.c index 4cd2cc3d..4cf9277c 100644 --- a/super0.c +++ b/super0.c @@ -322,14 +322,22 @@ static __u64 event_super0(void *sbv) -static void init_super0(void **sbp, mdu_array_info_t *info) +static int init_super0(void **sbp, mdu_array_info_t *info) { mdp_super_t *sb = malloc(MD_SB_BYTES); + int spares; memset(sb, 0, MD_SB_BYTES); if (info->major_version == -1) { /* zeroing the superblock */ - return; + return 0; + } + + spares = info->working_disks - info->active_disks; + if (info->raid_disks + spares > MD_SB_DISKS) { + fprintf(stderr, Name ": too many devices requested: %d+%d > %d\n", + info->raid_disks , spares, MD_SB_DISKS); + return 0; } sb->md_magic = MD_SB_MAGIC; @@ -361,6 +369,7 @@ static void init_super0(void **sbp, mdu_array_info_t *info) sb->chunk_size = info->chunk_size; *sbp = sb; + return 1; } /* Add a device to the superblock being created */ @@ -409,7 +418,7 @@ static int store_super0(int fd, void *sbv) return 0; } -static int write_init_super0(void *sbv, mdu_disk_info_t *dinfo, char *devname) +static int write_init_super0(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname) { mdp_super_t *sb = sbv; int fd = open(devname, O_RDWR, O_EXCL); @@ -469,7 +478,7 @@ static int compare_super0(void **firstp, void *secondv) } -static int load_super0(int fd, void **sbp, char *devname) +static int load_super0(struct supertype *st, int fd, void **sbp, char *devname) { /* try to read in the superblock * Return: @@ -541,17 +550,36 @@ static int load_super0(int fd, void **sbp, char *devname) return 2; } *sbp = super; + if (st->ss == NULL) { + st->ss = &super0; + st->minor_version = 90; + } + return 0; } -static int match_metadata_desc0(char *arg) +static struct supertype *match_metadata_desc0(char *arg) { + struct supertype *st = malloc(sizeof(*st)); + if (!st) return st; + + st->ss = &super0; + st->minor_version = 90; if (strcmp(arg, "0") == 0 || strcmp(arg, "0.90") == 0 || strcmp(arg, "default") == 0 ) - return 1; - return 0; + return st; + + free(st); + return NULL; +} + +static __u64 avail_size0(__u64 devsize) +{ + if (devsize < MD_RESERVED_SECTORS*2) + return 0ULL; + return MD_NEW_SIZE_SECTORS(devsize); } struct superswitch super0 = { @@ -570,4 +598,6 @@ struct superswitch super0 = { .compare_super = compare_super0, .load_super = load_super0, .match_metadata_desc = match_metadata_desc0, + .avail_size = avail_size0, + .major = 0, }; diff --git a/super1.c b/super1.c new file mode 100644 index 00000000..86787653 --- /dev/null +++ b/super1.c @@ -0,0 +1,720 @@ +/* + * 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 "asm/byteorder.h" +/* + * The version-1 superblock : + * All numeric fields are little-endian. + * + * total size: 256 bytes plus 2 per device. + * 1K allows 384 devices. + */ +struct mdp_superblock_1 { + /* constant array information - 128 bytes */ + __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + __u32 major_version; /* 1 */ + __u32 feature_map; /* 0 for now */ + __u32 pad0; /* always set to 0 when writing */ + + __u8 set_uuid[16]; /* user-space generated. */ + char set_name[32]; /* set and interpreted by user-space */ + + __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ + __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ + __u32 layout; /* only for raid5 currently */ + __u64 size; /* used size of component devices, in 512byte sectors */ + + __u32 chunksize; /* in 512byte sectors */ + __u32 raid_disks; + __u8 pad1[128-96]; /* set to 0 when written */ + + /* constant this-device information - 64 bytes */ + __u64 data_offset; /* sector start of data, often 0 */ + __u64 data_size; /* sectors in this device that can be used for data */ + __u64 super_offset; /* sector start of this superblock */ + __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + __u32 dev_number; /* permanent identifier of this device - not role in raid */ + __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ + __u8 pad2[64-56]; /* set to 0 when writing */ + + /* array state information - 64 bytes */ + __u64 utime; /* 40 bits second, 24 btes microseconds */ + __u64 events; /* incremented when superblock updated */ + __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ + __u32 sb_csum; /* checksum upto devs[max_dev] */ + __u32 max_dev; /* size of devs[] array to consider */ + __u8 pad3[64-32]; /* set to 0 when writing */ + + /* device state information. Indexed by dev_number. + * 2 bytes per device + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ +}; + +#define offsetof(t,f) ((int)&(((t*)0)->f)) +static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) +{ + unsigned int disk_csum, csum; + unsigned long long newcsum; + int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2; + unsigned int *isuper = (unsigned int*)sb; + int i; + +/* make sure I can count... */ + if (offsetof(struct mdp_superblock_1,data_offset) != 128 || + offsetof(struct mdp_superblock_1, utime) != 192 || + sizeof(struct mdp_superblock_1) != 256) { + fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); + } + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + newcsum = 0; + for (i=0; size>=4; size -= 4 ) + newcsum += __le32_to_cpu(*isuper++); + + if (size == 2) + newcsum += __le16_to_cpu(*(unsigned short*) isuper); + + csum = (newcsum & 0xffffffff) + (newcsum >> 32); + sb->sb_csum = disk_csum; + return csum; +} + + +static void examine_super1(void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + time_t atime; + int d; + int spares, faulty; + int i; + char *c; + + printf(" Magic : %08x\n", __le32_to_cpu(sb->magic)); + printf(" Version : %02d.%02d\n", 1, __le32_to_cpu(sb->feature_map)); + printf(" Array UUID : "); + for (i=0; i<16; i++) { + printf("%02x", sb->set_uuid[i]); + if ((i&3)==0 && i != 0) printf(":"); + } + printf("\n"); + printf(" Name : %.32s\n", sb->set_name); + + atime = __le64_to_cpu(sb->ctime) & 0xFFFFFFFFFFULL; + printf(" Creation Time : %.24s\n", ctime(&atime)); + c=map_num(pers, __le32_to_cpu(sb->level)); + printf(" Raid Level : %s\n", c?c:"-unknown-"); + printf(" Raid Devices : %d\n", __le32_to_cpu(sb->raid_disks)); + printf("\n"); + printf(" Device Size : %llu%s\n", sb->data_size, human_size(sb->data_size<<9)); + if (sb->data_offset) + printf(" Data Offset : %llu sectors\n", __le64_to_cpu(sb->data_offset)); + if (sb->super_offset) + printf(" Super Offset : %llu sectors\n", __le64_to_cpu(sb->super_offset)); + printf(" Device UUID : "); + for (i=0; i<16; i++) { + printf("%02x", sb->set_uuid[i]); + if ((i&3)==0 && i != 0) printf(":"); + } + printf("\n"); + + atime = __le64_to_cpu(sb->utime) & 0xFFFFFFFFFFULL; + printf(" Update Time : %.24s\n", ctime(&atime)); + + if (calc_sb_1_csum(sb) == sb->sb_csum) + printf(" Checksum : %x - correct\n", __le32_to_cpu(sb->sb_csum)); + else + printf(" Checksum : %x - expected %x\n", __le32_to_cpu(sb->sb_csum), + __le32_to_cpu(calc_sb_1_csum(sb))); + printf(" Events : %llu\n", __le64_to_cpu(sb->events)); + printf("\n"); + if (__le32_to_cpu(sb->level) == 5) { + c = map_num(r5layout, __le32_to_cpu(sb->layout)); + printf(" Layout : %s\n", c?c:"-unknown-"); + } + switch(__le32_to_cpu(sb->level)) { + case 0: + case 4: + case 5: + printf(" Chunk Size : %dK\n", __le32_to_cpu(sb->chunksize/2)); + break; + case -1: + printf(" Rounding : %dK\n", __le32_to_cpu(sb->chunksize/2)); + break; + default: break; + } + printf("\n"); + printf(" Array State : "); + for (d=0; d<__le32_to_cpu(sb->raid_disks); d++) { + int cnt = 0; + int me = 0; + int i; + for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { + int role = __le16_to_cpu(sb->dev_roles[i]); + if (role == d) { + if (i == __le32_to_cpu(sb->dev_number)) + me = 1; + cnt++; + } + } + if (cnt > 1) printf("?"); + else if (cnt == 1 && me) printf("U"); + else if (cnt == 1) printf("u"); + else printf ("_"); + } + spares = faulty = 0; + for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { + int role = __le16_to_cpu(sb->dev_roles[i]); + switch (role) { + case 0xFFFF: spares++; break; + case 0xFFFE: faulty++; + } + } + if (spares) printf(" %d spares", spares); + if (faulty) printf(" %d failed", faulty); + printf("\n"); +} + + +static void brief_examine_super1(void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + int i; + + char *c=map_num(pers, __le32_to_cpu(sb->level)); + + printf("ARRAY /dev/?? level=%s metadata=1 num-devices=%d UUID=", + c?c:"-unknown-", sb->raid_disks); + for (i=0; i<16; i++) { + printf("%02x", sb->set_uuid[i]); + if ((i&3)==0 && i != 0) printf(":"); + } + printf("\n"); +} + +static void detail_super1(void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + int i; + + printf(" UUID : "); + for (i=0; i<16; i++) { + printf("%02x", sb->set_uuid[i]); + if ((i&3)==0 && i != 0) printf(":"); + } + printf("\n Events : %llu\n\n", __le64_to_cpu(sb->events)); +} + +static void brief_detail_super1(void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + int i; + + printf(" UUID="); + for (i=0; i<16; i++) { + printf("%02x", sb->set_uuid[i]); + if ((i&3)==0 && i != 0) printf(":"); + } +} + +static void uuid_from_super1(int uuid[4], void * sbv) +{ + struct mdp_superblock_1 *super = sbv; + char *cuuid = (char*)uuid; + int i; + for (i=0; i<16; i++) + cuuid[i] = super->set_uuid[i]; +} + +static void getinfo_super1(struct mdinfo *info, void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + int working = 0; + int i; + int role; + + info->array.major_version = 1; + info->array.minor_version = __le32_to_cpu(sb->feature_map); + info->array.patch_version = 0; + info->array.raid_disks = __le32_to_cpu(sb->raid_disks); + info->array.level = __le32_to_cpu(sb->level); + info->array.md_minor = -1; + info->array.ctime = __le64_to_cpu(sb->ctime); + + info->disk.major = 0; + info->disk.minor = 0; + + if (__le32_to_cpu(sb->dev_number) >= __le32_to_cpu(sb->max_dev) || + __le32_to_cpu(sb->max_dev) > 512) + role = 0xfffe; + else + role = __le16_to_cpu(sb->dev_roles[__le32_to_cpu(sb->dev_number)]); + + info->disk.raid_disk = -1; + switch(role) { + case 0xFFFF: + info->disk.state = 2; /* spare: ACTIVE, not sync, not faulty */ + break; + case 0xFFFE: + info->disk.state = 1; /* faulty */ + break; + default: + info->disk.state = 6; /* active and in sync */ + info->disk.raid_disk = role; + } + info->events = __le64_to_cpu(sb->events); + + memcpy(info->uuid, sb->set_uuid, 16); + + for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { + role = __le16_to_cpu(sb->dev_roles[i]); + if (role == 0xFFFF || role < info->array.raid_disks) + working++; + } + + info->array.working_disks = working; +} + +static int update_super1(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose) +{ + int rv = 0; + struct mdp_superblock_1 *sb = sbv; + + if (strcmp(update, "force")==0) { + sb->events = __cpu_to_le32(info->events); + switch(__le32_to_cpu(sb->level)) { + case 5: case 4: case 6: + /* need to force clean */ + sb->resync_offset = ~0ULL; + } + } + if (strcmp(update, "assemble")==0) { + int d = info->disk.number; + int want; + if (info->disk.state == 6) + want = __cpu_to_le32(info->disk.raid_disk); + else + want = 0xFFFF; + if (sb->dev_roles[d] != want) { + sb->dev_roles[d] = want; + rv = 1; + } + } +#if 0 + if (strcmp(update, "newdev") == 0) { + int d = info->disk.number; + memset(&sb->disks[d], 0, sizeof(sb->disks[d])); + sb->disks[d].number = d; + sb->disks[d].major = info->disk.major; + sb->disks[d].minor = info->disk.minor; + sb->disks[d].raid_disk = info->disk.raid_disk; + sb->disks[d].state = info->disk.state; + sb->this_disk = sb->disks[d]; + } +#endif + if (strcmp(update, "grow") == 0) { + sb->raid_disks = __cpu_to_le32(info->array.raid_disks); + /* FIXME */ + } + if (strcmp(update, "resync") == 0) { + /* make sure resync happens */ + sb->resync_offset = ~0ULL; + } + + sb->sb_csum = calc_sb_1_csum(sb); + return rv; +} + + +static __u64 event_super1(void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + return __le64_to_cpu(sb->events); +} + +static int init_super1(void **sbp, mdu_array_info_t *info) +{ + struct mdp_superblock_1 *sb = malloc(1024); + int spares; + memset(sb, 0, 1024); + + if (info->major_version == -1) + /* zeroing superblock */ + return 0; + + spares = info->working_disks - info->active_disks; + if (info->raid_disks + spares > 384) { + fprintf(stderr, Name ": too many devices requested: %d+%d > %d\n", + info->raid_disks , spares, 384); + return 0; + } + + + sb->magic = __cpu_to_le32(MD_SB_MAGIC); + sb->major_version = __cpu_to_le32(1); + sb->feature_map = 0; + sb->pad0 = 0; + *(__u32*)(sb->set_uuid) = random(); + *(__u32*)(sb->set_uuid+4) = random(); + *(__u32*)(sb->set_uuid+8) = random(); + *(__u32*)(sb->set_uuid+12) = random(); + + /* FIXME name */ + + sb->ctime = __cpu_to_le64((unsigned long long)time(0)); + sb->level = __cpu_to_le32(info->level); + sb->layout = __cpu_to_le32(info->level); + sb->size = __cpu_to_le64(info->size*2ULL); + sb->chunksize = __cpu_to_le32(info->chunk_size>>9); + sb->raid_disks = __cpu_to_le32(info->raid_disks); + + sb->data_offset = __cpu_to_le64(0); + sb->data_size = __cpu_to_le64(0); + sb->super_offset = __cpu_to_le64(0); + sb->recovery_offset = __cpu_to_le64(0); + + sb->utime = sb->ctime; + sb->events = __cpu_to_le64(1); + if (info->state & MD_SB_CLEAN) + sb->resync_offset = ~0ULL; + else + sb->resync_offset = 0; + sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/ + sizeof(sb->dev_roles[0])); + memset(sb->pad3, 0, sizeof(sb->pad3)); + + memset(sb->dev_roles, 0xff, 1024 - sizeof(struct mdp_superblock_1)); + + *sbp = sb; + return 1; +} + +/* Add a device to the superblock being created */ +static void add_to_super1(void *sbv, mdu_disk_info_t *dk) +{ + struct mdp_superblock_1 *sb = sbv; + __u16 *rp = sb->dev_roles + dk->number; + if (dk->state == 6) /* active, sync */ + *rp = __cpu_to_le16(dk->raid_disk); + else if (dk->state == 2) /* active -> spare */ + *rp = 0xffff; + else + *rp = 0xfffe; +} + +static int store_super1(int fd, void *sbv) +{ + struct mdp_superblock_1 *sb = sbv; + long long sb_offset; + int sbsize; + + + sb_offset = __le64_to_cpu(sb->super_offset) << 9; + + if (lseek64(fd, sb_offset, 0)< 0LL) + return 3; + + sbsize = sizeof(*sb) + 2 * __le32_to_cpu(sb->max_dev); + + if (write(fd, sb, sbsize) != sbsize) + return 4; + + return 0; +} + +static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname) +{ + struct mdp_superblock_1 *sb = sbv; + int fd = open(devname, O_RDWR, O_EXCL); + int rv; + + long size; + long long sb_offset; + + + if (fd < 0) { + fprintf(stderr, Name ": Failed to open %s to write superblock\n", + devname); + return -1; + } + + sb->dev_number = __cpu_to_le32(dinfo->number); + *(__u32*)(sb->device_uuid) = random(); + *(__u32*)(sb->device_uuid+4) = random(); + *(__u32*)(sb->device_uuid+8) = random(); + *(__u32*)(sb->device_uuid+12) = random(); + + + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + + if (size < 24) + return 2; + + + /* + * Calculate the position of the superblock. + * It is always aligned to a 4K boundary and + * depending on minor_version, it can be: + * 0: At least 8K, but less than 12K, from end of device + * 1: At start of device + * 2: 4K from start of device. + */ + switch(st->minor_version) { + case 0: + sb_offset = size; + sb_offset -= 8*2; + sb_offset &= ~(4*2-1); + sb->super_offset = __cpu_to_le64(sb_offset); + sb->data_offset = __cpu_to_le64(0); + sb->data_size = sb->super_offset; + break; + case 1: + sb->super_offset = __cpu_to_le64(0); + sb->data_offset = __cpu_to_le64(2); + sb->data_size = __cpu_to_le64(size - 2); + break; + case 2: + sb_offset = 4*2; + sb->super_offset = __cpu_to_le64(sb_offset); + sb->data_offset = __cpu_to_le64(sb_offset+2); + sb->data_size = __cpu_to_le64(size - 4*2 - 2); + break; + default: + return -EINVAL; + } + + + sb->sb_csum = calc_sb_1_csum(sb); + rv = store_super1(fd, sb); + if (rv) + fprintf(stderr, Name ": failed to write superblock to %s\n", devname); + return rv; +} + +static int compare_super1(void **firstp, void *secondv) +{ + /* + * return: + * 0 same, or first was empty, and second was copied + * 1 second had wrong number + * 2 wrong uuid + * 3 wrong other info + */ + struct mdp_superblock_1 *first = *firstp; + struct mdp_superblock_1 *second = secondv; + + if (second->magic != __cpu_to_le32(MD_SB_MAGIC)) + return 1; + if (second->major_version != __cpu_to_le32(1)) + return 1; + + if (!first) { + first = malloc(1024); + memcpy(first, second, 1024); + *firstp = first; + return 0; + } + if (memcmp(first->set_uuid, second->set_uuid, 16)!= 0) + return 2; + + if (first->ctime != second->ctime || + first->level != second->level || + first->layout != second->layout || + first->size != second->size || + first->chunksize != second->chunksize || + first->raid_disks != second->raid_disks) + return 3; + return 0; +} + +static int load_super1(struct supertype *st, int fd, void **sbp, char *devname) +{ + unsigned long size; + unsigned long long sb_offset; + struct mdp_superblock_1 *super; + + + + if (st->ss == NULL) { + /* guess... */ + st->ss = &super1; + for (st->minor_version = 0; st->minor_version <= 2 ; st->minor_version++) { + switch(load_super1(st, fd, sbp, devname)) { + case 0: return 0; /* good */ + case 1: st->ss = NULL; return 1; /*bad device */ + case 2: break; /* bad, try next */ + } + } + st->ss = NULL; + return 2; + } + if (ioctl(fd, BLKGETSIZE, &size)) { + if (devname) + fprintf(stderr, Name ": cannot find device size for %s: %s\n", + devname, strerror(errno)); + return 1; + } + + if (size < 24) { + if (devname) + fprintf(stderr, Name ": %s is too small for md: size is %lu sectors.\n", + devname, size); + return 1; + } + + /* + * Calculate the position of the superblock. + * It is always aligned to a 4K boundary and + * depeding on minor_version, it can be: + * 0: At least 8K, but less than 12K, from end of device + * 1: At start of device + * 2: 4K from start of device. + */ + switch(st->minor_version) { + case 0: + sb_offset = size; + sb_offset -= 8*2; + sb_offset &= ~(4*2-1); + break; + case 1: + sb_offset = 0; + break; + case 2: + sb_offset = 4*2; + break; + default: + return -EINVAL; + } + + ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ + + + if (lseek64(fd, sb_offset << 9, 0)< 0LL) { + if (devname) + fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", + devname, strerror(errno)); + return 1; + } + + super = malloc(1024); + + if (read(fd, super, 1024) != 1024) { + if (devname) + fprintf(stderr, Name ": Cannot read superblock on %s\n", + devname); + free(super); + return 1; + } + + if (__le32_to_cpu(super->magic) != MD_SB_MAGIC) { + if (devname) + fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", + devname, MD_SB_MAGIC, __le32_to_cpu(super->magic)); + free(super); + return 2; + } + + if (__le32_to_cpu(super->major_version) != 1) { + if (devname) + fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", + devname, __le32_to_cpu(super->major_version)); + free(super); + return 2; + } + if (__le64_to_cpu(super->super_offset) != sb_offset) { + if (devname) + fprintf(stderr, Name ": No superblock found on %s (super_offset is wrong)\n", + devname); + free(super); + return 2; + } + *sbp = super; + return 0; +} + + +static struct supertype *match_metadata_desc1(char *arg) +{ + struct supertype *st = malloc(sizeof(*st)); + if (!st) return st; + + st->ss = &super1; + if (strcmp(arg, "1") == 0 || + strcmp(arg, "1.0") == 0) { + st->minor_version = 0; + return st; + } + if (strcmp(arg, "1.1") == 0) { + st->minor_version = 1; + return st; + } + if (strcmp(arg, "1.2") == 0) { + st->minor_version = 2; + return st; + } + + free(st); + return NULL; +} + +static __u64 avail_size1(__u64 devsize) +{ + if (devsize < 24) + return 0; + + return (devsize - 8*2 ) & ~(4*2-1); +} + +struct superswitch super1 = { + .examine_super = examine_super1, + .brief_examine_super = brief_examine_super1, + .detail_super = detail_super1, + .brief_detail_super = brief_detail_super1, + .uuid_from_super = uuid_from_super1, + .getinfo_super = getinfo_super1, + .update_super = update_super1, + .event_super = event_super1, + .init_super = init_super1, + .add_to_super = add_to_super1, + .store_super = store_super1, + .write_init_super = write_init_super1, + .compare_super = compare_super1, + .load_super = load_super1, + .match_metadata_desc = match_metadata_desc1, + .avail_size = avail_size1, + .major = 1, +}; diff --git a/util.c b/util.c index f243d884..bb4a4794 100644 --- a/util.c +++ b/util.c @@ -210,25 +210,21 @@ int check_raid(int fd, char *name) void *super; struct mdinfo info; time_t crtime; + struct supertype *st = guess_super(fd); - int i; - for (i=0; superlist[i]; i++) { - if (superlist[i]->load_super(fd, &super, name)) - continue; - /* Looks like a raid array .. */ - fprintf(stderr, Name ": %s appears to be part of a raid array:\n", - name); - superlist[i]->getinfo_super(&info, super); - free(super); - crtime = info.array.ctime; - fprintf(stderr, " level=%d devices=%d ctime=%s", - info.array.level, info.array.raid_disks, ctime(&crtime)); - return 1; - } - return 0; + if (!st) return 0; + st->ss->load_super(st, fd, &super, name); + /* Looks like a raid array .. */ + fprintf(stderr, Name ": %s appears to be part of a raid array:\n", + name); + st->ss->getinfo_super(&info, super); + free(super); + crtime = info.array.ctime; + fprintf(stderr, " level=%d devices=%d ctime=%s", + info.array.level, info.array.raid_disks, ctime(&crtime)); + return 1; } - int ask(char *mesg) { char *add = ""; @@ -526,38 +522,42 @@ void put_md_name(char *name) -struct superswitch *superlist[] = { &super0, NULL }; +struct superswitch *superlist[] = { &super0, &super1, NULL }; -struct superswitch *super_by_version(int vers) +struct supertype *super_by_version(int vers, int minor) { - if (vers == 0) return &super0; - return NULL; + struct supertype *st = malloc(sizeof(*st)); + if (!st) return st; + if (vers == 0) + st->ss = &super0; + + if (vers == 1) + st->ss = &super1; + st->minor_version = minor; + return st; } -struct superswitch *guess_super(int fd, char *dev) +struct supertype *guess_super(int fd) { /* try each load_super to find the best match, * and return the best superswitch */ - struct superswitch *best = NULL, *ss; - int bestrv = 0; + struct superswitch *ss; + struct supertype *st; + void *sbp = NULL; int i; + st = malloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); for (i=0 ; superlist[i]; i++) { int rv; ss = superlist[i]; - rv = ss->load_super(fd, &sbp, NULL); + rv = ss->load_super(st, fd, &sbp, NULL); if (rv == 0) { free(sbp); - return ss; - } - if (rv > bestrv) { - bestrv = rv; - best = ss; + return st; } } - if (bestrv > 2) /* FIXME */ - return best; return NULL; } -- 2.39.2