From 4b1ac34b51a3783ab528b1af307156fab057b543 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 3 May 2005 23:44:18 +0000 Subject: [PATCH] Separate sueprblock handling into separate file Signed-off-by: Neil Brown --- Assemble.c | 241 +++++++++--------------- Create.c | 95 ++++++---- Detail.c | 40 ++-- Examine.c | 180 +++--------------- Grow.c | 72 ++++--- Kill.c | 30 +-- Makefile | 5 +- Query.c | 49 ++--- ReadMe.c | 1 + mdadm.h | 28 ++- super0.c | 539 +++++++++++++++++++++++++++++++++++++++++++++++++++++ util.c | 160 ++-------------- 12 files changed, 823 insertions(+), 617 deletions(-) create mode 100644 super0.c diff --git a/Assemble.c b/Assemble.c index ace5717c..e762c693 100644 --- a/Assemble.c +++ b/Assemble.c @@ -28,8 +28,6 @@ */ #include "mdadm.h" -#include "md_u.h" -#include "md_p.h" int Assemble(char *mddev, int mdfd, mddev_ident_t ident, char *conffile, @@ -52,11 +50,11 @@ int Assemble(char *mddev, int mdfd, * Much of the work of Assemble is in finding and/or * checking the disks to make sure they look right. * - * If mddev is not set, then scan must be and we + * If mddev is not set, then scan must be set and we * read through the config file for dev+uuid mapping * We recurse, setting mddev, for each device that * - isn't running - * - has a valid uuid (or any uuid if !uuidset + * - has a valid uuid (or any uuid if !uuidset) * * If mddev is set, we try to determine state of md. * check version - must be at least 0.90.0 @@ -74,9 +72,9 @@ int Assemble(char *mddev, int mdfd, * Check superblock - discard if bad * Check uuid (set if we don't have one) - discard if no match * Check superblock similarity if we have a superblock - discard if different - * Record events, devicenum, utime + * Record events, devicenum * This should give us a list of devices for the array - * We should collect the most recent event and utime numbers + * We should collect the most recent event number * * Count disks with recent enough event count * While force && !enough disks @@ -94,14 +92,12 @@ int Assemble(char *mddev, int mdfd, */ int old_linux = 0; int vers; - mdu_array_info_t array; - mdp_super_t first_super, super; + void *first_super = NULL, *super = NULL; struct { char *devname; unsigned int major, minor; unsigned int oldmajor, oldminor; long long events; - time_t utime; int uptodate; int state; int raid_disk; @@ -119,6 +115,7 @@ int Assemble(char *mddev, int mdfd, int start_partial_ok = force || devlist==NULL; unsigned int num_devs; mddev_dev_t tmpdev; + struct mdinfo info; vers = md_get_version(mdfd); if (vers <= 0) { @@ -133,7 +130,7 @@ int Assemble(char *mddev, int mdfd, if (get_linux_version() < 2004000) old_linux = 1; - if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) { + if (ioctl(mdfd, GET_ARRAY_INFO, &info.array)>=0) { fprintf(stderr, Name ": device %s already active - cannot assemble it\n", mddev); return 1; @@ -165,12 +162,8 @@ int Assemble(char *mddev, int mdfd, num_devs++; tmpdev = tmpdev->next; } - best = malloc(num_devs * sizeof(*best)); devices = malloc(num_devs * sizeof(*devices)); - first_super.md_magic = 0; - for (i=0; idevname; devlist = devlist->next; @@ -192,6 +183,11 @@ int Assemble(char *mddev, int mdfd, fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); continue; } + + if (super) { + free(super); + super = NULL; + } dfd = open(devname, O_RDONLY|O_EXCL, 0); if (dfd < 0) { @@ -207,40 +203,39 @@ int Assemble(char *mddev, int mdfd, fprintf(stderr, Name ": %s is not a block device.\n", devname); close(dfd); - } else if (load_super(dfd, &super)) { + } else if (load_super0(dfd, &super, NULL)) { if (inargv || verbose) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); close(dfd); } else { - havesuper =1; - uuid_from_super(this_uuid, &super); + getinfo_super0(&info, super); close(dfd); } if (ident->uuid_set && - (!havesuper || same_uuid(this_uuid, ident->uuid)==0)) { + (!super || same_uuid(info.uuid, ident->uuid)==0)) { if (inargv || verbose) fprintf(stderr, Name ": %s has wrong uuid.\n", devname); continue; } if (ident->super_minor != UnSet && - (!havesuper || ident->super_minor != super.md_minor)) { + (!super || ident->super_minor != info.array.md_minor)) { if (inargv || verbose) fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); continue; } if (ident->level != UnSet && - (!havesuper|| ident->level != (int)super.level)) { + (!super|| ident->level != info.array.level)) { if (inargv || verbose) fprintf(stderr, Name ": %s has wrong raid level.\n", devname); continue; } if (ident->raid_disks != UnSet && - (!havesuper || ident->raid_disks!= super.raid_disks)) { + (!super || ident->raid_disks!= info.array.raid_disks)) { if (inargv || verbose) fprintf(stderr, Name ": %s requires wrong number of drives.\n", devname); @@ -252,85 +247,34 @@ int Assemble(char *mddev, int mdfd, * then we cannot continue */ - if (!havesuper) { + if (!super) { fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", devname); + free(first_super); return 1; } - if (compare_super(&first_super, &super)) { + if (compare_super0(&first_super, super)) { fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", devname); + free(super); + free(first_super); return 1; } - - /* this is needed until we get a more relaxed super block format */ - if (devcnt >= MD_SB_DISKS) { - fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n", - devname); - continue; - } - /* looks like a good enough match to update the super block if needed */ if (update) { - if (strcmp(update, "sparc2.2")==0 ) { - /* 2.2 sparc put the events in the wrong place - * So we copy the tail of the superblock - * up 4 bytes before continuing - */ - __u32 *sb32 = (__u32*)&super; - memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7, - sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1, - (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4); - fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n", - devname); - } - if (strcmp(update, "super-minor") ==0) { - struct stat stb2; - fstat(mdfd, &stb2); - super.md_minor = minor(stb2.st_rdev); - if (verbose) - fprintf(stderr, Name ": updating superblock of %s with minor number %d\n", - devname, super.md_minor); - } - if (strcmp(update, "summaries") == 0) { - /* set nr_disks, active_disks, working_disks, - * failed_disks, spare_disks based on disks[] - * array in superblock. - * Also make sure extra slots aren't 'failed' - */ - super.nr_disks = super.active_disks = - super.working_disks = super.failed_disks = - super.spare_disks = 0; - for (i=0; i < MD_SB_DISKS ; i++) - if (super.disks[i].major || - super.disks[i].minor) { - int state = super.disks[i].state; - if (state & (1<= 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<= 0) @@ -339,23 +283,22 @@ int Assemble(char *mddev, int mdfd, if (verbose) fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", - devname, mddev, super.this_disk.raid_disk); + devname, mddev, info.disk.raid_disk); devices[devcnt].devname = devname; devices[devcnt].major = major(stb.st_rdev); devices[devcnt].minor = minor(stb.st_rdev); - devices[devcnt].oldmajor = super.this_disk.major; - devices[devcnt].oldminor = super.this_disk.minor; - devices[devcnt].events = md_event(&super); - devices[devcnt].utime = super.utime; - devices[devcnt].raid_disk = super.this_disk.raid_disk; + devices[devcnt].oldmajor = info.disk.major; + devices[devcnt].oldminor = info.disk.minor; + devices[devcnt].events = info.events; + devices[devcnt].raid_disk = info.disk.raid_disk; devices[devcnt].uptodate = 0; - devices[devcnt].state = super.this_disk.state; + devices[devcnt].state = info.disk.state; if (most_recent < devcnt) { if (devices[devcnt].events > devices[most_recent].events) most_recent = devcnt; } - if ((int)super.level == -4) + if (info.array.level == -4) /* with multipath, the raid_disk from the superblock is meaningless */ i = devcnt; else @@ -381,11 +324,19 @@ int Assemble(char *mddev, int mdfd, devcnt++; } + if (super) + free(super); + super = NULL; + if (devcnt == 0) { fprintf(stderr, Name ": no devices found for %s\n", mddev); + free(first_super); return 1; } + + getinfo_super0(&info, first_super); + /* now we have some devices that might be suitable. * I wonder how many */ @@ -398,7 +349,7 @@ int Assemble(char *mddev, int mdfd, /* note: we ignore error flags in multipath arrays * as they don't make sense */ - if ((int)first_super.level != -4) + if (info.array.level != -4) if (!(devices[j].state & (1<= devices[most_recent].events) { devices[j].uptodate = 1; - if (i < first_super.raid_disks) + if (i < info.array.raid_disks) okcnt++; else sparecnt++; } } - while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) { + while (force && !enough(info.array.level, info.array.raid_disks, okcnt)) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. */ int fd; chosen_drive = -1; - for (i=0; i=0 && !devices[j].uptodate && @@ -442,31 +393,29 @@ int Assemble(char *mddev, int mdfd, devices[chosen_drive].events = 0; continue; } - if (load_super(fd, &super)) { + if (load_super0(fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; continue; } - super.events_hi = (devices[most_recent].events>>32)&0xFFFFFFFF; - super.events_lo = (devices[most_recent].events)&0xFFFFFFFF; - if (super.level == 5 || super.level == 4) { - /* need to force clean */ - super.state = (1<= req_cnt || start_partial_ok) ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { fprintf(stderr, Name ": %s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); - if (okcnt < first_super.raid_disks) - fprintf(stderr, " (out of %d)", first_super.raid_disks); + if (okcnt < info.array.raid_disks) + fprintf(stderr, " (out of %d)", info.array.raid_disks); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); fprintf(stderr, ".\n"); @@ -649,13 +584,13 @@ This doesnt work yet fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); - if (!enough(first_super.level, first_super.raid_disks, okcnt)) + if (!enough(info.array.level, info.array.raid_disks, okcnt)) fprintf(stderr, " - not enough to start the array.\n"); else { - if (req_cnt == first_super.raid_disks) + if (req_cnt == info.array.raid_disks) fprintf(stderr, " - need all %d to start it", req_cnt); else - fprintf(stderr, " - need %d of %d to start", req_cnt, first_super.raid_disks); + fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks); fprintf(stderr, " (use --run to insist).\n"); } return 1; diff --git a/Create.c b/Create.c index 66a88d20..87a275e2 100644 --- a/Create.c +++ b/Create.c @@ -62,7 +62,8 @@ int Create(char *mddev, int mdfd, int first_missing = MD_SB_DISKS*2; int missing_disks = 0; int insert_point = MD_SB_DISKS*2; /* where to insert a missing drive */ - mddev_dev_t moved_disk = NULL; /* the disk that was moved out of the insert point */ + void *super; + int pass; mdu_array_info_t array; @@ -342,50 +343,70 @@ int Create(char *mddev, int mdfd, array.layout = layout; array.chunk_size = chunk*1024; - if (ioctl(mdfd, SET_ARRAY_INFO, &array)) { + if (ioctl(mdfd, SET_ARRAY_INFO, NULL)) { fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", mddev, strerror(errno)); return 1; } - - for (dnum=0, dv = devlist ; dv ; dv=(dv->next)?(dv->next):moved_disk, dnum++) { - int fd; - struct stat stb; - mdu_disk_info_t disk; - disk.number = dnum; - if (dnum == insert_point) { - moved_disk = dv; - } - disk.raid_disk = disk.number; - if (disk.raid_disk < raiddisks) - disk.state = 6; /* active and in sync */ - else - disk.state = 0; - if (dnum == insert_point || - strcasecmp(dv->devname, "missing")==0) { - disk.major = 0; - disk.minor = 0; - disk.state = 1; /* faulty */ - } else { - fd = open(dv->devname, O_RDONLY|O_EXCL, 0); - if (fd < 0) { - fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n", - dv->devname); - return 1; + init_super0(&super, &array); + + + for (pass=1; pass <=2 ; pass++) { + mddev_dev_t moved_disk = NULL; /* the disk that was moved out of the insert point */ + + for (dnum=0, dv = devlist ; dv ; + dv=(dv->next)?(dv->next):moved_disk, dnum++) { + int fd; + struct stat stb; + mdu_disk_info_t disk; + + disk.number = dnum; + if (dnum == insert_point) { + moved_disk = dv; } - fstat(fd, &stb); - disk.major = major(stb.st_rdev); - disk.minor = minor(stb.st_rdev); - close(fd); - } - if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { - fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", - dv->devname, strerror(errno)); - return 1; + disk.raid_disk = disk.number; + if (disk.raid_disk < raiddisks) + disk.state = 6; /* active and in sync */ + else + disk.state = 0; + if (dnum == insert_point || + strcasecmp(dv->devname, "missing")==0) { + disk.major = 0; + disk.minor = 0; + disk.state = 1; /* faulty */ + } else { + fd = open(dv->devname, O_RDONLY|O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n", + dv->devname); + return 1; + } + fstat(fd, &stb); + disk.major = major(stb.st_rdev); + disk.minor = minor(stb.st_rdev); + close(fd); + } + switch(pass){ + case 1: + add_to_super0(super, &disk); + break; + case 2: + write_init_super0(super, &disk, dv->devname); + + if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { + fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", + dv->devname, strerror(errno)); + free(super); + return 1; + } + + break; + } + if (dv == moved_disk && dnum != insert_point) break; } - if (dv == moved_disk && dnum != insert_point) break; } + free(super); /* param is not actually used */ if (runstop == 1 || subdevs >= raiddisks) { diff --git a/Detail.c b/Detail.c index 7555a9ac..59b091fe 100644 --- a/Detail.c +++ b/Detail.c @@ -51,8 +51,7 @@ int Detail(char *dev, int brief, int test) int is_rebuilding = 0; int failed = 0; - mdp_super_t super; - int have_super = 0; + void *super = NULL; int rv = test ? 4 : 1; if (fd < 0) { @@ -99,16 +98,21 @@ int Detail(char *dev, int brief, int test) 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; + load_super0(fd2, &super, NULL) == 0) { + struct mdinfo info; + getinfo_super0(&info, super); + if (info.array.ctime != array.ctime || + info.array.level != array.level) { + free(super); + super = NULL; + } + } if (fd2 >= 0) close(fd2); } } @@ -198,15 +202,8 @@ int Detail(char *dev, int brief, int test) } 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); - } + if (super) + detail_super0(super); printf(" Number Major Minor RaidDevice State\n"); } @@ -278,14 +275,9 @@ int Detail(char *dev, int brief, int test) if (!brief) printf("\n"); } if (spares && brief) printf(" spares=%d", spares); - 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 (super && brief) + brief_detail_super0(super); + if (brief && devices) printf("\n devices=%s", devices); if (brief) printf("\n"); if (test && (rv&2)) rv &= ~1; diff --git a/Examine.c b/Examine.c index 79537fa7..cd79583a 100644 --- a/Examine.c +++ b/Examine.c @@ -54,18 +54,16 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) * if devlist==NULL, use conf_get_devs( */ int fd; - time_t atime; - mdp_super_t super; - int d; - char *c; + void *super = NULL; int rv = 0; int err; - int spares = 0; struct array { - mdp_super_t super; + void *super; + struct mdinfo info; void *devs; struct array *next; + int spares; } *arrays = NULL; for (; devlist ; devlist=devlist->next) { @@ -77,48 +75,21 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) err = 1; } else { - err = load_super(fd, &super); + err = load_super0(fd, &super, (brief||scan)?NULL:devlist->devname); close(fd); } - if (err && (brief||scan)) + if (err) continue; if (err) rv =1; - switch(err) { - case 1: - fprintf(stderr, Name ": cannot find device size for %s: %s\n", - devlist->devname, strerror(errno)); - continue; - case 2: -/* fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n", - devlist->devname, size); -*/ - fprintf(stderr, Name ": %s is too small for md\n", - devlist->devname); - continue; - case 3: - fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", - devlist->devname, strerror(errno)); - continue; - case 4: - fprintf(stderr, Name ": Cannot read superblock on %s\n", - devlist->devname); - continue; - case 5: - fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", - devlist->devname, MD_SB_MAGIC, super.md_magic); - continue; - case 6: - fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", - devlist->devname, super.major_version); - continue; - } - + + if (SparcAdjust) + update_super0(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 (compare_super(&ap->super, &super)==0) + if (compare_super0(&ap->super, super)==0) break; } if (!ap) { @@ -126,140 +97,37 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust) ap->super = super; ap->devs = dl_head(); ap->next = arrays; + ap->spares = 0; arrays = ap; + getinfo_super0(&ap->info, super); + } else { + getinfo_super0(&ap->info, super); + free(super); } + if (!(ap->info.disk.state & MD_DISK_SYNC)) + ap->spares++; d = dl_strdup(devlist->devname); dl_add(ap->devs, d); } else { printf("%s:\n",devlist->devname); - printf(" Magic : %08x\n", super.md_magic); - printf(" Version : %02d.%02d.%02d\n", super.major_version, super.minor_version, - super.patch_version); - if (super.minor_version >= 90) - printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1, - super.set_uuid2, super.set_uuid3); - else - printf(" UUID : %08x\n", super.set_uuid0); - - atime = super.ctime; - printf(" Creation Time : %.24s\n", ctime(&atime)); - c=map_num(pers, super.level); - printf(" Raid Level : %s\n", c?c:"-unknown-"); - if (super.level <= 0) - printf(" Device Size : %u%s\n", super.size, human_size((long long)super.size<<10)); - printf(" Raid Devices : %d\n", super.raid_disks); - printf(" Total Devices : %d\n", super.nr_disks); - printf("Preferred Minor : %d\n", super.md_minor); - printf("\n"); - atime = super.utime; - printf(" Update Time : %.24s\n", ctime(&atime)); - printf(" State : %s\n", - (super.state&(1< 0 && - (super.state & (1<>8) & 255); - - switch(super.level) { - case 0: - case 4: - case 5: - printf(" Chunk Size : %dK\n", super.chunk_size/1024); - break; - case -1: - printf(" Rounding : %dK\n", super.chunk_size/1024); - break; - default: break; - } - printf("\n"); - printf(" Number Major Minor RaidDevice State\n"); - for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) { - mdp_disk_t *dp; - char *dv; - char nb[5]; - if (d>=0) dp = &super.disks[d]; - else dp = &super.this_disk; - sprintf(nb, "%4d", d); - printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb, - dp->number, dp->major, dp->minor, dp->raid_disk); - if (dp->state & (1<state & (1<state & (1<state & (1<state == 0) { printf(" spare"); spares++; } - if ((dv=map_dev(dp->major, dp->minor))) - printf(" %s", dv); - printf("\n"); - if (d == -1) printf("\n"); - } - } - if (SparcAdjust == 2) { - printf(" ----- updating superblock on device ----\n"); - fd = open(devlist->devname, O_RDWR); - if (fd < 0) { - fprintf(stderr, Name ": cannot open %s to update superblock: %s\n", - devlist->devname, strerror(errno)); - err = 1; - } else { - super.sb_csum = calc_sb_csum(&super); - if (store_super(fd, &super)) { - fprintf(stderr, Name ": Count not re-write superblock on %s\n", - devlist->devname); - err = 1; - } - close(fd); - } + examine_super0(super); + free(super); } } if (brief) { struct array *ap; for (ap=arrays; ap; ap=ap->next) { char sep='='; - char *c=map_num(pers, ap->super.level); char *d; - printf("ARRAY %s level=%s num-devices=%d UUID=", - get_md_name(ap->super.md_minor), - c?c:"-unknown-", ap->super.raid_disks); - if (spares) printf(" spares=%d", spares); - if (ap->super.minor_version >= 90) - printf("%08x:%08x:%08x:%08x", ap->super.set_uuid0, ap->super.set_uuid1, - ap->super.set_uuid2, ap->super.set_uuid3); - else - printf("%08x", ap->super.set_uuid0); - printf("\n devices"); + brief_examine_super0(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)) { printf("%c%s", sep, d); sep=','; } + free(ap->super); + /* FIXME free ap */ printf("\n"); } } diff --git a/Grow.c b/Grow.c index 3f8a1c66..8de28d40 100644 --- a/Grow.c +++ b/Grow.c @@ -45,20 +45,20 @@ int Grow_Add_device(char *devname, int fd, char *newdev) * 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 mdinfo info; + + void *super = NULL; struct stat stb; int nfd, fd2; int d, nd; - if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) { + if (ioctl(fd, GET_ARRAY_INFO, &info.array) < 0) { fprintf(stderr, Name ": cannot get array info for %s\n", devname); return 1; } - if (array.level != -1) { + if (info.array.level != -1) { fprintf(stderr, Name ": can only add devices to linear arrays\n"); return 1; } @@ -75,7 +75,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev) return 1; } /* now check out all the devices and make sure we can read the superblock */ - for (d=0 ; d < array.raid_disks ; d++) { + for (d=0 ; d < info.array.raid_disks ; d++) { mdu_disk_info_t disk; char *dv; @@ -96,7 +96,9 @@ int Grow_Add_device(char *devname, int fd, char *newdev) fprintf(stderr, Name ": cannot open device file %s\n", dv); return 1; } - if (load_super(fd2, &super)) { + if (super) free(super); + super= NULL; + if (load_super0(fd2, &super, NULL)) { fprintf(stderr, Name ": cannot find super block on %s\n", dv); close(fd2); return 1; @@ -107,27 +109,21 @@ int Grow_Add_device(char *devname, int fd, char *newdev) * 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); + info.disk.number = d; + info.disk.major = major(stb.st_rdev); + info.disk.minor = minor(stb.st_rdev); + info.disk.raid_disk = d; + info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + update_super0(&info, super, "grow", newdev, 0); - super.this_disk = super.disks[d]; - super.sb_csum = calc_sb_csum(&super); - if (store_super(nfd, &super)) { + if (store_super0(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) { + + if (ioctl(fd, ADD_NEW_DISK, &info.disk) != 0) { fprintf(stderr, Name ": Cannot add new disk to this array\n"); return 1; } @@ -135,13 +131,13 @@ int Grow_Add_device(char *devname, int fd, char *newdev) * Now go through and update all superblocks */ - if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) { + if (ioctl(fd, GET_ARRAY_INFO, &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++) { + for (d=0 ; d < info.array.raid_disks ; d++) { mdu_disk_info_t disk; char *dv; @@ -162,25 +158,23 @@ int Grow_Add_device(char *devname, int fd, char *newdev) fprintf(stderr, Name ": cannot open device file %s\n", dv); return 1; } - if (load_super(fd2, &super)) { + if (load_super0(fd2, &super, NULL)) { 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)) { + info.array.raid_disks = nd+1; + info.array.nr_disks = nd+1; + info.array.active_disks = nd+1; + info.array.working_disks = nd+1; + info.disk.number = nd; + info.disk.major = major(stb.st_rdev); + info.disk.minor = minor(stb.st_rdev); + info.disk.raid_disk = nd; + info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); + update_super0(&info, super, "grow", dv, 0); + + if (store_super0(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 9441f73b..fbda6863 100644 --- a/Kill.c +++ b/Kill.c @@ -41,7 +41,7 @@ int Kill(char *dev, int force) * Definitely not safe. */ - mdp_super_t super; + void *super; int fd, rv = 0; fd = open(dev, O_RDWR|O_EXCL); @@ -50,32 +50,18 @@ int Kill(char *dev, int force) dev); return 1; } - rv = load_super(fd, &super); - if (force && rv >= 5) + rv = load_super0(fd, &super, dev); + if (force && rv >= 2) rv = 0; /* ignore bad data in superblock */ - switch(rv) { - case 1: - fprintf(stderr, Name ": cannot file device size for %s: %s\n", - dev, strerror(errno)); - break; - case 2: - fprintf(stderr, Name ": %s is too small for md.\n", dev); - break; - case 3: - case 4: - fprintf(stderr, Name ": cannot access superblock on %s.\n", dev); - break; - case 5: - case 6: - fprintf(stderr, Name ": %s does not appear to have an MD superblock.\n", dev); - break; - } - if (!rv) { + if (rv== 0 || (force && rv >= 2)) { memset(&super, 0, sizeof(super)); - if (store_super(fd, &super)) { + if (store_super0(fd, super)) { fprintf(stderr, Name ": Could not zero superblock on %s\n", dev); rv = 1; + } else if (rv) { + fprintf(stderr, Name ": superblock zeroed anyway\n"); + rv = 0; } } close(fd); diff --git a/Makefile b/Makefile index 8f0547b9..38cfcdee 100644 --- a/Makefile +++ b/Makefile @@ -58,9 +58,10 @@ 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 + Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o mdopen.o super0.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 + Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c mdopen.c super0.c + ASSEMBLE_SRCS := mdassemble.c Assemble.c config.c dlink.c util.c ifdef MDASSEMBLE_AUTO ASSEMBLE_SRCS += mdopen.c mdstat.c diff --git a/Query.c b/Query.c index 95d69147..71aafd84 100644 --- a/Query.c +++ b/Query.c @@ -41,8 +41,10 @@ int Query(char *dev) int vers; int ioctlerr; int superror, superrno; - mdp_super_t super; + struct mdinfo info; mdu_array_info_t array; + void *super; + unsigned long long larray_size; unsigned long array_size; struct stat stb; @@ -60,8 +62,6 @@ int Query(char *dev) if (ioctl(fd, GET_ARRAY_INFO, &array)<0) ioctlerr = errno; else ioctlerr = 0; - superror = load_super(fd, &super); - superrno = errno; fstat(fd, &stb); @@ -76,7 +76,6 @@ int Query(char *dev) larray_size <<= 9; } else larray_size = 0; } - close(fd); if (vers < 0) printf("%s: is not an md array\n", dev); @@ -95,35 +94,14 @@ int Query(char *dev) array.raid_disks, array.spare_disks, array.spare_disks==1?"":"s"); } - switch(superror) { - case 1: - printf("%s: cannot find device size: %s\n", - dev, strerror(superrno)); - break; - case 2: - printf("%s: is too small to be an md component.\n", - dev); - break; - case 3: - printf("%s: Cannot seek to superblock: %s\n", - dev, strerror(superrno)); - break; - case 4: - printf("%s: Cannot read md superblock.\n", - dev); - break; - case 5: - printf("%s: No md super block found, not an md component.\n", - dev); - break; - case 6: - printf("%s: md superblock present with wrong version: %d\n", - dev, super.major_version); - break; - default: + superror = load_super0(fd, &super, dev); + superrno = errno; + close(fd); + if (superror == 0) { /* array might be active... */ - mddev = get_md_name(super.md_minor); - disc.number = super.this_disk.number; + getinfo_super0(&info, super); + mddev = get_md_name(info.array.md_minor); + disc.number = info.disk.number; activity = "undetected"; if (mddev && (fd = open(mddev, O_RDONLY))>=0) { if (md_get_version(fd) >= 9000 && @@ -138,11 +116,10 @@ int Query(char *dev) } printf("%s: device %d in %d device %s %s md%d. Use mdadm --examine for more detail.\n", dev, - super.this_disk.number, super.raid_disks, + info.disk.number, info.array.raid_disks, activity, - map_num(pers, super.level), - super.md_minor); - break; + map_num(pers, info.array.level), + info.array.md_minor); } return 0; } diff --git a/ReadMe.c b/ReadMe.c index 78073df0..00283e99 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -30,6 +30,7 @@ #include "mdadm.h" char Version[] = Name " - v1.11.0 - 11 April 2005\n"; + /* * File: ReadMe.c * diff --git a/mdadm.h b/mdadm.h index b7f34d10..6638a342 100644 --- a/mdadm.h +++ b/mdadm.h @@ -65,6 +65,14 @@ char *strncpy(char *dest, const char *src, size_t n) __THROW; #include "md_u.h" #include "md_p.h" +/* general information that might be extracted from a superblock */ +struct mdinfo { + mdu_array_info_t array; + mdu_disk_info_t disk; + __u64 events; + unsigned int uuid[4]; +}; + #define Name "mdadm" enum mode { @@ -211,11 +219,10 @@ extern char *conf_line(FILE *file); extern char *conf_word(FILE *file, int allow_key); extern void free_line(char *line); extern int match_oneof(char *devices, char *devname); -extern int load_super(int fd, mdp_super_t *super); extern void uuid_from_super(int uuid[4], mdp_super_t *super); extern int same_uuid(int a[4], int b[4]); -extern int compare_super(mdp_super_t *first, mdp_super_t *second); -extern unsigned long calc_sb_csum(mdp_super_t *super); +/* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/ +extern unsigned long calc_csum(void *super, int bytes); extern int store_super(int fd, mdp_super_t *super); extern int enough(int level, int raid_disks, int avail_disks); extern int ask(char *mesg); @@ -255,3 +262,18 @@ extern int open_mddev(char *dev, int autof); #define ModeMask 0x1f #define ModeShift 5 + +extern void examine_super0(void *sbv); +extern void brief_examine_super0(void *sbv); +extern void detail_super0(void *sbv); +extern void brief_detail_super0(void *sbv); +extern void getinfo_super0(struct mdinfo *info, void *sbv); +extern int update_super0(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose); +extern __u64 event_super0(void *sbv); +extern void uuid_from_super0(int uuid[4], void * sbv); +extern void init_super0(void **sbv, mdu_array_info_t *info); +extern void add_to_super0(void *sbp, mdu_disk_info_t *dinfo); +extern int store_super0(int fd, mdp_super_t *super); +extern int write_init_super0(void *sbv, mdu_disk_info_t *dinfo, char *devname); +extern int load_super0(int fd, void **super, char *devname); +extern int compare_super0(void **first, void *second); diff --git a/super0.c b/super0.c new file mode 100644 index 00000000..a65d1e14 --- /dev/null +++ b/super0.c @@ -0,0 +1,539 @@ +/* + * 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" + +/* + * All handling for the 0.90.0 version superblock is in + * this file. + * This includes: + * - finding, loading, and writing the superblock. + * - initialising a new superblock + * - printing the superblock for --examine + * - printing part of the superblock for --detail + * .. other stuff + */ + + +static unsigned long calc_sb0_csum(mdp_super_t *super) +{ + unsigned long csum = super->sb_csum; + unsigned long newcsum; + super->sb_csum= 0 ; + newcsum = calc_csum(super, MD_SB_BYTES); + super->sb_csum = csum; + return newcsum; +} + +void examine_super0(void *sbv) +{ + mdp_super_t *sb = sbv; + time_t atime; + int d; + char *c; + + printf(" Magic : %08x\n", sb->md_magic); + printf(" Version : %02d.%02d.%02d\n", sb->major_version, sb->minor_version, + sb->patch_version); + if (sb->minor_version >= 90) + printf(" UUID : %08x:%08x:%08x:%08x\n", sb->set_uuid0, sb->set_uuid1, + sb->set_uuid2, sb->set_uuid3); + else + printf(" UUID : %08x\n", sb->set_uuid0); + + atime = sb->ctime; + printf(" Creation Time : %.24s\n", ctime(&atime)); + c=map_num(pers, sb->level); + printf(" Raid Level : %s\n", c?c:"-unknown-"); + if ((int)sb->level >= 0) + printf(" Device Size : %d%s\n", sb->size, human_size((long long)sb->size<<10)); + printf(" Raid Devices : %d\n", sb->raid_disks); + printf(" Total Devices : %d\n", sb->nr_disks); + printf("Preferred Minor : %d\n", sb->md_minor); + printf("\n"); + atime = sb->utime; + printf(" Update Time : %.24s\n", ctime(&atime)); + printf(" State : %s\n", + (sb->state&(1<active_disks); + printf("Working Devices : %d\n", sb->working_disks); + printf(" Failed Devices : %d\n", sb->failed_disks); + printf(" Spare Devices : %d\n", sb->spare_disks); + if (calc_sb0_csum(sb) == sb->sb_csum) + printf(" Checksum : %x - correct\n", sb->sb_csum); + else + printf(" Checksum : %x - expected %lx\n", sb->sb_csum, calc_sb0_csum(sb)); + printf(" Events : %d.%d\n", sb->events_hi, sb->events_lo); + printf("\n"); + if (sb->level == 5) { + c = map_num(r5layout, sb->layout); + printf(" Layout : %s\n", c?c:"-unknown-"); + } + switch(sb->level) { + case 0: + case 4: + case 5: + printf(" Chunk Size : %dK\n", sb->chunk_size/1024); + break; + case -1: + printf(" Rounding : %dK\n", sb->chunk_size/1024); + break; + default: break; + } + printf("\n"); + printf(" Number Major Minor RaidDevice State\n"); + for (d= -1; d<(signed int)(sb->raid_disks+sb->spare_disks); d++) { + mdp_disk_t *dp; + char *dv; + char nb[5]; + if (d>=0) dp = &sb->disks[d]; + else dp = &sb->this_disk; + sprintf(nb, "%4d", d); + printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb, + dp->number, dp->major, dp->minor, dp->raid_disk); + if (dp->state & (1<state & (1<state & (1<state & (1<state == 0) printf(" spare"); + if ((dv=map_dev(dp->major, dp->minor))) + printf(" %s", dv); + printf("\n"); + if (d == -1) printf("\n"); + } +} + +void brief_examine_super0(void *sbv) +{ + mdp_super_t *sb = sbv; + char *c=map_num(pers, sb->level); + + printf("ARRAY %s level=%s num-devices=%d UUID=", + get_md_name(sb->md_minor), + c?c:"-unknown-", sb->raid_disks); + if (sb->minor_version >= 90) + printf("%08x:%08x:%08x:%08x", sb->set_uuid0, sb->set_uuid1, + sb->set_uuid2, sb->set_uuid3); + else + printf("%08x", sb->set_uuid0); + printf("\n"); +} + +void detail_super0(void *sbv) +{ + mdp_super_t *sb = sbv; + printf(" UUID : "); + if (sb->minor_version >= 90) + printf("%08x:%08x:%08x:%08x", sb->set_uuid0, sb->set_uuid1, + sb->set_uuid2, sb->set_uuid3); + else + printf("%08x", sb->set_uuid0); + printf("\n Events : %d.%d\n\n", sb->events_hi, sb->events_lo); +} + +void brief_detail_super0(void *sbv) +{ + mdp_super_t *sb = sbv; + printf(" UUID="); + if (sb->minor_version >= 90) + printf("%08x:%08x:%08x:%08x", sb->set_uuid0, sb->set_uuid1, + sb->set_uuid2, sb->set_uuid3); + else + printf("%08x", sb->set_uuid0); +} + +void uuid_from_super0(int uuid[4], void * sbv) +{ + mdp_super_t *super = sbv; + uuid[0] = super->set_uuid0; + if (super->minor_version >= 90) { + uuid[1] = super->set_uuid1; + uuid[2] = super->set_uuid2; + uuid[3] = super->set_uuid3; + } else { + uuid[1] = 0; + uuid[2] = 0; + uuid[3] = 0; + } +} + +void getinfo_super0(struct mdinfo *info, void *sbv) +{ + mdp_super_t *sb = sbv; + int working = 0; + int i; + + info->array.major_version = sb->major_version; + info->array.minor_version = sb->minor_version; + info->array.patch_version = sb->patch_version; + info->array.raid_disks = sb->raid_disks; + info->array.level = sb->level; + info->array.md_minor = sb->md_minor; + info->array.ctime = sb->ctime; + + info->disk.state = sb->this_disk.state; + info->disk.major = sb->this_disk.major; + info->disk.minor = sb->this_disk.minor; + info->disk.raid_disk = sb->this_disk.raid_disk; + + info->events = md_event(sb); + + uuid_from_super0(info->uuid, sbv); + + /* work_disks is calculated rather than read directly */ + for (i=0; i < MD_SB_DISKS; i++) + if ((sb->disks[i].state & (1<disks[i].state & (1<disks[i].state & (1<array.working_disks = working; +} + + +int update_super0(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose) +{ + int rv = 0; + mdp_super_t *sb = sbv; + if (strcmp(update, "sparc2.2")==0 ) { + /* 2.2 sparc put the events in the wrong place + * So we copy the tail of the superblock + * up 4 bytes before continuing + */ + __u32 *sb32 = (__u32*)sb; + memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7, + sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1, + (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4); + fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n", + devname); + } + if (strcmp(update, "super-minor") ==0) { + sb->md_minor = info->array.md_minor; + if (verbose) + fprintf(stderr, Name ": updating superblock of %s with minor number %d\n", + devname, info->array.md_minor); + } + if (strcmp(update, "summaries") == 0) { + int i; + /* set nr_disks, active_disks, working_disks, + * failed_disks, spare_disks based on disks[] + * array in superblock. + * Also make sure extra slots aren't 'failed' + */ + sb->nr_disks = sb->active_disks = + sb->working_disks = sb->failed_disks = + sb->spare_disks = 0; + for (i=0; i < MD_SB_DISKS ; i++) + if (sb->disks[i].major || + sb->disks[i].minor) { + int state = sb->disks[i].state; + if (state & (1<nr_disks++; + if (state & (1<active_disks++; + if (state & (1<failed_disks++; + else + sb->working_disks++; + if (state == 0) + sb->spare_disks++; + } else if (i >= sb->raid_disks && sb->disks[i].number == 0) + sb->disks[i].state = 0; + } + if (strcmp(update, "force")==0) { + sb->events_hi = (info->events>>32) & 0xFFFFFFFF; + sb->events_lo = (info->events) & 0xFFFFFFFF; + if (sb->level == 5 || sb->level == 4 || sb->level == 6) + /* need to force clean */ + sb->state |= (1 << MD_SB_CLEAN); + } + if (strcmp(update, "assemble")==0) { + int d = info->disk.number; + if (sb->disks[d].state != info->disk.state) { + sb->disks[d].state = info->disk.state; + rv = 1; + } + } + 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]; + } + if (strcmp(update, "grow") == 0) { + sb->raid_disks = info->array.raid_disks; + sb->nr_disks = info->array.nr_disks; + sb->active_disks = info->array.active_disks; + sb->working_disks = info->array.working_disks; + memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0])); + sb->disks[info->disk.number].number = info->disk.number; + sb->disks[info->disk.number].major = info->disk.major; + sb->disks[info->disk.number].minor = info->disk.minor; + sb->disks[info->disk.number].raid_disk = info->disk.raid_disk; + sb->disks[info->disk.number].state = info->disk.state; + if (sb->this_disk.number == info->disk.number) + sb->this_disk = sb->disks[info->disk.number]; + } + if (strcmp(update, "resync") == 0) { + /* make sure resync happens */ + sb->state &= ~(1<recovery_cp = 0; + } + + sb->sb_csum = calc_sb0_csum(sb); + return rv; +} + +__u64 event_super0(void *sbv) +{ + mdp_super_t *sb = sbv; + return md_event(sb); +} + + + +void init_super0(void **sbp, mdu_array_info_t *info) +{ + mdp_super_t *sb = malloc(MD_SB_BYTES); + memset(sb, 0, MD_SB_BYTES); + + sb->md_magic = MD_SB_MAGIC; + sb->major_version = 0; + sb->minor_version = 90; + sb->patch_version = 0; + sb->gvalid_words = 0; /* ignored */ + sb->set_uuid0 = random(); + sb->ctime = time(0); + sb->level = info->level; + sb->size = info->size; + sb->nr_disks = info->nr_disks; + sb->raid_disks = info->raid_disks; + sb->md_minor = info->md_minor; + sb->not_persistent = 0; + sb->set_uuid1 = random(); + sb->set_uuid2 = random(); + sb->set_uuid3 = random(); + + sb->utime = sb->ctime; + sb->state = info->state; + sb->active_disks = info->active_disks; + sb->working_disks = info->working_disks; + sb->failed_disks = info->failed_disks; + sb->events_hi = 0; + sb->events_lo = 1; + + sb->layout = info->layout; + sb->chunk_size = info->chunk_size; + + *sbp = sb; +} + +/* Add a device to the superblock being created */ +void add_to_super0(void *sbv, mdu_disk_info_t *dinfo) +{ + mdp_super_t *sb = sbv; + mdp_disk_t *dk = &sb->disks[dinfo->number]; + + dk->number = dinfo->number; + dk->major = dinfo->major; + dk->minor = dinfo->minor; + dk->raid_disk = dinfo->raid_disk; + dk->state = dinfo->state; +} + +int store_super0(int fd, mdp_super_t *super) +{ + unsigned long size; + unsigned long long dsize; + unsigned long long offset; + +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + else + dsize = ((unsigned long long)size)<<9; + } + + if (dsize < MD_RESERVED_SECTORS*2) + return 2; + + offset = MD_NEW_SIZE_SECTORS(dsize>>9); + + offset *= 512; + + if (lseek64(fd, offset, 0)< 0LL) + return 3; + + if (write(fd, super, sizeof(*super)) != sizeof(*super)) + return 4; + + return 0; +} + +int write_init_super0(void *sbv, mdu_disk_info_t *dinfo, char *devname) +{ + mdp_super_t *sb = sbv; + int fd = open(devname, O_RDWR, O_EXCL); + int rv; + + if (fd < 0) { + fprintf(stderr, Name ": Failed to open %s to write superblock\n", devname); + return -1; + } + + sb->this_disk = sb->disks[dinfo->number]; + sb->sb_csum = calc_sb0_csum(sb); + rv = store_super0(fd, sb); + close(fd); + if (rv) + fprintf(stderr, Name ": failed to write superblock to %s\n", devname); + return rv; +} + +int compare_super0(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 + */ + mdp_super_t *first = *firstp; + mdp_super_t *second = secondv; + + int uuid1[4], uuid2[4]; + if (second->md_magic != MD_SB_MAGIC) + return 1; + if (!first) { + first = malloc(MD_SB_BYTES); + memcpy(first, second, MD_SB_BYTES); + *firstp = first; + return 0; + } + + uuid_from_super0(uuid1, first); + uuid_from_super0(uuid2, second); + if (!same_uuid(uuid1, uuid2)) + return 2; + if (first->major_version != second->major_version || + first->minor_version != second->minor_version || + first->patch_version != second->patch_version || + first->gvalid_words != second->gvalid_words || + first->ctime != second->ctime || + first->level != second->level || + first->size != second->size || + first->raid_disks != second->raid_disks ) + return 3; + + return 0; +} + + +int load_super0(int fd, void **sbp, char *devname) +{ + /* try to read in the superblock + * Return: + * 0 on success + * 1 on cannot get superblock + * 2 on superblock meaningless + */ + unsigned long size; + unsigned long long dsize; + unsigned long long offset; + mdp_super_t *super; + +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) { + if (devname) + fprintf(stderr, Name ": cannot find device size for %s: %s\n", + devname, strerror(errno)); + return 1; + } else + dsize = size << 9; + } + + if (dsize < MD_RESERVED_SECTORS*2) { + if (devname) + fprintf(stderr, Name ": %s is too small for md: size is %ld sectors.\n", + devname, size); + return 1; + } + + offset = MD_NEW_SIZE_SECTORS(dsize>>9); + + offset *= 512; + + ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ + + if (lseek64(fd, offset, 0)< 0LL) { + if (devname) + fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", + devname, strerror(errno)); + return 1; + } + + super = malloc(MD_SB_BYTES); + + if (read(fd, super, sizeof(*super)) != MD_SB_BYTES) { + if (devname) + fprintf(stderr, Name ": Cannot read superblock on %s\n", + devname); + free(super); + return 1; + } + + if (super->md_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, super->md_magic); + free(super); + return 2; + } + + if (super->major_version != 0) { + if (devname) + fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", + devname, super->major_version); + free(super); + return 2; + } + *sbp = super; + return 0; +} diff --git a/util.c b/util.c index d5e2910c..e9bce2a1 100644 --- a/util.c +++ b/util.c @@ -150,140 +150,6 @@ int same_uuid(int a[4], int b[4]) return 0; } -void uuid_from_super(int uuid[4], mdp_super_t *super) -{ - uuid[0] = super->set_uuid0; - if (super->minor_version >= 90) { - uuid[1] = super->set_uuid1; - uuid[2] = super->set_uuid2; - uuid[3] = super->set_uuid3; - } else { - uuid[1] = 0; - uuid[2] = 0; - uuid[3] = 0; - } -} - -int compare_super(mdp_super_t *first, mdp_super_t *second) -{ - /* - * return: - * 0 same, or first was empty, and second was copied - * 1 second had wrong number - * 2 wrong uuid - * 3 wrong other info - */ - int uuid1[4], uuid2[4]; - if (second->md_magic != MD_SB_MAGIC) - return 1; - if (first-> md_magic != MD_SB_MAGIC) { - memcpy(first, second, sizeof(*first)); - return 0; - } - - uuid_from_super(uuid1, first); - uuid_from_super(uuid2, second); - if (!same_uuid(uuid1, uuid2)) - return 2; - if (first->major_version != second->major_version || - first->minor_version != second->minor_version || - first->patch_version != second->patch_version || - first->gvalid_words != second->gvalid_words || - first->ctime != second->ctime || - first->level != second->level || - first->size != second->size || - first->raid_disks != second->raid_disks ) - return 3; - - return 0; -} - -int load_super(int fd, mdp_super_t *super) -{ - /* try to read in the superblock - * - * return - * 0 - success - * 1 - no block size - * 2 - too small - * 3 - no seek - * 4 - no read - * 5 - no magic - * 6 - wrong major version - */ - unsigned long size; - unsigned long long dsize; - unsigned long long offset; - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) -#endif - { - if (ioctl(fd, BLKGETSIZE, &size)) - return 1; - else - dsize = size << 9; - } - - if (dsize < MD_RESERVED_SECTORS*2) - return 2; - - offset = MD_NEW_SIZE_SECTORS(dsize>>9); - - offset *= 512; - - ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ - - if (lseek64(fd, offset, 0)< 0LL) - return 3; - - if (read(fd, super, sizeof(*super)) != sizeof(*super)) - return 4; - - if (super->md_magic != MD_SB_MAGIC) - return 5; - - if (super->major_version != 0) - return 6; - return 0; -} - -int store_super(int fd, mdp_super_t *super) -{ - unsigned long size; - unsigned long long dsize; - - long long offset; - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) -#endif - { - if (ioctl(fd, BLKGETSIZE, &size)) - return 1; - else - dsize = ((unsigned long long)size) << 9; - } - - if (dsize < MD_RESERVED_SECTORS*2) - return 2; - - offset = MD_NEW_SIZE_SECTORS(dsize>>9); - - offset *= 512; - - if (lseek64(fd, offset, 0)< 0LL) - return 3; - - if (write(fd, super, sizeof(*super)) != sizeof(*super)) - return 4; - - fsync(fd); - return 0; -} - - - int check_ext2(int fd, char *name) { /* @@ -339,18 +205,25 @@ int check_reiser(int fd, char *name) return 1; } +int load_super(int fd, void **sbp, int vers) +{ + return load_super0(fd, sbp, NULL); +} int check_raid(int fd, char *name) { - mdp_super_t super; + void *super; + struct mdinfo info; time_t crtime; - if (load_super(fd, &super)) + if (load_super(fd, &super, -1)) return 0; /* Looks like a raid array .. */ fprintf(stderr, Name ": %s appears to be part of a raid array:\n", name); - crtime = super.ctime; + getinfo_super0(&info, super); + free(super); + crtime = info.array.ctime; fprintf(stderr, " level=%d devices=%d ctime=%s", - super.level, super.raid_disks, ctime(&crtime)); + info.array.level, info.array.raid_disks, ctime(&crtime)); return 1; } @@ -506,19 +379,16 @@ char *map_dev(int major, int minor) #endif -unsigned long calc_sb_csum(mdp_super_t *super) +unsigned long calc_csum(void *super, int bytes) { - unsigned int oldcsum = super->sb_csum; unsigned long long newcsum = 0; - unsigned long csum; int i; - unsigned int *superc = (int*) super; - super->sb_csum = 0; + unsigned int csum; + unsigned int *superc = (unsigned int*) super; - for(i=0; i>32); - super->sb_csum = oldcsum; return csum; } -- 2.39.2