Separate sueprblock handling into separate file

Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
This commit is contained in:
Neil Brown 2005-05-03 23:44:18 +00:00
parent e5811618d1
commit 4b1ac34b51
12 changed files with 823 additions and 617 deletions

View File

@ -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; i<num_devs; i++)
best[i] = -1;
if (verbose)
fprintf(stderr, Name ": looking for devices for %s\n",
@ -178,10 +171,8 @@ int Assemble(char *mddev, int mdfd,
while ( devlist) {
char *devname;
int this_uuid[4];
int dfd;
struct stat stb;
int havesuper=0;
devname = devlist->devname;
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<<MD_DISK_REMOVED))
continue;
super.nr_disks++;
if (state & (1<<MD_DISK_ACTIVE))
super.active_disks++;
if (state & (1<<MD_DISK_FAULTY))
super.failed_disks++;
else
super.working_disks++;
if (state == 0)
super.spare_disks++;
} else if (i >= super.raid_disks && super.disks[i].number == 0)
super.disks[i].state = 0;
}
if (strcmp(update, "resync") == 0) {
/* make sure resync happens */
super.state &= ~(1<<MD_SB_CLEAN);
super.recovery_cp = 0;
}
super.sb_csum = calc_sb_csum(&super);
/* prepare useful information in info structures */
struct stat stb2;
fstat(mdfd, &stb2);
info.array.md_minor = minor(stb2.st_rdev);
update_super0(&info, super, update, devname, verbose);
dfd = open(devname, O_RDWR|O_EXCL, 0);
if (dfd < 0)
fprintf(stderr, Name ": Cannot open %s for superblock update\n",
devname);
else if (store_super(dfd, &super))
else if (store_super0(dfd, super))
fprintf(stderr, Name ": Could not re-write superblock on %s.\n",
devname);
if (dfd >= 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<<MD_DISK_SYNC))) {
if (!(devices[j].state & (1<<MD_DISK_FAULTY)))
sparecnt++;
@ -407,20 +358,20 @@ int Assemble(char *mddev, int mdfd,
if (devices[j].events+event_margin >=
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<first_super.raid_disks && i < bestcnt; i++) {
for (i=0; i<info.array.raid_disks && i < bestcnt; i++) {
int j = best[i];
if (j>=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<<MD_SB_CLEAN);
}
super.sb_csum = calc_sb_csum(&super);
/*DRYRUN*/ if (store_super(fd, &super)) {
info.events = devices[most_recent].events;
update_super0(&info, super, "force", devices[chosen_drive].devname, verbose);
if (store_super0(fd, super)) {
close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname);
devices[chosen_drive].events = 0;
free(super);
continue;
}
close(fd);
devices[chosen_drive].events = devices[most_recent].events;
devices[chosen_drive].uptodate = 1;
okcnt++;
free(super);
}
/* Now we want to look at the superblock which the kernel will base things on
@ -476,9 +425,11 @@ int Assemble(char *mddev, int mdfd,
* superblock.
*/
chosen_drive = -1;
super = NULL;
for (i=0; chosen_drive < 0 && i<bestcnt; i++) {
int j = best[i];
int fd;
if (j<0)
continue;
if (!devices[j].uptodate)
@ -489,7 +440,7 @@ int Assemble(char *mddev, int mdfd,
devices[j].devname, strerror(errno));
return 1;
}
if (load_super(fd, &super)) {
if (load_super0(fd, &super, NULL)) {
close(fd);
fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
devices[j].devname);
@ -497,12 +448,16 @@ int Assemble(char *mddev, int mdfd,
}
close(fd);
}
if (super == NULL) {
fprintf(stderr, Name ": No suitable drives found for %s\n", mddev);
return 1;
}
getinfo_super0(&info, super);
for (i=0; i<bestcnt; i++) {
int j = best[i];
unsigned int desired_state;
if (i < super.raid_disks)
if (i < info.array.raid_disks)
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
else
desired_state = 0;
@ -511,77 +466,57 @@ int Assemble(char *mddev, int mdfd,
continue;
if (!devices[j].uptodate)
continue;
#if 0
This doesnt work yet
if (devices[j].major != super.disks[i].major ||
devices[j].minor != super.disks[i].minor) {
change |= 1;
super.disks[i].major = devices[j].major;
super.disks[i].minor = devices[j].minor;
}
#endif
if (devices[j].oldmajor != super.disks[i].major ||
devices[j].oldminor != super.disks[i].minor) {
change |= 2;
super.disks[i].major = devices[j].oldmajor;
super.disks[i].minor = devices[j].oldminor;
}
info.disk.number = i;
info.disk.state = desired_state;
if (devices[j].uptodate &&
(super.disks[i].state != desired_state)) {
update_super0(&info, super, "assemble", NULL, 0)) {
if (force) {
fprintf(stderr, Name ": "
"clearing FAULTY flag for device %d in %s for %s\n",
j, mddev, devices[j].devname);
super.disks[i].state = desired_state;
change |= 2;
change = 1;
} else {
fprintf(stderr, Name ": "
"device %d in %s has wrong state in superblock, but %s seems ok\n",
i, mddev, devices[j].devname);
}
}
#if 0
if (!devices[j].uptodate &&
!(super.disks[i].state & (1 << MD_DISK_FAULTY))) {
fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n",
i, mddev);
}
#endif
}
if (force && (super.level == 4 || super.level == 5) &&
okcnt == super.raid_disks-1) {
super.state = (1<< MD_SB_CLEAN);
change |= 2;
if (force && okcnt == info.array.raid_disks-1) {
/* FIXME check event count */
change += update_super0(&info, super, "force",
devices[chosen_drive].devname, 0);
}
if ((force && (change & 2))
|| (old_linux && (change & 1))) {
if (change) {
int fd;
super.sb_csum = calc_sb_csum(&super);
fd = open(devices[chosen_drive].devname, O_RDWR|O_EXCL);
if (fd < 0) {
fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n",
devices[chosen_drive].devname);
return 1;
}
if (store_super(fd, &super)) {
if (store_super0(fd, super)) {
close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname);
return 1;
}
close(fd);
change = 0;
}
/* count number of in-sync devices according to the superblock.
* We must have this number to start the array without -s or -R
*/
req_cnt = 0;
for (i=0; i<MD_SB_DISKS; i++)
if ((first_super.disks[i].state & (1<<MD_DISK_SYNC)) &&
(first_super.disks[i].state & (1<<MD_DISK_ACTIVE)) &&
!(first_super.disks[i].state & (1<<MD_DISK_FAULTY)))
req_cnt ++;
req_cnt = info.array.working_disks;
/* Almost ready to actually *do* something */
if (!old_linux) {
@ -610,28 +545,28 @@ This doesnt work yet
devices[j].devname,
mddev,
strerror(errno));
if (i < first_super.raid_disks || i == bestcnt)
if (i < info.array.raid_disks || i == bestcnt)
okcnt--;
else
sparecnt--;
} else if (verbose)
fprintf(stderr, Name ": added %s to %s as %d\n",
devices[j].devname, mddev, devices[j].raid_disk);
} else if (verbose && i < first_super.raid_disks)
} else if (verbose && i < info.array.raid_disks)
fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
i, mddev);
}
if (runstop == 1 ||
(runstop == 0 &&
( enough(first_super.level, first_super.raid_disks, okcnt) &&
( enough(info.array.level, info.array.raid_disks, okcnt) &&
(okcnt >= 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;

View File

@ -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);
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 (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
dv->devname, strerror(errno));
return 1;
}
if (dv == moved_disk && dnum != insert_point) break;
}
free(super);
/* param is not actually used */
if (runstop == 1 || subdevs >= raiddisks) {

View File

@ -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<<MD_DISK_ACTIVE))) {
if (!super && (disk.state & (1<<MD_DISK_ACTIVE))) {
/* try to read the superblock from this device
* to get more info
*/
int fd2 = open(dv, O_RDONLY);
if (fd2 >=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;

180
Examine.c
View File

@ -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<<MD_SB_CLEAN))?"clean":"active");
printf(" Active Devices : %d\n", super.active_disks);
printf("Working Devices : %d\n", super.working_disks);
printf(" Failed Devices : %d\n", super.failed_disks);
printf(" Spare Devices : %d\n", super.spare_disks);
if (calc_sb_csum(&super) == super.sb_csum)
printf(" Checksum : %x - correct\n", super.sb_csum);
else
printf(" Checksum : %x - expected %lx\n", super.sb_csum, calc_sb_csum(&super));
if (SparcAdjust) {
/* 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);
printf (" --- adjusting superblock for 2.2/sparc compatability ---\n");
}
printf(" Events : %d.%d\n", super.events_hi, super.events_lo);
if (super.events_hi == super.cp_events_hi &&
super.events_lo == super.cp_events_lo &&
super.recovery_cp > 0 &&
(super.state & (1<<MD_SB_CLEAN)) == 0 )
printf("Sync checkpoint : %d KB (%d%%)\n", super.recovery_cp/2, super.recovery_cp/(super.size/100*2));
printf("\n");
if (super.level == 5) {
c = map_num(r5layout, super.layout);
printf(" Layout : %s\n", c?c:"-unknown-");
}
if (super.level == 10)
printf(" Layout : near=%d, far=%d\n",
super.layout&255, (super.layout>>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<<MD_DISK_FAULTY)) printf(" faulty");
if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
if (dp->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");
}
}

72
Grow.c
View File

@ -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;

30
Kill.c
View File

@ -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);

View File

@ -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

49
Query.c
View File

@ -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;
}

View File

@ -30,6 +30,7 @@
#include "mdadm.h"
char Version[] = Name " - v1.11.0 - 11 April 2005\n";
/*
* File: ReadMe.c
*

28
mdadm.h
View File

@ -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);

539
super0.c Normal file
View File

@ -0,0 +1,539 @@
/*
* 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"
/*
* 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<<MD_SB_CLEAN))?"clean":"active");
printf(" Active Devices : %d\n", sb->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<<MD_DISK_FAULTY)) printf(" faulty");
if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
if (dp->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<<MD_DISK_SYNC)) &&
(sb->disks[i].state & (1<<MD_DISK_ACTIVE)) &&
!(sb->disks[i].state & (1<<MD_DISK_FAULTY)))
working ++;
info->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<<MD_DISK_REMOVED))
continue;
sb->nr_disks++;
if (state & (1<<MD_DISK_ACTIVE))
sb->active_disks++;
if (state & (1<<MD_DISK_FAULTY))
sb->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<<MD_SB_CLEAN);
sb->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;
}

160
util.c
View File

@ -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<MD_SB_BYTES/4; i++)
for(i=0; i<bytes/4; i++)
newcsum+= superc[i];
csum = (newcsum& 0xffffffff) + (newcsum>>32);
super->sb_csum = oldcsum;
return csum;
}