Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Fix raid5 creation with new code.

Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
This commit is contained in:
Neil Brown 2005-05-03 23:44:40 +00:00
parent f9ce90ba50
commit 82d9eba687
14 changed files with 910 additions and 149 deletions

View File

@ -29,7 +29,7 @@
#include "mdadm.h" #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_ident_t ident, char *conffile,
mddev_dev_t devlist, mddev_dev_t devlist,
int readonly, int runstop, int readonly, int runstop,
@ -164,7 +164,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
} }
devices = malloc(num_devs * sizeof(*devices)); devices = malloc(num_devs * sizeof(*devices));
if (!ss && ident->ss) ss = ident->ss; if (!st && ident->st) st = ident->st;
if (verbose) if (verbose)
fprintf(stderr, Name ": looking for devices for %s\n", fprintf(stderr, Name ": looking for devices for %s\n",
@ -174,7 +174,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
char *devname; char *devname;
int dfd; int dfd;
struct stat stb; struct stat stb;
struct superswitch *tss = ss; struct supertype *tst = st;
devname = devlist->devname; devname = devlist->devname;
devlist = devlist->next; 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", fprintf(stderr, Name ": %s is not a block device.\n",
devname); devname);
close(dfd); close(dfd);
} else if (!tss && (tss = guess_super(dfd, NULL)) == NULL) { } else if (!tst && (tst = guess_super(dfd)) == NULL) {
if (inargv || verbose) if (inargv || verbose)
fprintf(stderr, Name ": no recogniseable superblock\n"); 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) if (inargv || verbose)
fprintf( stderr, Name ": no RAID superblock on %s\n", fprintf( stderr, Name ": no RAID superblock on %s\n",
devname); devname);
close(dfd); close(dfd);
} else { } else {
tss->getinfo_super(&info, super); tst->ss->getinfo_super(&info, super);
close(dfd); close(dfd);
} }
@ -258,8 +258,8 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
free(first_super); free(first_super);
return 1; return 1;
} }
ss = tss; /* commit to this format, if haven't already */ st = tst; /* commit to this format, if haven't already */
if (ss->compare_super(&first_super, super)) { if (st->ss->compare_super(&first_super, super)) {
fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
devname); devname);
free(super); free(super);
@ -274,13 +274,13 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
fstat(mdfd, &stb2); fstat(mdfd, &stb2);
info.array.md_minor = minor(stb2.st_rdev); 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); dfd = open(devname, O_RDWR|O_EXCL, 0);
if (dfd < 0) if (dfd < 0)
fprintf(stderr, Name ": Cannot open %s for superblock update\n", fprintf(stderr, Name ": Cannot open %s for superblock update\n",
devname); 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", fprintf(stderr, Name ": Could not re-write superblock on %s.\n",
devname); devname);
if (dfd >= 0) if (dfd >= 0)
@ -341,7 +341,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
return 1; return 1;
} }
ss->getinfo_super(&info, first_super); st->ss->getinfo_super(&info, first_super);
/* now we have some devices that might be suitable. /* now we have some devices that might be suitable.
* I wonder how many * I wonder how many
@ -399,7 +399,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
devices[chosen_drive].events = 0; devices[chosen_drive].events = 0;
continue; continue;
} }
if (ss->load_super(fd, &super, NULL)) { if (st->ss->load_super(st,fd, &super, NULL)) {
close(fd); close(fd);
fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n",
devices[chosen_drive].devname); devices[chosen_drive].devname);
@ -407,9 +407,9 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
continue; continue;
} }
info.events = devices[most_recent].events; 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); close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n", fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname); devices[chosen_drive].devname);
@ -446,7 +446,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
devices[j].devname, strerror(errno)); devices[j].devname, strerror(errno));
return 1; return 1;
} }
if (ss->load_super(fd, &super, NULL)) { if (st->ss->load_super(st,fd, &super, NULL)) {
close(fd); close(fd);
fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
devices[j].devname); 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); fprintf(stderr, Name ": No suitable drives found for %s\n", mddev);
return 1; return 1;
} }
ss->getinfo_super(&info, super); st->ss->getinfo_super(&info, super);
for (i=0; i<bestcnt; i++) { for (i=0; i<bestcnt; i++) {
int j = best[i]; int j = best[i];
unsigned int desired_state; unsigned int desired_state;
@ -476,7 +476,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
info.disk.state = desired_state; info.disk.state = desired_state;
if (devices[j].uptodate && if (devices[j].uptodate &&
ss->update_super(&info, super, "assemble", NULL, 0)) { st->ss->update_super(&info, super, "assemble", NULL, 0)) {
if (force) { if (force) {
fprintf(stderr, Name ": " fprintf(stderr, Name ": "
"clearing FAULTY flag for device %d in %s for %s\n", "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) { if (force && okcnt == info.array.raid_disks-1) {
/* FIXME check event count */ /* FIXME check event count */
change += ss->update_super(&info, super, "force", change += st->ss->update_super(&info, super, "force",
devices[chosen_drive].devname, 0); devices[chosen_drive].devname, 0);
} }
@ -510,7 +510,7 @@ int Assemble(struct superswitch *ss, char *mddev, int mdfd,
devices[chosen_drive].devname); devices[chosen_drive].devname);
return 1; return 1;
} }
if (ss->store_super(fd, super)) { if (st->ss->store_super(fd, super)) {
close(fd); close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n", fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname); devices[chosen_drive].devname);

View File

@ -31,7 +31,7 @@
#include "md_u.h" #include "md_u.h"
#include "md_p.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 chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks,
int subdevs, mddev_dev_t devlist, int subdevs, mddev_dev_t devlist,
int runstop, int verbose, int force) int runstop, int verbose, int force)
@ -49,7 +49,7 @@ int Create(struct superswitch *ss, char *mddev, int mdfd,
* abort. * abort.
* *
* SET_ARRAY_INFO and ADD_NEW_DISK, and * 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 * RUN_ARRAY
*/ */
unsigned long long minsize=0, maxsize=0; unsigned long long minsize=0, maxsize=0;
@ -59,16 +59,18 @@ int Create(struct superswitch *ss, char *mddev, int mdfd,
mddev_dev_t dv; mddev_dev_t dv;
int fail=0, warn=0; int fail=0, warn=0;
struct stat stb; struct stat stb;
int first_missing = MD_SB_DISKS*2; int first_missing = subdevs * 2;
int missing_disks = 0; 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; void *super;
int pass; int pass;
int vers;
int rv;
mdu_array_info_t array; mdu_array_info_t array;
vers = md_get_version(mdfd);
if (md_get_version(mdfd) < 9000) { if (vers < 9000) {
fprintf(stderr, Name ": Create requires md driver version 0.90.0 or later\n"); fprintf(stderr, Name ": Create requires md driver version 0.90.0 or later\n");
return 1; 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"); Name ": at least 2 raid-devices needed for level 4 or 5\n");
return 1; 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) { if (subdevs > raiddisks+sparedisks) {
fprintf(stderr, Name ": You have listed more devices (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks); fprintf(stderr, Name ": You have listed more devices (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
return 1; return 1;
@ -211,15 +207,16 @@ int Create(struct superswitch *ss, char *mddev, int mdfd,
ldsize = dsize; ldsize = dsize;
dsize <<= 9; 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", fprintf(stderr, Name ": %s is too small: %luK\n",
dname, (unsigned long)(ldsize>>10)); dname, (unsigned long)(ldsize>>10));
fail = 1; fail = 1;
close(fd); close(fd);
continue; continue;
} }
freesize = MD_NEW_SIZE_SECTORS((ldsize>>9));
freesize /= 2; freesize /= 2; /* convert to K */
if (size && freesize < size) { if (size && freesize < size) {
fprintf(stderr, Name ": %s is smaller that given 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.nr_disks = array.working_disks + array.failed_disks;
array.layout = layout; array.layout = layout;
array.chunk_size = chunk*1024; array.chunk_size = chunk*1024;
printf("VERS = %d\n", vers);
if (ioctl(mdfd, SET_ARRAY_INFO, NULL)) { if (!st->ss->init_super(&super, &array))
return 1;
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", fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
mddev, strerror(errno)); mddev, strerror(errno));
return 1; return 1;
} }
ss->init_super(&super, &array);
for (pass=1; pass <=2 ; pass++) { 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); disk.minor = minor(stb.st_rdev);
close(fd); close(fd);
} }
if (disk.state != 1)
switch(pass){ switch(pass){
case 1: case 1:
ss->add_to_super(super, &disk); st->ss->add_to_super(super, &disk);
break; break;
case 2: 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)) { if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",

View File

@ -50,7 +50,7 @@ int Detail(char *dev, int brief, int test)
int is_26 = get_linux_version() >= 2006000; int is_26 = get_linux_version() >= 2006000;
int is_rebuilding = 0; int is_rebuilding = 0;
int failed = 0; int failed = 0;
struct superswitch *ss = NULL; struct supertype *st = NULL;
void *super = NULL; void *super = NULL;
int rv = test ? 4 : 1; int rv = test ? 4 : 1;
@ -83,7 +83,7 @@ int Detail(char *dev, int brief, int test)
close(fd); close(fd);
return rv; 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)) if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode))
stb.st_rdev = 0; stb.st_rdev = 0;
@ -106,10 +106,10 @@ int Detail(char *dev, int brief, int test)
* to get more info * to get more info
*/ */
int fd2 = open(dv, O_RDONLY); int fd2 = open(dv, O_RDONLY);
if (fd2 >=0 && ss && if (fd2 >=0 && st &&
ss->load_super(fd2, &super, NULL) == 0) { st->ss->load_super(st, fd2, &super, NULL) == 0) {
struct mdinfo info; struct mdinfo info;
ss->getinfo_super(&info, super); st->ss->getinfo_super(&info, super);
if (info.array.ctime != array.ctime || if (info.array.ctime != array.ctime ||
info.array.level != array.level) { info.array.level != array.level) {
free(super); free(super);
@ -205,8 +205,8 @@ int Detail(char *dev, int brief, int test)
} }
free_mdstat(ms); free_mdstat(ms);
if (super && ss) if (super && st)
ss->detail_super(super); st->ss->detail_super(super);
printf(" Number Major Minor RaidDevice State\n"); printf(" Number Major Minor RaidDevice State\n");
} }
@ -278,8 +278,8 @@ int Detail(char *dev, int brief, int test)
if (!brief) printf("\n"); if (!brief) printf("\n");
} }
if (spares && brief) printf(" spares=%d", spares); if (spares && brief) printf(" spares=%d", spares);
if (super && brief && ss) if (super && brief && st)
ss->brief_detail_super(super); st->ss->brief_detail_super(super);
if (brief && devices) printf("\n devices=%s", devices); if (brief && devices) printf("\n devices=%s", devices);
if (brief) printf("\n"); if (brief) printf("\n");

View File

@ -35,7 +35,7 @@
#endif #endif
#include "md_u.h" #include "md_u.h"
#include "md_p.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 /* 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 { struct array {
void *super; void *super;
struct superswitch *ss; struct supertype *st;
struct mdinfo info; struct mdinfo info;
void *devs; void *devs;
struct array *next; struct array *next;
@ -68,7 +68,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
} *arrays = NULL; } *arrays = NULL;
for (; devlist ; devlist=devlist->next) { for (; devlist ; devlist=devlist->next) {
struct superswitch *ss; struct supertype *st = forcest;
fd = open(devlist->devname, O_RDONLY); fd = open(devlist->devname, O_RDONLY);
if (fd < 0) { if (fd < 0) {
@ -78,9 +78,10 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
err = 1; err = 1;
} }
else { else {
ss = guess_super(fd, devlist->devname); if (!st)
if (ss) st = guess_super(fd);
err = ss->load_super(fd, &super, (brief||scan)?NULL:devlist->devname); if (st)
err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname);
else else
err = 1; err = 1;
close(fd); close(fd);
@ -90,13 +91,13 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
if (err) rv =1; if (err) rv =1;
if (SparcAdjust) 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 */ /* Ok, its good enough to try, though the checksum could be wrong */
if (brief) { if (brief) {
struct array *ap; struct array *ap;
char *d; char *d;
for (ap=arrays; ap; ap=ap->next) { 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; break;
} }
if (!ap) { if (!ap) {
@ -105,11 +106,11 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
ap->devs = dl_head(); ap->devs = dl_head();
ap->next = arrays; ap->next = arrays;
ap->spares = 0; ap->spares = 0;
ap->ss = ss; ap->st = st;
arrays = ap; arrays = ap;
ss->getinfo_super(&ap->info, super); st->ss->getinfo_super(&ap->info, super);
} else { } else {
ss->getinfo_super(&ap->info, super); st->ss->getinfo_super(&ap->info, super);
free(super); free(super);
} }
if (!(ap->info.disk.state & MD_DISK_SYNC)) 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); dl_add(ap->devs, d);
} else { } else {
printf("%s:\n",devlist->devname); printf("%s:\n",devlist->devname);
ss->examine_super(super); st->ss->examine_super(super);
free(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) { for (ap=arrays; ap; ap=ap->next) {
char sep='='; char sep='=';
char *d; 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); if (ap->spares) printf(" spares=%d", ap->spares);
printf(" devices"); printf(" devices");
for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) {

18
Grow.c
View File

@ -51,7 +51,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
struct stat stb; struct stat stb;
int nfd, fd2; int nfd, fd2;
int d, nd; int d, nd;
struct superswitch *ss = NULL; struct supertype *st = NULL;
if (ioctl(fd, GET_ARRAY_INFO, &info.array) < 0) { 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; return 1;
} }
ss = super_by_version(info.array.major_version); st = super_by_version(info.array.major_version, info.array.minor_version);
if (!ss) { if (!st) {
fprintf(stderr, Name ": cannot handle arrays with superblock version %d\n", info.array.major_version); fprintf(stderr, Name ": cannot handle arrays with superblock version %d\n", info.array.major_version);
return 1; return 1;
} }
@ -105,7 +105,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
} }
if (super) free(super); if (super) free(super);
super= NULL; 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); fprintf(stderr, Name ": cannot find super block on %s\n", dv);
close(fd2); close(fd2);
return 1; 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.minor = minor(stb.st_rdev);
info.disk.raid_disk = d; info.disk.raid_disk = d;
info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); 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); fprintf(stderr, Name ": Cannot store new superblock on %s\n", newdev);
close(nfd); close(nfd);
return 1; 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); fprintf(stderr, Name ": cannot open device file %s\n", dv);
return 1; 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); fprintf(stderr, Name ": cannot find super block on %s\n", dv);
close(fd); close(fd);
return 1; 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.minor = minor(stb.st_rdev);
info.disk.raid_disk = nd; info.disk.raid_disk = nd;
info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); 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); fprintf(stderr, Name ": Cannot store new superblock on %s\n", dv);
close(fd2); close(fd2);
return 1; return 1;

12
Kill.c
View File

@ -43,7 +43,7 @@ int Kill(char *dev, int force)
void *super; void *super;
int fd, rv = 0; int fd, rv = 0;
struct superswitch *ss; struct supertype *st;
fd = open(dev, O_RDWR|O_EXCL); fd = open(dev, O_RDWR|O_EXCL);
if (fd < 0) { if (fd < 0) {
@ -51,20 +51,20 @@ int Kill(char *dev, int force)
dev); dev);
return 1; return 1;
} }
ss = guess_super(fd, dev); st = guess_super(fd);
if (ss == NULL) { if (st == NULL) {
fprintf(stderr, Name ": Unrecognised md component device - %s\n", dev); fprintf(stderr, Name ": Unrecognised md component device - %s\n", dev);
return 1; return 1;
} }
rv = ss->load_super(fd, &super, dev); rv = st->ss->load_super(st, fd, &super, dev);
if (force && rv >= 2) if (force && rv >= 2)
rv = 0; /* ignore bad data in superblock */ rv = 0; /* ignore bad data in superblock */
if (rv== 0 || (force && rv >= 2)) { if (rv== 0 || (force && rv >= 2)) {
mdu_array_info_t info; mdu_array_info_t info;
info.major_version = -1; /* zero superblock */ info.major_version = -1; /* zero superblock */
free(super); free(super);
ss->init_super(&super, &info); st->ss->init_super(&super, &info);
if (ss->store_super(fd, super)) { if (st->ss->store_super(fd, super)) {
fprintf(stderr, Name ": Could not zero superblock on %s\n", fprintf(stderr, Name ": Could not zero superblock on %s\n",
dev); dev);
rv = 1; rv = 1;

View File

@ -58,9 +58,9 @@ MAN5DIR = $(MANDIR)/man5
MAN8DIR = $(MANDIR)/man8 MAN8DIR = $(MANDIR)/man8
OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o \ 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 \ 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 ASSEMBLE_SRCS := mdassemble.c Assemble.c config.c dlink.c util.c
ifdef MDASSEMBLE_AUTO ifdef MDASSEMBLE_AUTO

10
Query.c
View File

@ -44,7 +44,7 @@ int Query(char *dev)
struct mdinfo info; struct mdinfo info;
mdu_array_info_t array; mdu_array_info_t array;
void *super; void *super;
struct superswitch *ss = NULL; struct supertype *st = NULL;
unsigned long long larray_size; unsigned long long larray_size;
unsigned long array_size; unsigned long array_size;
@ -95,16 +95,16 @@ int Query(char *dev)
array.raid_disks, array.raid_disks,
array.spare_disks, array.spare_disks==1?"":"s"); array.spare_disks, array.spare_disks==1?"":"s");
} }
ss = guess_super(fd, dev); st = guess_super(fd);
if (ss) { if (st) {
superror = ss->load_super(fd, &super, dev); superror = st->ss->load_super(st, fd, &super, dev);
superrno = errno; superrno = errno;
} else } else
superror = -1; superror = -1;
close(fd); close(fd);
if (superror == 0) { if (superror == 0) {
/* array might be active... */ /* array might be active... */
ss->getinfo_super(&info, super); st->ss->getinfo_super(&info, super);
mddev = get_md_name(info.array.md_minor); mddev = get_md_name(info.array.md_minor);
disc.number = info.disk.number; disc.number = info.disk.number;
activity = "undetected"; activity = "undetected";

View File

@ -332,12 +332,10 @@ void arrayline(char *line)
/* style of metadata on the devices. */ /* style of metadata on the devices. */
int i; int i;
for(i=0; superlist[i]; i++) for(i=0; superlist[i] && !mis.st; i++)
if (superlist[i]->match_metadata_desc(w+9)) { mis.st = superlist[i]->match_metadata_desc(w+9);
mis.ss = superlist[i];
break; if (!mis.st)
}
if (!mis.ss)
fprintf(stderr, Name ": metadata format %s unknown, ignored.\n", w+9); fprintf(stderr, Name ": metadata format %s unknown, ignored.\n", w+9);
} else if (strncasecmp(w, "auto=", 5) == 0 ) { } else if (strncasecmp(w, "auto=", 5) == 0 ) {
/* whether to create device special files as needed */ /* whether to create device special files as needed */

19
mdadm.c
View File

@ -81,7 +81,7 @@ int main(int argc, char *argv[])
int daemonise = 0; int daemonise = 0;
char *pidfile = NULL; char *pidfile = NULL;
int oneshot = 0; int oneshot = 0;
struct superswitch *ss = NULL; struct supertype *ss = NULL;
int copies; int copies;
@ -281,11 +281,9 @@ int main(int argc, char *argv[])
fprintf(stderr, Name ": metadata information already given\n"); fprintf(stderr, Name ": metadata information already given\n");
exit(2); exit(2);
} }
for(i=0; superlist[i]; i++) for(i=0; !ss && superlist[i]; i++)
if (superlist[i]->match_metadata_desc(optarg)) { ss = superlist[i]->match_metadata_desc(optarg);
ss = superlist[i];
break;
}
if (!ss) { if (!ss) {
fprintf(stderr, Name ": unrecognised metadata identifier: %s\n", optarg); fprintf(stderr, Name ": unrecognised metadata identifier: %s\n", optarg);
exit(2); exit(2);
@ -818,11 +816,8 @@ int main(int argc, char *argv[])
break; break;
case CREATE: case CREATE:
if (ss == NULL) { if (ss == NULL) {
for(i=0; superlist[i]; i++) for(i=0; !ss && superlist[i]; i++)
if (superlist[i]->match_metadata_desc("default")) { ss = superlist[i]->match_metadata_desc("default");
ss = superlist[i];
break;
}
} }
if (!ss) { if (!ss) {
fprintf(stderr, Name ": internal error - no default metadata style\n"); 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); fprintf(stderr, Name ": No devices listed in %s\n", configfile?configfile:DefaultConfFile);
exit(1); exit(1);
} }
rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust); rv = Examine(devlist, scan?!verbose:brief, scan, SparcAdjust, ss);
} else { } else {
if (devlist == NULL) { if (devlist == NULL) {
if ((devmode == 'S' ||devmode=='D') && scan) { if ((devmode == 'S' ||devmode=='D') && scan) {

30
mdadm.h
View File

@ -116,7 +116,7 @@ typedef struct mddev_ident_s {
int level; int level;
unsigned int raid_disks; unsigned int raid_disks;
unsigned int spare_disks; unsigned int spare_disks;
struct superswitch *ss; struct supertype *st;
int autof; /* 1 for normal, 2 for partitioned */ int autof; /* 1 for normal, 2 for partitioned */
char *spare_group; char *spare_group;
@ -173,17 +173,24 @@ extern struct superswitch {
void (*getinfo_super)(struct mdinfo *info, void *sbv); void (*getinfo_super)(struct mdinfo *info, void *sbv);
int (*update_super)(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose); int (*update_super)(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose);
__u64 (*event_super)(void *sbv); __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); void (*add_to_super)(void *sbv, mdu_disk_info_t *dinfo);
int (*store_super)(int fd, void *sbv); 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 (*compare_super)(void **firstp, void *secondv);
int (*load_super)(int fd, void **sbp, char *devname); int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname);
int (*match_metadata_desc)(char *arg); struct supertype * (*match_metadata_desc)(char *arg);
} super0, *superlist[]; __u64 (*avail_size)(__u64 size);
int major;
} super0, super1, *superlist[];
extern struct superswitch *super_by_version(int vers); struct supertype {
extern struct superswitch *guess_super(int fd, char *dev); struct superswitch *ss;
int minor_version;
};
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); 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 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, mddev_ident_t ident,
char *conffile, char *conffile,
mddev_dev_t devlist, 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); 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 chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks,
int subdevs, mddev_dev_t devlist, int subdevs, mddev_dev_t devlist,
int runstop, int verbose, int force); int runstop, int verbose, int force);
extern int Detail(char *dev, int brief, int test); extern int Detail(char *dev, int brief, int test);
extern int Query(char *dev); 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, extern int Monitor(mddev_dev_t devlist,
char *mailaddr, char *alert_cmd, char *mailaddr, char *alert_cmd,
int period, int daemonise, int scan, int oneshot, int period, int daemonise, int scan, int oneshot,

View File

@ -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); mdp_super_t *sb = malloc(MD_SB_BYTES);
int spares;
memset(sb, 0, MD_SB_BYTES); memset(sb, 0, MD_SB_BYTES);
if (info->major_version == -1) { if (info->major_version == -1) {
/* zeroing the superblock */ /* 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; 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; sb->chunk_size = info->chunk_size;
*sbp = sb; *sbp = sb;
return 1;
} }
/* Add a device to the superblock being created */ /* Add a device to the superblock being created */
@ -409,7 +418,7 @@ static int store_super0(int fd, void *sbv)
return 0; 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; mdp_super_t *sb = sbv;
int fd = open(devname, O_RDWR, O_EXCL); 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 /* try to read in the superblock
* Return: * Return:
@ -541,17 +550,36 @@ static int load_super0(int fd, void **sbp, char *devname)
return 2; return 2;
} }
*sbp = super; *sbp = super;
if (st->ss == NULL) {
st->ss = &super0;
st->minor_version = 90;
}
return 0; 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 || if (strcmp(arg, "0") == 0 ||
strcmp(arg, "0.90") == 0 || strcmp(arg, "0.90") == 0 ||
strcmp(arg, "default") == 0 strcmp(arg, "default") == 0
) )
return 1; return st;
return 0;
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 = { struct superswitch super0 = {
@ -570,4 +598,6 @@ struct superswitch super0 = {
.compare_super = compare_super0, .compare_super = compare_super0,
.load_super = load_super0, .load_super = load_super0,
.match_metadata_desc = match_metadata_desc0, .match_metadata_desc = match_metadata_desc0,
.avail_size = avail_size0,
.major = 0,
}; };

720
super1.c Normal file
View File

@ -0,0 +1,720 @@
/*
* mdadm - manage Linux "md" devices aka RAID arrays.
*
* Copyright (C) 2001-2004 Neil Brown <neilb@cse.unsw.edu.au>
*
*
* 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: <neilb@cse.unsw.edu.au>
* 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,
};

62
util.c
View File

@ -210,25 +210,21 @@ int check_raid(int fd, char *name)
void *super; void *super;
struct mdinfo info; struct mdinfo info;
time_t crtime; time_t crtime;
struct supertype *st = guess_super(fd);
int i; if (!st) return 0;
for (i=0; superlist[i]; i++) { st->ss->load_super(st, fd, &super, name);
if (superlist[i]->load_super(fd, &super, name)) /* Looks like a raid array .. */
continue; fprintf(stderr, Name ": %s appears to be part of a raid array:\n",
/* Looks like a raid array .. */ name);
fprintf(stderr, Name ": %s appears to be part of a raid array:\n", st->ss->getinfo_super(&info, super);
name); free(super);
superlist[i]->getinfo_super(&info, super); crtime = info.array.ctime;
free(super); fprintf(stderr, " level=%d devices=%d ctime=%s",
crtime = info.array.ctime; info.array.level, info.array.raid_disks, ctime(&crtime));
fprintf(stderr, " level=%d devices=%d ctime=%s", return 1;
info.array.level, info.array.raid_disks, ctime(&crtime));
return 1;
}
return 0;
} }
int ask(char *mesg) int ask(char *mesg)
{ {
char *add = ""; 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; struct supertype *st = malloc(sizeof(*st));
return NULL; 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, /* try each load_super to find the best match,
* and return the best superswitch * and return the best superswitch
*/ */
struct superswitch *best = NULL, *ss; struct superswitch *ss;
int bestrv = 0; struct supertype *st;
void *sbp = NULL; void *sbp = NULL;
int i; int i;
st = malloc(sizeof(*st));
memset(st, 0, sizeof(*st));
for (i=0 ; superlist[i]; i++) { for (i=0 ; superlist[i]; i++) {
int rv; int rv;
ss = superlist[i]; ss = superlist[i];
rv = ss->load_super(fd, &sbp, NULL); rv = ss->load_super(st, fd, &sbp, NULL);
if (rv == 0) { if (rv == 0) {
free(sbp); free(sbp);
return ss; return st;
}
if (rv > bestrv) {
bestrv = rv;
best = ss;
} }
} }
if (bestrv > 2) /* FIXME */
return best;
return NULL; return NULL;
} }