mdctl-0.5

This commit is contained in:
Neil Brown 2001-08-23 02:33:20 +00:00
parent 0db17fcbde
commit 5282684628
20 changed files with 1957 additions and 916 deletions

View File

@ -28,18 +28,20 @@
*/
#include "mdctl.h"
#include "md_p.h"
#include "md_u.h"
#include "md_p.h"
int Assemble(char *mddev, int mdfd,
int uuid[4], int uuidset,
char *conffile, int scan,
mddev_ident_t ident, char *conffile,
int subdevs, char **subdev,
int readonly, int runstop,
int verbose, int force)
{
/*
* The task of Assemble is to submit a
* The task of Assemble is to find a collection of
* devices that should (according to their superblocks)
* form an array, and to give this collection to the MD driver.
* In Linux-2.4 and later, this involves submitting a
* SET_ARRAY_INFO ioctl with no arg - to prepare
* the array - and then submit a number of
* ADD_NEW_DISK ioctls to add disks into
@ -100,52 +102,15 @@ int Assemble(char *mddev, int mdfd,
long long events;
time_t utime;
int uptodate;
int raid_disk;
} devices[MD_SB_DISKS];
int best[MD_SB_DISKS]; /* indexed by raid_disk */
int devcnt = 0, okcnt;
int devcnt = 0, okcnt, sparecnt;
int i;
int most_recent = 0;
int chosen_drive = -1;
int change = 0;
if (!mddev && !scan) {
fputs(Name ": internal error - Assemble called with no device or --scan\n", stderr);
return 1;
}
if (!mddev) {
mddev_uuid_t device_list;
int found = 0;
device_list = conf_get_uuids(conffile);
if (!device_list) {
fprintf(stderr, Name ": No devices found in config file\n");
return 1;
}
for (; device_list; device_list=device_list->next) {
if (!uuidset || same_uuid(device_list->uuid,uuid)) {
mdfd = open(device_list->devname, O_RDONLY, 0);
if (mdfd < 0) {
fprintf(stderr,
Name ": error opening %s: %s\n",
device_list->devname,
strerror(errno));
continue;
}
if (Assemble(device_list->devname, mdfd,
device_list->uuid, 1,
conffile, 1,
subdevs, subdev,
readonly, runstop, verbose, force)==0)
found++;
close(mdfd);
}
}
if (found)
return 0;
fprintf(stderr,Name ": Did not successfully Assemble any devices\n");
return 1;
}
/*
* Ok, we have an mddev, check it out
*/
vers = md_get_version(mdfd);
if (vers <= 0) {
fprintf(stderr, Name ": %s appears not to be an md device.\n");
@ -153,7 +118,7 @@ int Assemble(char *mddev, int mdfd,
}
if (vers < 9000) {
fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n"
" Upgrade your kernel or try --Build\n");
" Upgrade your kernel or try --build\n");
return 1;
}
if (get_linux_version() < 2004000)
@ -167,40 +132,24 @@ int Assemble(char *mddev, int mdfd,
ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */
/*
* We have a valid mddev, check out uuid
* If any subdevs are listed, then any that don't
* match ident are discarded. Remainder must all match and
* become the array.
* If no subdevs, then we scan all devices in the config file, but
* there must be something in the identity
*/
if (!uuidset && scan) {
/* device must be listed with uuid in conf file */
mddev_uuid_t device_list;
device_list = conf_get_uuids(conffile);
while (device_list &&
strcmp(device_list->devname, mddev) != 0)
device_list = device_list->next;
if (!device_list) {
fprintf(stderr, Name ": --scan set and no uuid found for %s in config file.\n",
mddev);
return 1;
}
/* the uuid is safe until next call to conf_get_uuids */
uuid = device_list->uuid;
uuidset = 1;
}
/* Now to start looking at devices.
* If no devices were given, but a uuid is available and
* --scan was set, then we should scan all devices listed in the
* config file
*
*/
if (subdevs==0 && scan && uuidset)
devlist = conf_get_devs(conffile);
if (subdevs == 0 && devlist == NULL) {
fprintf(stderr, Name ": no devices given for %s\n", mddev);
if (subdevs == 0 &&
ident->uuid_set == 0 &&
ident->super_minor < 0 &&
ident->devices == NULL) {
fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n",
mddev);
return 1;
}
/* now for each device */
if (subdevs==0)
devlist = conf_get_devs(conffile);
first_super.md_magic = 0;
for (i=0; i<MD_SB_DISKS; i++)
best[i] = -1;
@ -215,6 +164,8 @@ int Assemble(char *mddev, int mdfd,
int dfd;
struct stat stb;
int inargv;
int havesuper=0;
if (subdevs) {
devname = *subdev++;
subdevs--;
@ -225,61 +176,69 @@ int Assemble(char *mddev, int mdfd,
inargv=0;
}
if (ident->devices &&
!match_oneof(ident->devices, devname))
continue;
dfd = open(devname, O_RDONLY, 0);
if (dfd < 0) {
if (inargv || verbose)
fprintf(stderr, Name ": cannot open device %s: %s\n",
devname, strerror(errno));
continue;
}
if (fstat(dfd, &stb)< 0) {
/* Impossible! */
fprintf(stderr, Name ": fstat failed for %s: %s\n",
devname, strerror(errno));
close(dfd);
continue;
}
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
fprintf(stderr, Name ": %d is not a block device.\n",
devname);
close(dfd);
continue;
}
if (load_super(dfd, &super)) {
} else if (fstat(dfd, &stb)< 0) {
/* Impossible! */
fprintf(stderr, Name ": fstat failed for %s: %s\n",
devname, strerror(errno));
close(dfd);
} if ((stb.st_mode & S_IFMT) != S_IFBLK) {
fprintf(stderr, Name ": %d is not a block device.\n",
devname);
close(dfd);
} if (load_super(dfd, &super)) {
if (inargv || verbose)
fprintf( stderr, Name ": no RAID superblock on %s\n",
devname);
close(dfd);
continue;
} else {
havesuper =1;
uuid_from_super(this_uuid, &super);
close(dfd);
}
close(dfd);
uuid_from_super(this_uuid, &super);
if (uuidset && !same_uuid(this_uuid, uuid)) {
if (inargv || verbose)
fprintf(stderr, Name ": %s has wrong uuid.\n",
devname);
continue;
}
if (compare_super(&first_super, &super)) {
if (ident->uuid_set &&
(!havesuper || same_uuid(this_uuid, ident->uuid)==0)) {
if (inargv || verbose)
fprintf(stderr, Name ": superblock on %s doesn't match\n",
fprintf(stderr, Name ": %s has wrong uuid.\n",
devname);
continue;
}
if (uuidset) {
uuid_from_super(this_uuid, &first_super);
if (!same_uuid(this_uuid, uuid)) {
if (inargv || verbose)
fprintf(stderr, Name ": %s has wrong uuid.\n",
devname);
continue;
}
} else {
uuid_from_super(uuid, &first_super);
uuidset = 1;
if (ident->super_minor >= 0 &&
(!havesuper || ident->super_minor != super.md_minor)) {
if (inargv || verbose)
fprintf(stderr, Name ": %s has wrong super-minor.\n",
devname);
continue;
}
/* If we are this far, then we are commited to this device.
* If the super_block doesn't exist, or doesn't match others,
* then we cannot continue
*/
if (verbose)
fprintf(stderr, Name ": %s is identified as a member of %s.\n",
devname, mddev);
if (!havesuper) {
fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
devname);
return 1;
}
if (compare_super(&first_super, &super)) {
fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
devname);
return 1;
}
/* Ok, this one is at least worth considering */
if (devcnt >= MD_SB_DISKS) {
fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n",
devname);
@ -290,17 +249,19 @@ int Assemble(char *mddev, int mdfd,
devices[devcnt].minor = MINOR(stb.st_rdev);
devices[devcnt].events = md_event(&super);
devices[devcnt].utime = super.utime;
devices[devcnt].raid_disk = super.this_disk.raid_disk;
devices[devcnt].uptodate = 0;
if (most_recent < devcnt) {
if (devices[devcnt].events
> devices[most_recent].events)
most_recent = devcnt;
}
i = super.this_disk.raid_disk;
if (best[i] == -1
|| devices[best[i]].events < devices[devcnt].events) {
best[i] = devcnt;
}
i = devices[devcnt].raid_disk;
if (i>=0 && i < MD_SB_DISKS)
if (best[i] == -1
|| devices[best[i]].events < devices[devcnt].events)
best[i] = devcnt;
devcnt++;
}
@ -313,13 +274,17 @@ int Assemble(char *mddev, int mdfd,
* I wonder how many
*/
okcnt = 0;
for (i=0; i< first_super.raid_disks;i++) {
sparecnt=0;
for (i=0; i< MD_SB_DISKS;i++) {
int j = best[i];
if (j < 0) continue;
if (devices[j].events+1 >=
devices[most_recent].events) {
devices[j].uptodate = 1;
okcnt++;
if (i < first_super.raid_disks)
okcnt++;
else
sparecnt++;
}
}
while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) {
@ -327,10 +292,133 @@ int Assemble(char *mddev, int mdfd,
* not up-to-date, update the superblock
* and add it.
*/
fprintf(stderr,"NotImplementedYet\n");
/* FIXME */
exit(2);
int fd;
for (i=0; i<first_super.raid_disks; i++) {
int j = best[i];
if (j>=0 &&
!devices[j].uptodate &&
devices[j].events > 0 &&
(chosen_drive < 0 ||
devices[j].events > devices[chosen_drive].events))
chosen_drive = j;
}
if (chosen_drive < 0)
break;
fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n",
devices[chosen_drive].devname, devices[chosen_drive].raid_disk,
(int)(devices[chosen_drive].events),
(int)(devices[most_recent].events));
fd = open(devices[chosen_drive].devname, O_RDWR);
if (fd < 0) {
fprintf(stderr, Name ": Couldn't open %s for write - not updating\n",
devices[chosen_drive].devname);
devices[chosen_drive].events = 0;
continue;
}
if (load_super(fd, &super)) {
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;
super.sb_csum = calc_sb_csum(&super);
/*DRYRUN*/ if (store_super(fd, &super)) {
close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname);
devices[chosen_drive].events = 0;
continue;
}
close(fd);
devices[chosen_drive].events = devices[most_recent].events;
devices[chosen_drive].uptodate = 1;
okcnt++;
}
/* Now we want to look at the superblock which the kernel will base things on
* and compare the devices that we think are working with the devices that the
* superblock thinks are working.
* If there are differences and --force is given, then update this chosen
* superblock.
*/
for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) {
int j = best[i];
int fd;
if (j<0)
continue;
if (!devices[j].uptodate)
continue;
chosen_drive = j;
if ((fd=open(devices[j].devname, O_RDONLY))< 0) {
fprintf(stderr, Name ": Cannot open %s: %s\n",
devices[j].devname, strerror(errno));
return 1;
}
if (load_super(fd, &super)) {
close(fd);
fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
devices[j].devname);
return 1;
}
close(fd);
}
for (i=0; i<MD_SB_DISKS; i++) {
int j = best[i];
if (j<0)
continue;
if (!devices[j].uptodate)
continue;
if (devices[j].major != super.disks[j].major ||
devices[j].minor != super.disks[j].minor) {
change |= 1;
super.disks[j].major = devices[j].major;
super.disks[j].minor = devices[j].minor;
}
if (devices[j].uptodate &&
(super.disks[i].state & (1 << MD_DISK_FAULTY))) {
if (force) {
fprintf(stderr, Name ": "
"clearing FAULT flag for device %d in %s for %s\n",
j, mddev, devices[j].devname);
super.disks[i].state &= ~(1<<MD_DISK_FAULTY);
change |= 2;
} else {
fprintf(stderr, Name ": "
"device %d in %s is marked faulty in superblock, but %s seems ok\n",
i, mddev, devices[j].devname);
}
}
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);
}
}
if ((force && (change & 2))
|| (old_linux && (change & 1))) {
int fd;
super.sb_csum = calc_sb_csum(&super);
fd = open(devices[chosen_drive].devname, O_RDWR);
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)) {
close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname);
return 1;
}
close(fd);
change = 0;
}
/* Almost ready to actually *do* something */
if (!old_linux) {
if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) {
@ -338,9 +426,16 @@ int Assemble(char *mddev, int mdfd,
mddev, strerror(errno));
return 1;
}
/* First, add the raid disks */
for (i=0; i<first_super.raid_disks; i++) {
int j = best[i];
/* First, add the raid disks, but add the chosen one last */
for (i=0; i<=MD_SB_DISKS; i++) {
int j;
if (i < MD_SB_DISKS) {
j = best[i];
if (j == chosen_drive)
continue;
} else
j = chosen_drive;
if (j >= 0 && devices[j].uptodate) {
mdu_disk_info_t disk;
memset(&disk, 0, sizeof(disk));
@ -351,18 +446,27 @@ int Assemble(char *mddev, int mdfd,
devices[j].devname,
mddev,
strerror(errno));
okcnt--;
}
} else if (verbose)
if (i < first_super.raid_disks)
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)
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))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
fprintf(stderr, Name ": %s has been started with %d drives\n",
mddev, okcnt);
fprintf(stderr, Name ": %s has been started with %d drive%s",
mddev, okcnt, okcnt==1?"":"s");
if (sparecnt)
fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
fprintf(stderr, ".\n");
return 0;
}
fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
@ -370,68 +474,19 @@ int Assemble(char *mddev, int mdfd,
return 1;
}
if (runstop == -1) {
fprintf(stderr, Name ": %s assembled from %d drives, but not started.\n",
mddev, okcnt);
fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n",
mddev, okcnt, okcnt==1?"":"s");
return 0;
}
fprintf(stderr, Name ": %s assembled from %d drives - not enough to start it.\n",
mddev, okcnt);
fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it.\n",
mddev, okcnt, okcnt==1?"":"s");
return 1;
} else {
/* It maybe just a case of calling START_ARRAY, but it may not..
* We need to pick a working device, read it's super block, and make
* sure all the device numbers and the minor number are right.
* Then we might need to re-write the super block.
* THEN we call START_ARRAY
* If the md_minor is wrong, wejust give up for now. The alternate is to
* re-write ALL super blocks.
/* The "chosen_drive" is a good choice, and if necessary, the superblock has
* been updated to point to the current locations of devices.
* so we can just start the array
*/
int chosen_drive = -1;
int change = 0;
int dev;
for (i=0; i<first_super.nr_disks; i++) {
if (!devices[i].uptodate)
continue;
if (chosen_drive == -1) {
int fd;
chosen_drive = i;
if (open(devices[i].devname, O_RDONLY)>= 0) {
fprintf(stderr, Name ": Cannot open %s: %s\n",
devices[i].devname, strerror(errno));
return 1;
}
if (load_super(fd, &super)) {
close(fd);
fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
devices[i].devname);
return 1;
}
close(fd);
}
if (devices[i].major != super.disks[i].major ||
devices[i].minor != super.disks[i].minor) {
change = 1;
super.disks[i].major = devices[i].major;
super.disks[i].minor = devices[i].minor;
}
}
if (change) {
int fd;
super.sb_csum = calc_sb_csum(super);
fd = open(devices[chosen_drive].devname, O_RDWR);
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)) {
close(fd);
fprintf(stderr, Name ": Could not re-write superblock on %s\n",
devices[chosen_drive].devname);
return 1;
}
close(fd);
}
dev = MKDEV(devices[chosen_drive].major,
devices[chosen_drive].minor);
if (ioctl(mdfd, START_ARRAY, dev)) {

199
Create.c
View File

@ -34,7 +34,7 @@
int Create(char *mddev, int mdfd,
int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
int subdevs, char *subdev[],
int runstop, int verbose)
int runstop, int verbose, int force)
{
/*
* Create a new raid array.
@ -57,13 +57,16 @@ int Create(char *mddev, int mdfd,
int i;
int fail=0, warn=0;
struct stat stb;
int first_missing = MD_SB_DISKS*2;
int missing_disks = 0;
int insert_point = MD_SB_DISKS*2; /* where to insert a missing drive */
mdu_array_info_t array;
if (md_get_version(mdfd) < 9000) {
fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
return 1;
fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
return 1;
}
if (level == -10) {
fprintf(stderr,
@ -75,6 +78,11 @@ int Create(char *mddev, int mdfd,
Name ": a number of --raid-disks must be given to create an array\n");
return 1;
}
if (raiddisks < 2 && level >= 4) {
fprintf(stderr,
Name ": atleast 2 raid-disks needed for level 4 or 5\n");
return 1;
}
if (raiddisks+sparedisks > MD_SB_DISKS) {
fprintf(stderr,
Name ": too many discs requested: %d+%d > %d\n",
@ -82,9 +90,14 @@ int Create(char *mddev, int mdfd,
return 1;
}
if (subdevs > raiddisks+sparedisks) {
fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
return 1;
fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
return 1;
}
if (subdevs < raiddisks) {
fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
return 1;
}
/* now set some defaults */
if (layout == -1)
switch(level) {
@ -106,10 +119,22 @@ int Create(char *mddev, int mdfd,
}
/* now look at the subdevs */
array.active_disks = 0;
array.working_disks = 0;
for (i=0; i<subdevs; i++) {
char *dname = subdev[i];
int dsize, freesize;
int fd = open(dname, O_RDONLY, 0);
int fd;
if (strcasecmp(subdev[i], "missing")==0) {
if (first_missing > i)
first_missing = i;
missing_disks ++;
continue;
}
array.working_disks++;
if (i < raiddisks)
array.active_disks++;
fd = open(dname, O_RDONLY, 0);
if (fd <0 ) {
fprintf(stderr, Name ": Cannot open %s: %s\n",
dname, strerror(errno));
@ -124,29 +149,29 @@ int Create(char *mddev, int mdfd,
continue;
}
if (dsize < MD_RESERVED_SECTORS*2) {
fprintf(stderr, Name ": %s is too small: %dK\n",
dname, dsize/2);
fail = 1;
close(fd);
continue;
fprintf(stderr, Name ": %s is too small: %dK\n",
dname, dsize/2);
fail = 1;
close(fd);
continue;
}
freesize = MD_NEW_SIZE_SECTORS(dsize);
freesize /= 2;
if (size && freesize < size) {
fprintf(stderr, Name ": %s is smaller that given size."
" %dK < %dK + superblock\n", dname, freesize, size);
fail = 1;
close(fd);
continue;
fprintf(stderr, Name ": %s is smaller that given size."
" %dK < %dK + superblock\n", dname, freesize, size);
fail = 1;
close(fd);
continue;
}
if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) {
maxdisc = i;
maxsize = freesize;
maxdisc = i;
maxsize = freesize;
}
if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) {
mindisc = i;
minsize = freesize;
mindisc = i;
minsize = freesize;
}
warn |= check_ext2(fd, dname);
warn |= check_reiser(fd, dname);
@ -154,41 +179,50 @@ int Create(char *mddev, int mdfd,
close(fd);
}
if (fail) {
fprintf(stderr, Name ": create aborted\n");
return 1;
fprintf(stderr, Name ": create aborted\n");
return 1;
}
if (size == 0) {
if (mindisc == -1) {
fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
return 1;
}
size = minsize;
if (verbose)
fprintf(stderr, Name ": size set to %dK\n", size);
if (mindisc == -1) {
fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
return 1;
}
size = minsize;
if (verbose && level>0)
fprintf(stderr, Name ": size set to %dK\n", size);
}
if ((maxsize-size)*100 > maxsize) {
fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
subdev[maxdisc], size);
warn = 1;
fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
subdev[maxdisc], size);
warn = 1;
}
if (warn) {
if (runstop!= 1) {
if (!ask("Continue creating array? ")) {
fprintf(stderr, Name ": create aborted.\n");
return 1;
if (runstop!= 1) {
if (!ask("Continue creating array? ")) {
fprintf(stderr, Name ": create aborted.\n");
return 1;
}
} else {
if (verbose)
fprintf(stderr, Name ": creation continuing despite oddities due to --run\n");
}
} else {
if (verbose)
fprintf(stderr, Name ": creation continuing despite oddities due to --run\n");
}
}
/* If this is raid5, we want to configure the last active slot
* as missing, so that a reconstruct happens (faster than re-parity)
*/
if (force == 0 && level == 5 && first_missing >= raiddisks) {
insert_point = raiddisks-1;
sparedisks++;
array.active_disks--;
missing_disks++;
}
/* Ok, lets try some ioctls */
array.level = level;
array.size = size;
array.nr_disks = raiddisks+sparedisks+(level==4||level==5);
array.raid_disks = raiddisks;
/* The kernel should *know* what md_minor we are dealing
* with, but it chooses to trust me instead. Sigh
@ -197,10 +231,10 @@ int Create(char *mddev, int mdfd,
if (fstat(mdfd, &stb)==0)
array.md_minor = MINOR(stb.st_rdev);
array.not_persistent = 0;
if (level == 4 || level == 5)
array.state = 1; /* clean, but one drive will be missing */
if (level == 5 && (insert_point < raiddisks || first_missing < raiddisks))
array.state = 1; /* clean, but one drive will be missing */
else
array.state = 0; /* not clean, but no errors */
array.state = 0; /* not clean, but no errors */
/* There is lots of redundancy in these disk counts,
* raid_disks is the most meaningful value
@ -221,52 +255,57 @@ int Create(char *mddev, int mdfd,
* So for now, we assume that all raid and spare
* devices will be given.
*/
array.active_disks=raiddisks-(level==4||level==5);
array.working_disks=raiddisks+sparedisks;
array.spare_disks=sparedisks + (level==4||level==5);
array.failed_disks=0;
array.spare_disks=sparedisks;
array.failed_disks=missing_disks;
array.nr_disks = array.working_disks + array.failed_disks;
array.layout = layout;
array.chunk_size = chunk*1024;
if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
mddev, strerror(errno));
return 1;
fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
mddev, strerror(errno));
return 1;
}
for (i=0; i<subdevs; i++) {
int fd = open(subdev[i], O_RDONLY, 0);
struct stat stb;
mdu_disk_info_t disk;
if (fd < 0) {
fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
subdev[i]);
return 1;
}
fstat(fd, &stb);
disk.number = i;
if ((level==4 || level==5) &&
disk.number >= raiddisks-1)
disk.number++;
disk.raid_disk = disk.number;
if (disk.raid_disk < raiddisks)
disk.state = 6; /* active and in sync */
else
disk.state = 0;
disk.major = MAJOR(stb.st_rdev);
disk.minor = MINOR(stb.st_rdev);
close(fd);
if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
subdev[i], strerror(errno));
return 1;
}
int fd;
struct stat stb;
mdu_disk_info_t disk;
disk.number = i;
if (i >= insert_point)
disk.number++;
disk.raid_disk = disk.number;
if (disk.raid_disk < raiddisks)
disk.state = 6; /* active and in sync */
else
disk.state = 0;
if (strcasecmp(subdev[i], "missing")==0) {
disk.major = 0;
disk.minor = 0;
disk.state = 1; /* faulty */
} else {
fd = open(subdev[i], O_RDONLY, 0);
if (fd < 0) {
fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
subdev[i]);
return 1;
}
fstat(fd, &stb);
disk.major = MAJOR(stb.st_rdev);
disk.minor = MINOR(stb.st_rdev);
close(fd);
}
if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
subdev[i], strerror(errno));
return 1;
}
}
/* hack */
if (level==4 || level==5) {
if (insert_point < MD_SB_DISKS) {
mdu_disk_info_t disk;
disk.number = raiddisks-1;
disk.number = insert_point;
disk.raid_disk = disk.number;
disk.state = 1; /* faulty */
disk.major = disk.minor = 0;

View File

@ -119,7 +119,7 @@ int Detail(char *dev)
printf("\n");
printf(" Number Major Minor RaidDisk State\n");
for (d= 0; d<array.nr_disks; d++) {
for (d= 0; d<array.raid_disks+array.spare_disks; d++) {
mdu_disk_info_t disk;
char *dv;
disk.number = d;

View File

@ -147,7 +147,7 @@ int Examine(char *dev)
}
printf("\n");
printf(" Number Major Minor RaidDisk State\n");
for (d= -1; d<(signed int)super.nr_disks; d++) {
for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) {
mdp_disk_t *dp;
char *dv;
char nb[5];

View File

@ -29,7 +29,7 @@
CFLAGS = -Wall,error,strict-prototypes -ggdb
OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o dlink.o
OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Monitor.o dlink.o
all : mdctl
mdctl : $(OBJS)
@ -38,7 +38,7 @@ mdctl : $(OBJS)
$(OBJS) : mdctl.h
clean :
rm -f mdctl $(OBJS)
rm -f mdctl $(OBJS) core
dist : clean
./makedist

View File

@ -107,7 +107,7 @@ int Manage_runstop(char *devname, int fd, int runstop)
}
} else if (runstop < 0){
if (ioctl(fd, STOP_ARRAY, NULL)) {
fprintf(stderr, Name ": fail to re writable for %s: %s\n",
fprintf(stderr, Name ": fail to stop array %s: %s\n",
devname, strerror(errno));
return 1;
}

211
Monitor.c Normal file
View File

@ -0,0 +1,211 @@
/*
* mdctl - manage Linux "md" devices aka RAID arrays.
*
* Copyright (C) 2001 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 "mdctl.h"
#include "md_p.h"
#include "md_u.h"
#include <sys/signal.h>
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
int Monitor(int num_devs, char *devlist[],
char *mailaddr, char *alert_cmd,
int period,
char *config)
{
/*
* Every few seconds, scan every md device looking for changes
* When a change is found, log it, possibly run the alert command,
* and possibly send Email
*
* For each array, we record:
* Update time
* active/working/failed/spare drives
* State of each device.
*
* If the update time changes, check out all the data again
* It is possible that we cannot get the state of each device
* due to bugs in the md kernel module.
*
* if active_drives decreases, generate a "Fail" event
* if active_drives increases, generate a "SpareActive" event
*
* if we detect an array with active<raid and spare==0
* we look at other arrays that have same spare-group
* If we find one with active==raid and spare>0,
* and if we can get_disk_info and find a name
* Then we hot-remove and hot-add to the other array
*
*/
struct state {
char *devname;
long utime;
int err;
int active, working, failed, spare;
int devstate[MD_SB_DISKS];
struct state *next;
} *statelist = NULL;
int finished = 0;
while (! finished) {
mddev_ident_t mdlist = NULL;
int dnum=0;
if (num_devs == 0)
mdlist = conf_get_ident(config, NULL);
while (dnum < num_devs || mdlist) {
mddev_ident_t mdident;
struct state *st;
mdu_array_info_t array;
char *dev;
int fd;
char *event = NULL;
int i;
char *event_disc = NULL;
if (num_devs) {
dev = devlist[dnum++];
mdident = conf_get_ident(config, dev);
} else {
mdident = mdlist;
dev = mdident->devname;
mdlist = mdlist->next;
}
for (st=statelist; st ; st=st->next)
if (strcmp(st->devname, dev)==0)
break;
if (!st) {
st =malloc(sizeof *st);
if (st == NULL)
continue;
st->devname = strdup(dev);
st->utime = 0;
st->next = statelist;
st->err = 0;
statelist = st;
}
fd = open(dev, O_RDONLY);
if (fd < 0) {
if (!st->err)
fprintf(stderr, Name ": cannot open %s: %s\n",
dev, strerror(errno));
st->err=1;
continue;
}
if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
if (!st->err)
fprintf(stderr, Name ": cannot get array info for %s: %s\n",
dev, strerror(errno));
st->err=1;
close(fd);
continue;
}
st->err = 0;
if (st->utime == array.utime &&
st->failed == array.failed_disks) {
close(fd);
continue;
}
event = NULL;
if (st->utime) {
int i;
if (st->active > array.active_disks)
event = "Fail";
else if (st->working > array.working_disks)
event = "FailSpare";
else if (st->active < array.active_disks)
event = "ActiveSpare";
}
for (i=0; i<array.raid_disks+array.spare_disks; i++) {
mdu_disk_info_t disc;
disc.number = i;
if (ioctl(fd, GET_DISK_INFO, &disc)>= 0) {
if (event && event_disc == NULL &&
st->devstate[i] != disc.state) {
char * dv = map_dev(disc.major, disc.minor);
if (dv)
event_disc = strdup(dv);
}
st->devstate[i] = disc.state;
}
}
close(fd);
st->active = array.active_disks;
st->working = array.working_disks;
st->spare = array.spare_disks;
st->failed = array.failed_disks;
st->utime = array.utime;
if (event)
alert(event, dev, event_disc, mailaddr, alert_cmd);
}
sleep(period);
}
return 0;
}
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd)
{
if (cmd) {
int pid = fork();
switch(pid) {
default:
waitpid(pid, NULL, 0);
break;
case -1:
break;
case 0:
execl(cmd, cmd, event, dev, disc, NULL);
exit(2);
}
}
if (mailaddr && strncmp(event, "Fail", 4)==0) {
FILE *mp = popen(Sendmail, "w");
if (mp) {
char hname[256];
gethostname(hname, sizeof(hname));
signal(SIGPIPE, SIG_IGN);
fprintf(mp, "From: " Name " monitoring <root>\n");
fprintf(mp, "To: %s\n", mailaddr);
fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname);
fprintf(mp, "This is an automatically generated mail message from " Name "\n");
fprintf(mp, "running on %s\n\n", hname);
fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
if (disc)
fprintf(mp, "It could be related to sub-device %s.\n\n", disc);
fprintf(mp, "Faithfully yours, etc.\n");
fclose(mp);
}
}
/* FIXME log the event to syslog maybe */
}

View File

@ -29,7 +29,7 @@
#include "mdctl.h"
char Version[] = Name " - v0.4.2 - 27 July 2001\n";
char Version[] = Name " - v0.5 - 23 August 2001\n";
/*
* File: ReadMe.c
*
@ -78,7 +78,7 @@ char Version[] = Name " - v0.4.2 - 27 July 2001\n";
* command, subsequent Manage commands can finish the job.
*/
char short_options[]="-ABCDEhVvc:l:p:n:x:u:c:z:sarfRSow";
char short_options[]="-ABCDEFhVvc:l:p:m:n:x:u:c:d:z:sarfRSow";
struct option long_options[] = {
{"manage", 0, 0, '@'},
{"assemble", 0, 0, 'A'},
@ -86,6 +86,11 @@ struct option long_options[] = {
{"create", 0, 0, 'C'},
{"detail", 0, 0, 'D'},
{"examine", 0, 0, 'E'},
{"follow", 0, 0, 'F'},
/* synonyms */
{"monitor", 0, 0, 'F'},
/* after those will normally come the name of the md device */
{"help", 0, 0, 'h'},
{"version", 0, 0, 'V'},
@ -103,6 +108,7 @@ struct option long_options[] = {
/* For assemble */
{"uuid", 1, 0, 'u'},
{"super-minor",1,0, 'm'},
{"config", 1, 0, 'c'},
{"scan", 0, 0, 's'},
{"force", 0, 0, 'f'},
@ -115,6 +121,13 @@ struct option long_options[] = {
{"stop", 0, 0, 'S'},
{"readonly", 0, 0, 'o'},
{"readwrite", 0, 0, 'w'},
/* For Follow/monitor */
{"mail", 1, 0, 'm'},
{"program", 1, 0, 'p'},
{"alert", 1, 0, 'p'},
{"delay", 1, 0, 'd'},
{0, 0, 0, 0}
};
@ -130,6 +143,7 @@ char Help[] =
" mdctl --build device options...\n"
" mdctl --detail device\n"
" mdctl --examine device\n"
" mdctl --follow options...\n"
" mdctl device options...\n"
" mdctl is used for controlling Linux md devices (aka RAID arrays)\n"
" For detail help on major modes use, e.g.\n"
@ -145,6 +159,9 @@ char Help[] =
" --build -B : Build a legacy array without superblock\n"
" --detail -D : Print detail of a given md array\n"
" --examine -E : Print content of md superblock on device\n"
" --follow -F : Follow (monitor) any changes to devices and respond to them\n"
" --monitor : same as --follow\n"
"\n"
" --help -h : This help message or, after above option,\n"
" mode specific help message\n"
" --version -V : Print version information for mdctl\n"
@ -159,14 +176,24 @@ char Help[] =
" --raid-disks= -n : number of active devices in array\n"
" --spare-disks= -x : number of spares (eXtras) to allow space for\n"
" --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n"
" --force -f : Honour devices as listed on command line. Don't\n"
" : insert a missing drive for RAID5.\n"
"\n"
" For assemble:\n"
" --uuid= -u : uuid of array to assemble. Devices which don't\n"
" have this uuid are excluded\n"
" --super-minor= -m : minor number to look for in super-block when\n"
" choosing devices to use.\n"
" --config= -c : config file\n"
" --scan -s : scan config file for missing information\n"
" --force -f : Assemble the array even if some superblocks appear out-of-date\n"
"\n"
" For follow/monitor:\n"
" --mail= -m : Address to mail alerts of failure to\n"
" --program= -p : Program to run when an event is detected\n"
" --alert= : same as --program\n"
" --delay= -d : seconds of delay between polling state. default=60\n"
"\n"
" General management:\n"
" --add -a : add, or hotadd subsequent devices\n"
" --remove -r : remove subsequent devices\n"
@ -185,10 +212,10 @@ char Help_create[] =
" This usage will initialise a new md array and possibly associate some\n"
" devices with it. If enough devices are given to complete the array,\n"
" the array will be activated. Otherwise it will be left inactive\n"
" to be competed and activated by subsequent management commands.\n"
" to be completed and activated by subsequent management commands.\n"
"\n"
" As devices are added, they are checked to see if they contain\n"
" raid superblock or filesystems. They are also check to see if\n"
" raid superblocks or filesystems. They are also check to see if\n"
" the variance in device size exceeds 1%.\n"
" If any discrepancy is found, the array will not automatically\n"
" be run, though the presence of a '--run' can override this\n"
@ -225,30 +252,53 @@ char Help_assemble[] =
"\n"
"This usage assembles one or more raid arrays from pre-existing\n"
"components.\n"
"For each array, mdctl needs to know the md device, the uuid, and\n"
"a number of sub devices. These can be found in a number of ways.\n"
"For each array, mdctl needs to know the md device, the identify of\n"
"the array, and a number of sub devices. These can be found in a number\n"
"of ways.\n"
"\n"
"The md device is either given before --scan or is found from the\n"
"config file. In the latter case, multiple md devices can be started\n"
"with a single mdctl command.\n"
"The md device is either given on the command line or is found listed\n"
"in the config file. The array identity is determined either from the\n"
"--uuid or --super-minor commandline arguments, or from the config file,\n"
"or from the first component device on the command line.\n"
"\n"
"The uuid can be given with the --uuid option, or can be found in\n"
"in the config file, or will be taken from the super block on the first\n"
"subdevice listed on the command line or in a subsequent --add command.\n"
"The different combinations of these are as follows:\n"
" If the --scan option is not given, then only devices and identities\n"
" listed on the command line are considered.\n"
" The first device will be the array devices, and the remainder will\n"
" examined when looking for components.\n"
" If an explicit identity is given with --uuid or --super-minor, then\n"
" Each device with a superblock which matches that identity is considered,\n"
" otherwise every device listed is considered.\n"
"\n"
"Devices can be given on the --assemble command line, on subsequent\n"
"'mdctl --add' command lines, or from the config file. Only devices\n"
"which have an md superblock which contains the right uuid will be\n"
"considered for any device.\n"
" If the --scan option is given, and no devices are listed, then\n"
" every array listed in the config file is considered for assembly.\n"
" The identity can candidate devices are determined from the config file.\n"
"\n"
"The config file is only used if explicitly named with --config or\n"
"requested with --scan. In the later case, '/etc/md.conf' is used.\n"
" If the --scan option is given as well as one or more devices, then\n"
" Those devices are md devices that are to be assembled. Their identity\n"
" and components are determined from the config file.\n"
"\n"
"If --scan is not given, then the config file will only be used\n"
"to find uuids for md arrays.\n"
"The config file contains, apart from blank lines and comment lines that\n"
"start with a has, two sorts of configuration lines, array lines and\n"
"device lines.\n"
"Each configuration line is constructed of a number of space separated\n"
"words, and can be continued on subsequent physical lines by indenting\n"
"those lines.\n"
"\n"
"The format of the config file is:\n"
" not yet documented\n"
"A device line starts with the word 'device' and then has a number of words\n"
"which identify devices. These words should be names of devices in the filesystem,\n"
"and can contain wildcards. There can be multiple words or each device line,\n"
"and multiple device lines. All devices so listed are checked for relevant\n"
"super blocks when assembling arrays.\n"
"\n"
"An array line start with the word 'array'. This is followed by the name of\n"
"the array device in the filesystem, e.g. '/dev/md2'. Subsequent words\n"
"describe the identity of the array, used to recognise devices to include in the\n"
"array. The identity can be given as a UUID with a word starting 'uuid=', or\n"
"as a minor-number stored in the superblock using 'super-minor=', or as a list\n"
"of devices. This is given as a comma separated list of names, possibly containing\n"
"wildcards, preceeded by 'devices='. If multiple critea are given, than a device\n"
"must match all of them to be considered.\n"
"\n"
;

159
TAGS
View File

@ -1,4 +1,12 @@
dlink.h,193
struct __dl_head__dl_head5,100
#define dl_alloc(dl_alloc11,187
#define dl_new(dl_new12,297
#define dl_newv(dl_newv13,341
#define dl_next(dl_next15,391
#define dl_prev(dl_prev16,461
md_p.h,1316
#define _MD_P_H16,582
#define MD_RESERVED_BYTES 44,1414
@ -69,72 +77,123 @@ typedef struct mdu_start_info_s mdu_start_info_s97,2713
typedef struct mdu_param_smdu_param_s108,2878
} mdu_param_t;mdu_param_t113,3014
mdctl.h,823
mdctl.h,826
#define __USE_LARGEFILE6430,1115
#define MD_MAJOR 47,1491
extern char short_options[52,1531
extern struct option long_options[53,1560
extern char Version[54,1597
extern char Version[], Usage[54,1597
extern char Version[], Usage[], Help[54,1597
extern char Version[], Usage[], Help[], Help_create[54,1597
extern char Version[], Usage[], Help[], Help_create[], Help_build[54,1597
extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[54,1597
typedef struct mddev_uuid_s mddev_uuid_s58,1762
} *mddev_uuid_t;mddev_uuid_t62,1852
typedef struct mddev_dev_s mddev_dev_s65,1918
} *mddev_dev_t;mddev_dev_t68,1990
#define ALGORITHM_LEFT_ASYMMETRIC 73,2044
#define ALGORITHM_RIGHT_ASYMMETRIC 74,2080
#define ALGORITHM_LEFT_SYMMETRIC 75,2117
#define ALGORITHM_RIGHT_SYMMETRIC 76,2152
#define Name 52,1531
extern char short_options[54,1553
extern struct option long_options[55,1582
extern char Version[56,1619
extern char Version[], Usage[56,1619
extern char Version[], Usage[], Help[56,1619
extern char Version[], Usage[], Help[], Help_create[56,1619
extern char Version[], Usage[], Help[], Help_create[], Help_build[56,1619
extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[56,1619
typedef struct mddev_ident_s mddev_ident_s68,2055
} *mddev_ident_t;mddev_ident_t80,2292
typedef struct mddev_dev_s mddev_dev_s83,2359
} *mddev_dev_t;mddev_dev_t86,2431
typedef struct mapping mapping88,2448
} mapping_t;mapping_t91,2496
extern mapping_t r5layout[95,2606
extern mapping_t r5layout[], pers[95,2606
Assemble.c,22
int Assemble(34,1171
Build.c,19
int Build(32,1135
Build.c,100
#define REGISTER_DEV 32,1135
#define START_MD 33,1176
#define STOP_MD 34,1217
int Build(36,1259
Create.c,20
int Create(32,1135
int Create(34,1171
Detail.c,20
int Detail(34,1171
Examine.c,21
int Examine(34,1171
int Examine(37,1261
Manage.c,79
int Manage_ro(32,1135
int Manage_runstop(36,1191
int Manage_subdevs(40,1251
Manage.c,161
#define REGISTER_DEV 34,1171
#define START_MD 35,1212
#define STOP_MD 36,1253
int Manage_ro(38,1295
int Manage_runstop(75,2149
int Manage_subdevs(118,3161
ReadMe.c,231
#define Name 32,1135
char Version[33,1156
char short_options[82,3241
struct option long_options[83,3297
char Usage[122,4441
char Help[127,4498
char Help_create[181,6989
char Help_build[203,7973
char Help_assemble[216,8513
ReadMe.c,265
char Version[32,1135
char short_options[81,3222
struct option long_options[82,3280
char Usage[123,4484
char Help[128,4541
char Help_create[185,7233
char Help_build[212,8453
char Help_assemble[225,8993
mapping_t r5layout[284,11939
mapping_t pers[298,12155
config.c,102
char DefaultConfFile[43,1371
mddev_uuid_t conf_get_uuids(45,1416
mddev_dev_t conf_get_devs(50,1482
config.c,479
char DefaultConfFile[68,2396
char *keywords[70,2441
int match_keyword(77,2640
char *conf_word(97,3148
char *conf_line(163,4739
void free_line(184,5041
struct conf_dev conf_dev195,5183
} *cdevlist 198,5244
int devline(202,5267
mddev_ident_t mddevlist 220,5590
mddev_ident_t *mddevlp 221,5622
void arrayline(223,5660
int loaded 289,7453
void load_conffile(291,7470
mddev_ident_t conf_get_ident(324,7961
mddev_dev_t conf_get_devs(334,8163
int match_oneof(369,8791
mdctl.c,40
int main(33,1153
#define O(O131,3313
dlink.c,177
void *dl_head(11,180
void dl_free(20,289
void dl_init(26,363
void dl_insert(32,430
void dl_add(40,598
void dl_del(48,763
char *dl_strndup(57,969
char *dl_strdup(73,1176
util.c,212
mdctl.c,64
int open_mddev(33,1153
int main(50,1472
#define O(O149,3610
raid5extend.c,39
int phys2log(2,1
raid5_extend(46,902
util.c,573
int parse_uuid(40,1354
int md_get_version(80,2091
int get_linux_version(99,2448
int enough(111,2639
int same_uuid(127,2889
void uuid_from_super(137,3018
int compare_super(151,3295
int load_super(185,4258
int md_get_version(82,2117
int get_linux_version(101,2476
int enough(113,2673
int same_uuid(129,2923
void uuid_from_super(139,3052
int compare_super(153,3329
int load_super(187,4292
int store_super(227,4950
int check_ext2(253,5321
int check_reiser(284,6084
int check_raid(308,6640
int ask(324,7003
char *map_num(344,7368
int map_name(354,7503
struct devmap devmap369,7832
} *devlist 373,7911
int devlist_ready 374,7930
#define __USE_XOPEN_EXTENDED376,7954
int add_dev(380,8003
char *map_dev(396,8370
int calc_sb_csum(412,8645

54
TODO
View File

@ -3,13 +3,14 @@
- report "chunk" or "rounding" depending on raid level DONE
- report "linear" instead of "-1" for raid level DONE
- decode ayout depending on raid level DONE
- get Assemble to upgrade devices if force flag.
- --verbose and --force flags.
- set md_minor, *_disks for Create - DONE
- for create raid5, how to choose between
all working, but not insync
one missing, one spare, insync
- and for raid1 - some failed drives...
- when RUN_ARRAY, make sure *_disks counts are right
- get --detail to extract extra stuff from superblock,
@ -23,3 +24,54 @@
- mdctl -S /dev/md0 /dev/md1 gives internal error
- mdctl --detail --scan print summary of what it can find?
---------
Assemble doesn't add spares. - DONE
Create to allow "missing" name for devices.
Create to accept "--force" for do exactly what is requested
- get Assemble to upgrade devices if force flag.
ARRAY lines in config file to have super_minor=n
ARRAY lines in config file to have device=pattern, and only accept
those devices
If UUID given, insist on that
If not, but super_minor given, require all found with that minor
to have same uuid
If only device given, all valid supers on those devices must have
same uuid
allow /dev/mdX as first argument before any options
Possible --dry-run option for create and assemble--force
Assemble to check that all devices mentioned in superblock
are present.
New mode: --Monitor (or --Follow)
Periodically check status of all arrays (listed in config file).
Log every event and apparent cause - or differences
Email and alert - or run a program - for important events
Move spares around if necessary.
An Array line can have a spare-group= field that indicates that
the array shares spares with other arrays with the same
spare-group name.
If an array has a failed and no spares, then check all other
arrays in the spare group. If one has no failures and a spare,
then consider that spare.
Choose the smallest considered spare that is large enough.
If there is one, then hot-remove it from it's home, and
hot-add it to the array in question.
--mail-to address
--alert-handler program
Will also extract information from /proc/mdstat if present,
and consider 20% marks in rebuild as events.
Events are:
drive fails - causes mail to be sent
rebuild started
spare activated
spare removed
spare added

405
config.c
View File

@ -30,6 +30,8 @@
#include "mdctl.h"
#include "dlink.h"
#include <glob.h>
#include <fnmatch.h>
/*
* Read the config file
*
@ -74,15 +76,15 @@ char *keywords[] = { "device", "array", NULL };
int match_keyword(char *word)
{
int len = strlen(word);
int n;
int len = strlen(word);
int n;
if (len < 3) return -1;
for (n=0; keywords[n]; n++) {
if (strncasecmp(word, keywords[n], len)==0)
return n;
}
return -1;
if (len < 3) return -1;
for (n=0; keywords[n]; n++) {
if (strncasecmp(word, keywords[n], len)==0)
return n;
}
return -1;
}
/* conf_word gets one word from the conf file.
@ -94,60 +96,60 @@ int match_keyword(char *word)
char *conf_word(FILE *file, int allow_key)
{
int wsize = 100;
int len = 0;
int c;
int quote;
int wordfound = 0;
char *word = malloc(wsize);
int wsize = 100;
int len = 0;
int c;
int quote;
int wordfound = 0;
char *word = malloc(wsize);
if (!word) abort();
if (!word) abort();
while (wordfound==0) {
/* at the end of a word.. */
c = getc(file);
if (c == '#')
while (c != EOF && c != '\n')
while (wordfound==0) {
/* at the end of a word.. */
c = getc(file);
if (c == EOF) break;
if (c == '\n') continue;
if (c == '#')
while (c != EOF && c != '\n')
c = getc(file);
if (c == EOF) break;
if (c == '\n') continue;
if (c != ' ' && c != '\t' && ! allow_key) {
ungetc(c, file);
break;
}
/* looks like it is safe to get a word here, if there is one */
quote = 0;
/* first, skip any spaces */
while (c == ' ' || c == '\t')
c = getc(file);
if (c != EOF && c != '\n' && c != '#') {
/* we really have a character of a word, so start saving it */
while (c != EOF && c != '\n' && (quote || (c!=' ' && c != '\t'))) {
wordfound = 1;
if (quote && c == quote) quote = 0;
else if (quote == 0 && (c == '\'' || c == '"'))
quote = c;
else {
if (len == wsize-1) {
wsize += 100;
word = realloc(word, wsize);
if (!word) abort();
}
word[len++] = c;
if (c != ' ' && c != '\t' && ! allow_key) {
ungetc(c, file);
break;
}
c = getc(file);
}
/* looks like it is safe to get a word here, if there is one */
quote = 0;
/* first, skip any spaces */
while (c == ' ' || c == '\t')
c = getc(file);
if (c != EOF && c != '\n' && c != '#') {
/* we really have a character of a word, so start saving it */
while (c != EOF && c != '\n' && (quote || (c!=' ' && c != '\t'))) {
wordfound = 1;
if (quote && c == quote) quote = 0;
else if (quote == 0 && (c == '\'' || c == '"'))
quote = c;
else {
if (len == wsize-1) {
wsize += 100;
word = realloc(word, wsize);
if (!word) abort();
}
word[len++] = c;
}
c = getc(file);
}
}
if (c != EOF) ungetc(c, file);
}
if (c != EOF) ungetc(c, file);
}
word[len] = 0;
word[len] = 0;
/* printf("word is <%s>\n", word); */
if (!wordfound) {
free(word);
word = NULL;
}
return word;
if (!wordfound) {
free(word);
word = NULL;
}
return word;
}
/*
@ -160,33 +162,33 @@ char *conf_word(FILE *file, int allow_key)
char *conf_line(FILE *file)
{
char *w;
char *list;
char *w;
char *list;
w = conf_word(file, 1);
if (w == NULL) return NULL;
w = conf_word(file, 1);
if (w == NULL) return NULL;
list = dl_strdup(w);
free(w);
dl_init(list);
while ((w = conf_word(file,0))){
char *w2 = dl_strdup(w);
list = dl_strdup(w);
free(w);
dl_add(list, w2);
}
dl_init(list);
while ((w = conf_word(file,0))){
char *w2 = dl_strdup(w);
free(w);
dl_add(list, w2);
}
/* printf("got a line\n");*/
return list;
return list;
}
void free_line(char *line)
{
char *w;
for (w=dl_next(line); w != line; w=dl_next(line)) {
dl_del(w);
dl_free(w);
}
dl_free(line);
char *w;
for (w=dl_next(line); w != line; w=dl_next(line)) {
dl_del(w);
dl_free(w);
}
dl_free(line);
}
@ -199,141 +201,198 @@ struct conf_dev {
int devline(char *line)
{
char *w;
struct conf_dev *cd;
char *w;
struct conf_dev *cd;
for (w=dl_next(line); w != line; w=dl_next(w)) {
if (w[0] == '/') {
cd = malloc(sizeof(*cd));
cd->name = strdup(w);
cd->next = cdevlist;
cdevlist = cd;
} else {
fprintf(stderr, Name ": unreconised word on DEVICE line: %s\n",
w);
for (w=dl_next(line); w != line; w=dl_next(w)) {
if (w[0] == '/') {
cd = malloc(sizeof(*cd));
cd->name = strdup(w);
cd->next = cdevlist;
cdevlist = cd;
} else {
fprintf(stderr, Name ": unreconised word on DEVICE line: %s\n",
w);
}
}
}
}
mddev_uuid_t uuidlist = NULL;
mddev_uuid_t *uidlp = &uuidlist;
mddev_ident_t mddevlist = NULL;
mddev_ident_t *mddevlp = &mddevlist;
void arrayline(char *line)
{
char *w;
char *dev = NULL;
__u32 uuid[4];
int uidset=0;
mddev_uuid_t mu;
char *w;
for (w=dl_next(line); w!=line; w=dl_next(w)) {
if (w[0] == '/') {
if (dev)
fprintf(stderr, Name ": only give one device per ARRAY line: %s and %s\n",
dev, w);
else dev = w;
} else if (strncasecmp(w, "uuid=", 5)==0 ) {
if (uidset)
fprintf(stderr, Name ": only specify uuid once, %s ignored.\n",
w);
else {
if (parse_uuid(w+5, uuid))
uidset = 1;
else
fprintf(stderr, Name ": bad uuid: %s\n", w);
}
} else {
fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
w);
struct mddev_ident_s mis;
mddev_ident_t mi;
mis.uuid_set = 0;
mis.super_minor = -1;
mis.devices = NULL;
mis.devname = NULL;
for (w=dl_next(line); w!=line; w=dl_next(w)) {
if (w[0] == '/') {
if (mis.devname)
fprintf(stderr, Name ": only give one device per ARRAY line: %s and %s\n",
mis.devname, w);
else mis.devname = w;
} else if (strncasecmp(w, "uuid=", 5)==0 ) {
if (mis.uuid_set)
fprintf(stderr, Name ": only specify uuid once, %s ignored.\n",
w);
else {
if (parse_uuid(w+5, mis.uuid))
mis.uuid_set = 1;
else
fprintf(stderr, Name ": bad uuid: %s\n", w);
}
} else if (strncasecmp(w, "super-minor=", 12)==0 ) {
if (mis.super_minor >= 0)
fprintf(stderr, Name ": only specify super-minor once, %s ignored.\n",
w);
else {
char *endptr;
mis.super_minor= strtol(w+12, &endptr, 10);
if (w[12]==0 || endptr[0]!=0 || mis.super_minor < 0) {
fprintf(stderr, Name ": invalid super-minor number: %s\n",
w);
mis.super_minor = -1;
}
}
} else if (strncasecmp(w, "devices=", 8 ) == 0 ) {
if (mis.devices)
fprintf(stderr, Name ": only specify devices once (use a comma separated list). %s ignored\n",
w);
else
mis.devices = strdup(w+8);
} else if (strncasecmp(w, "spare-group=", 12) == 0 ) {
if (mis.spare_group)
fprintf(stderr, Name ": only specify one spare group per array. %s ignored.\n",
w);
else
mis.spare_group = strdup(w+12);
} else {
fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
w);
}
}
if (mis.devname == NULL)
fprintf(stderr, Name ": ARRAY line with a device\n");
else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor < 0)
fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname);
else {
mi = malloc(sizeof(*mi));
*mi = mis;
mi->devname = strdup(mis.devname);
mi->next = NULL;
*mddevlp = mi;
mddevlp = &mi->next;
}
}
if (dev == NULL)
fprintf(stderr, Name ": ARRAY line with a device\n");
else if (uidset == 0)
fprintf(stderr, Name ": ARRAY line %s has no uuid\n", dev);
else {
mu = malloc(sizeof(*mu));
mu->devname = strdup(dev);
memcpy(mu->uuid, uuid, sizeof(uuid));
mu->next = NULL;
*uidlp = mu;
uidlp = &mu->next;
}
}
int loaded = 0;
void load_conffile(char *conffile)
{
FILE *f;
char *line;
FILE *f;
char *line;
if (loaded) return;
if (conffile == NULL)
conffile = DefaultConfFile;
if (loaded) return;
if (conffile == NULL)
conffile = DefaultConfFile;
f = fopen(conffile, "r");
if (f ==NULL)
return;
f = fopen(conffile, "r");
if (f ==NULL)
return;
loaded = 1;
while ((line=conf_line(f))) {
switch(match_keyword(line)) {
case 0: /* DEVICE */
devline(line);
break;
case 1:
arrayline(line);
break;
default:
fprintf(stderr, Name ": Unknown keyword %s\n", line);
loaded = 1;
while ((line=conf_line(f))) {
switch(match_keyword(line)) {
case 0: /* DEVICE */
devline(line);
break;
case 1:
arrayline(line);
break;
default:
fprintf(stderr, Name ": Unknown keyword %s\n", line);
}
free_line(line);
}
free_line(line);
}
/* printf("got file\n"); */
}
mddev_uuid_t conf_get_uuids(char *conffile)
mddev_ident_t conf_get_ident(char *conffile, char *dev)
{
load_conffile(conffile);
return uuidlist;
mddev_ident_t rv;
load_conffile(conffile);
rv = mddevlist;
while (dev && rv && strcmp(dev, rv->devname)!=0)
rv = rv->next;
return rv;
}
mddev_dev_t conf_get_devs(char *conffile)
{
glob_t globbuf;
struct conf_dev *cd;
int flags = 0;
static mddev_dev_t dlist = NULL;
int i;
glob_t globbuf;
struct conf_dev *cd;
int flags = 0;
static mddev_dev_t dlist = NULL;
int i;
while (dlist) {
mddev_dev_t t = dlist;
dlist = dlist->next;
free(t->devname);
free(t);
}
while (dlist) {
mddev_dev_t t = dlist;
dlist = dlist->next;
free(t->devname);
free(t);
}
load_conffile(conffile);
load_conffile(conffile);
for (cd=cdevlist; cd; cd=cd->next) {
glob(cd->name, flags, NULL, &globbuf);
flags |= GLOB_APPEND;
}
for (cd=cdevlist; cd; cd=cd->next) {
glob(cd->name, flags, NULL, &globbuf);
flags |= GLOB_APPEND;
}
for (i=0; i<globbuf.gl_pathc; i++) {
mddev_dev_t t = malloc(sizeof(*t));
t->devname = strdup(globbuf.gl_pathv[i]);
t->next = dlist;
dlist = t;
for (i=0; i<globbuf.gl_pathc; i++) {
mddev_dev_t t = malloc(sizeof(*t));
t->devname = strdup(globbuf.gl_pathv[i]);
t->next = dlist;
dlist = t;
/* printf("one dev is %s\n", t->devname);*/
}
globfree(&globbuf);
}
globfree(&globbuf);
return dlist;
return dlist;
}
int match_oneof(char *devices, char *devname)
{
/* check if one of the comma separated patterns in devices
* matches devname
*/
while (devices && *devices) {
char patn[1024];
char *p = devices;
devices = strchr(devices, ',');
if (!devices)
devices = p + strlen(p);
if (devices-p < 1024) {
strncpy(patn, p, devices-p);
patn[devices-p] = 0;
if (fnmatch(patn, devname, FNM_PATHNAME)==0)
return 1;
}
if (*devices == ',')
devices++;
}
return 0;
}

View File

@ -7,14 +7,15 @@ else echo $target is not a directory
exit 2
fi
set `grep '^char Version' ReadMe.c `
echo version = $7
base=mdctl-$7.tgz
version=`echo $7 | sed 's/v//'`
echo version = $version
base=mdctl-$version.tgz
if [ -f $target/$base ]
then
echo $target/$base exists.
exit 1
fi
trap "rm $target/$base; exit" 1 2 3
( cd .. ; tar czvf - mdctl ) > $target/$base
( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude=RCS mdctl-$version ; rm mdctl-$version ) > $target/$base
chmod a+r $target/$base
ls -l $target/$base

2
md_p.h
View File

@ -128,7 +128,7 @@ typedef struct mdp_superblock_s {
__u32 failed_disks; /* 4 Number of failed disks */
__u32 spare_disks; /* 5 Number of spare disks */
__u32 sb_csum; /* 6 checksum of the whole superblock */
#ifdef __BIG_ENDIAN
#if __BYTE_ORDER == __BIG_ENDIAN
__u32 events_hi; /* 7 high-order of superblock update count */
__u32 events_lo; /* 8 low-order of superblock update count */
#else

287
mdctl.8 Normal file
View File

@ -0,0 +1,287 @@
.\" -*- nroff -*-
.TH mdctl 8
.SH NAME
mdctl \- a single program that can be used to control Linux md devices
.SH SYNOPSIS
.BI mdctl
[mode] <raiddevice> [options]
.SH DESCRIPTION
RAID devices are virtual devices created from two or more
real block devices. This allows multiple disks to be combined into a single
filesystem, possibly with integrated redundancy to survive drive failure.. Linux RAID devices
are implemented through the md device driver.
If you're using the
.B /proc
filesystem,
.B /proc/mdstat
gives you informations about md devices status.
Currently, Linux supports linear md devices, RAID0 (striping), RAID1
(mirrroring), RAID4 and RAID5. For information on the various levels of
RAID, check out:
http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
for new releases of the RAID driver check out:
ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
.B mdctl
is a single program that can be used to control Linux md devices. It
is intended to provide all the functionality (and more) of the mdtools
and raidtools but with a very different interface.
mdctl can perform all functions without a configuration file. There is the
option of using a configuration file, but not in the same way that raidtools
uses one. raidtools uses a configuration file to describe how to create a
RAID array, and also uses this file partially to start a previously created
RAID array. Further, raidtools requires the configuration file for such
things as stopping a raid array which needs to know nothing about the array.
The configuration file that can be used by mdctl lists two different things:
.IP "\fB\-\fP"
a list of md devices and information about how to identify each. The
identity can consist of a UUID, and minor-number as recorded on the
superblock, or a list of devices.
.IP "\fB\-\fP"
a list of devices that should be scanned for md sub-devices.
.SH MODES
mdctl has 4 major modes of operation:
.IP "\fBCreate\fP"
This mode is used to create a new array with a superblock. It can progress
in several step create-add-add-run or it can all happen with one command.
.IP "\fBAssemble\fP"
This mode is used to assemble the parts of a previously created
array into an active array. Components can be explicitly given
or can be searched for.
.B mdctl
(optionally) checks that the components
do form a bonafide array, and can, on request, fiddle superblock
version numbers so as to assemble a faulty array.
.IP "\fBBuild\fP"
This is for building legacy arrays without superblocks.
.IP "\fBManage\fP"
This is for odd bits an pieces like hotadd, hotremove, setfaulty, stop,
readonly,readwrite If an array is only partially setup by the
Create/Assemble/Build command, subsequent Manage commands can finish the
job.
.SH OPTIONS
Available options are:
.IP "\fB\-C\fP, \fB\-\-create\fP"
Create a new array
.IP "\fB-A\fP, \fB\-\-assemble\fP"
Assemble an existing array
.IP "\fB\-B\fP, \fB\-\-build\fP"
Build a legacy array without superblock
.IP "\fB\-D\fP, \fB\-\-detail\fP"
Print detail of a given md array
.IP "\fB\-E\fP, \fB\-\-examine\fP"
Print content of md superblock on device
.IP "\fB\-h\fP, \fB\-\-help\fP"
This help message or, after above option, mode specific help message
.IP "\fB\-V\fP, \fB\-\-version\fP"
Print version information for mdctl
.IP "\fB\-v\fP, \fB\-\-verbose\fP"
Be more verbose about what is happening
.SH For create or build:
.IP "\fB\-c\fP, \fB\-\-chunk=\fP"
chunk size of kibibytes
.IP "\fB\-\-rounding=\fP"
rounding factor for linear array (==chunk size)
.IP "\fB\-l\fP, \fB\-\-level=\fP"
raid level: 0,1,4,5,linear. 0 or linear for build
.IP "\fB\-p\fP, \fB\-\-parity=\fP"
raid5 parity algorithm: {left,right}-{,a}symmetric
.IP "\fB\-\-layout=\fP"
same as --parity
.IP "\fB\-n\fP, \fB\-\-raid-disks=\fP"
number of active devices in array
.IP "\fB\-x\fP, \fB\-\-spare-disks=\fP"
number of spares (eXtras) to allow space for
.IP "\fB\-z\fP, \fB\-\-size=\fP"
Size (in K) of each drive in RAID1/4/5 - optional
.SH For assemble:
.IP "\fB\-u\fP, \fB\-\-uuid=\fP"
uuid of array to assemble. Devices which don't have this uuid are excluded
.IP "\fB\-c\fP, \fB\-\-config=\fP"
config file
.IP "\fB\-s\fP, \fB\-\-scan\fP"
scan config file for missing information
.IP "\fB\-f\fP, \fB\-\-force\fP"
Assemble the array even if some superblocks appear out-of-date
.SH General management
.IP "\fB\-a\fP, \fB\-\-add\fP"
add, or hotadd subsequent devices
.IP "\fB\-r\fP, \fB\-\-remove\fP"
remove subsequent devices
.IP "\fB\-f\fP, \fB\-\-fail\fP"
mark subsequent devices a faulty
.IP "\fB\-\-set-faulty\fP"
same as --fail
.IP "\fB\-R\fP, \fB\-\-run\fP"
start a partially built array
.IP "\fB\-S\fP, \fB\-\-stop\fP"
deactivate array, releasing all resources
.IP "\fB\-o\fP, \fB\-\-readonly\fP"
mark array as readonly
.IP "\fB\-w\fP, \fB\-\-readwrite\fP"
mark array as readwrite
.SH CREATE MODE
Usage:
.B mdctl
--create device --chunk=X --level=Y --raid-disks=Z devices
This usage will initialise a new md array and possibly associate some
devices with it. If enough devices are given to complete the array, the
array will be activated. Otherwise it will be left inactive to be completed
and activated by subsequent management commands.
As devices are added, they are checked to see if they contain raid
superblocks or filesystems. They are also check to see if the variance in
device size exceeds 1%.
If any discrepancy is found, the array will not automatically be run, though
the presence of a
.B --run
can override this caution.
If the
.B --size
option is given, it is not necessary to list any subdevices in this command.
They can be added later, before a
.B --run.
If no
.B --size
is given, the apparent size of the smallest drive given is used.
The General management options that are valid with --create are:
.IP "\fB\-\-run\fP"
insist of running the array even if not all devices are present or some look
odd.
.IP "\fB\-\-readonly\fP"
start the array readonly - not supported yet.
.SH ASSEMBLY MODE
Usage:
.B mdctl
--assemble device options...
.B mdctl
--assemble --scan options...
This usage assembles one or more raid arrays from pre-existing components.
For each array, mdctl needs to know the md device, the uuid, and a number of
sub devices. These can be found in a number of ways.
The md device is either given before
.B --scan
or is found from the config file. In the latter case, multiple md devices
can be started with a single mdctl command.
The uuid can be given with the
.B --uuid
option, or can be found in in the config file, or will be taken from the
super block on the first subdevice listed on the command line or in a
subsequent
.B --add
command.
Devices can be given on the
.B --assemble
command line, on subsequent
.B 'mdctl --add'
command lines, or from the config file. Only devices which have an md
superblock which contains the right uuid will be considered for any device.
The config file is only used if explicitly named with
.B --config
or requested with
.B --scan.
In the later case,
.B /etc/md.conf
is used.
If
.B --scan
is not given, then the config file will only be used to find uuids for md
arrays.
The format of the config file is:
not yet documented
.SH BUILD MDOE
Usage:
.B mdctl
--build device -chunk=X --level=Y --raid-disks=Z devices
This usage is similar to
.B --create.
The difference is that it creates a legacy array without a superblock. With
these arrays there is no different between initially creating the array and
subsequently assembling the array, except that hopefully there is useful
data there in the second case.
The level may only be 0 or linear. All devices must be listed and the array
will be started once complete.
.SH BUGS
no known bugs.
.SH TODO
.SH SEE ALSO
.IR raidtab (5),
.IR raid0run (8),
.IR raidstop (8),
.IR mkraid (8)

828
mdctl.c
View File

@ -30,376 +30,466 @@
#include "mdctl.h"
#include "md_p.h"
int main(int argc, char *argv[])
int open_mddev(char *dev)
{
char mode = '\0';
int opt;
char *help_text;
char *c;
int rv;
int i;
int chunk = 0;
int size = 0;
int level = -10;
int layout = -1;
int raiddisks = 0;
int sparedisks = 0;
int uuid[4];
int uuidset = 0;
char *configfile = NULL;
int scan = 0;
char devmode = 0;
int runstop = 0;
int readonly = 0;
char *mddev = NULL;
char *subdev[MD_SB_DISKS];
int devmodes[MD_SB_DISKS];
int subdevs = 0;
int verbose = 0;
int force = 0;
int mdfd = -1;
while ((opt=getopt_long(argc, argv,
short_options, long_options,
NULL)) != -1) {
switch(opt) {
case '@': /* just incase they say --manage */
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
/* setting mode - only once */
if (mode) {
fprintf(stderr, Name ": --%s/-%c not allowed, mode already set to %s\n",
long_options[opt-'A'+1].name,
long_options[opt-'A'+1].val,
long_options[mode-'A'+1].name);
exit(2);
}
mode = opt;
continue;
case 'h':
help_text = Help;
switch (mode) {
case 'C': help_text = Help_create; break;
case 'B': help_text = Help_build; break;
case 'A': help_text = Help_assemble; break;
}
fputs(help_text,stderr);
exit(0);
case 'V':
fputs(Version, stderr);
exit(0);
case 'v': verbose = 1;
continue;
case 1: /* an undecorated option - must be a device name.
* The first device is the "md" device unless scan
* has been set or mode is Examine or Detail
*/
if (mddev == NULL && !scan && mode != 'E' && mode != 'D')
mddev = optarg;
else {
if (subdevs +1 >= MD_SB_DISKS) {
fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n",
optarg, MD_SB_DISKS);
exit(2);
}
subdev[subdevs] = optarg;
devmodes[subdevs] = devmode;
subdevs++;
}
continue;
case ':':
case '?':
fputs(Usage, stderr);
exit(2);
default:
/* force mode setting - @==manage if nothing else */
if (!mode) mode = '@';
int mdfd = open(dev, O_RDWR, 0);
if (mdfd < 0)
fprintf(stderr,Name ": error opening %s: %s\n",
dev, strerror(errno));
else if (md_get_version(mdfd) <= 0) {
fprintf(stderr, Name ": %s does not appear to be an md device\n",
dev);
close(mdfd);
mdfd = -1;
}
/* We've got a mode, and opt is now something else which
* could depend on the mode */
#define O(a,b) ((a<<8)|b)
switch (O(mode,opt)) {
case O('C','c'):
case O('B','c'): /* chunk or rounding */
if (chunk) {
fprintf(stderr, Name ": chunk/rounding may only be specified once. "
"Second value is %s.\n", optarg);
exit(2);
}
chunk = strtol(optarg, &c, 10);
if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
optarg);
exit(2);
}
continue;
case O('c','z'): /* size */
if (size) {
fprintf(stderr, Name ": size may only be specified once. "
"Second value is %s.\n", optarg);
exit(2);
}
size = strtol(optarg, &c, 10);
if (!optarg[0] || *c || size < 4) {
fprintf(stderr, Name ": invalid size: %s\n",
optarg);
exit(2);
}
continue;
case O('C','l'):
case O('B','l'): /* set raid level*/
if (level != -10) {
fprintf(stderr, Name ": raid level may only be set once. "
"Second value is %s.\n", optarg);
exit(2);
}
level = map_name(pers, optarg);
if (level == -10) {
fprintf(stderr, Name ": invalid raid level: %s\n",
optarg);
exit(2);
}
if (level > 0 && mode == 'B') {
fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
optarg);
exit(2);
}
if (sparedisks > 0 && level < 1) {
fprintf(stderr, Name ": raid level %s is incompatible with spare-disks setting.\n",
optarg);
exit(2);
}
continue;
case O('C','p'): /* raid5 layout */
if (layout >= 0) {
fprintf(stderr,Name ": layout may only be sent once. "
"Second value was %s\n", optarg);
exit(2);
}
switch(level) {
default:
fprintf(stderr, Name ": layout now meaningful for %s arrays.\n",
map_num(pers, level));
exit(2);
case -10:
fprintf(stderr, Name ": raid level must be given before layout.\n");
exit(2);
case 5:
layout = map_name(r5layout, optarg);
if (layout==-10) {
fprintf(stderr, Name ": layout %s not understood for raid5.\n",
optarg);
exit(2);
}
break;
}
continue;
case O('C','n'):
case O('B','n'): /* number of raid disks */
if (raiddisks) {
fprintf(stderr, Name ": raid-disks set twice: %d and %s\n",
raiddisks, optarg);
exit(2);
}
raiddisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
fprintf(stderr, Name ": invalid number of raid disks: %s\n",
optarg);
exit(2);
}
continue;
case O('C','x'): /* number of spare (eXtra) discs */
if (sparedisks) {
fprintf(stderr,Name ": spare-disks set twice: %d and %s\n",
sparedisks, optarg);
exit(2);
}
if (level > -10 && level < 1) {
fprintf(stderr, Name ": spare-disks setting is incompatible with raid level %d\n",
level);
exit(2);
}
sparedisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
fprintf(stderr, Name ": invalid number of spare disks: %s\n",
optarg);
exit(2);
}
continue;
/* now for the Assemble options */
case O('A','f'): /* force assembly */
force = 1;
continue;
case O('A','u'): /* uuid of array */
if (uuidset) {
fprintf(stderr, Name ": uuid cannot bet set twice. "
"Second value %s.\n", optarg);
exit(2);
}
if (parse_uuid(optarg, uuid))
uuidset = 1;
else {
fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
exit(2);
}
continue;
case O('A','c'): /* config file */
if (configfile) {
fprintf(stderr, Name ": configfile cannot be set twice. "
"Second value is %s.\n", optarg);
exit(2);
}
configfile = optarg;
/* FIXME possibly check that config file exists. Even parse it */
continue;
case O('A','s'): /* scan */
scan = 1;
continue;
/* now the general management options. Some are applicable
* to other modes. None have arguments.
*/
case O('@','a'):
case O('C','a'):
case O('B','a'):
case O('A','a'): /* add a drive */
devmode = 'a';
continue;
case O('@','r'): /* remove a drive */
devmode = 'r';
continue;
case O('@','f'): /* set faulty */
case O('C','f'):
devmode = 'f';
continue;
case O('@','R'):
case O('A','R'):
case O('B','R'):
case O('C','R'): /* Run the array */
if (runstop < 0) {
fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
exit(2);
}
runstop = 1;
continue;
case O('@','S'):
if (runstop > 0) {
fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
exit(2);
}
runstop = -1;
continue;
case O('@','o'):
if (readonly < 0) {
fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
exit(2);
}
readonly = 1;
continue;
case O('@','w'):
if (readonly > 0) {
fprintf(stderr, "mkdctl: Cannot have both readwrite and readonly.\n");
exit(2);
}
readonly = -1;
continue;
}
/* We have now processed all the valid options. Anything else is
* an error
*/
fprintf(stderr, Name ": option %c not valid in mode %c\n",
opt, mode);
exit(2);
}
if (!mode) {
fputs(Usage, stderr);
exit(2);
}
/* Ok, got the option parsing out of the way
* hopefully it's mostly right but there might be some stuff
* missing
*
* That is mosty checked in ther per-mode stuff but...
*
* There must be an mddev unless D or E or (A and scan)
* If there is one, we open it.
*/
if (mode !='D' && mode !='E' && ! (mode =='A' && scan)) {
if (!mddev) {
fprintf(stderr, Name ": an md device must be given in this mode\n");
exit(2);
}
mdfd = open(mddev, O_RDWR, 0);
if (mdfd < 0) {
fprintf(stderr,Name ": error opening %s: %s\n",
mddev, strerror(errno));
exit(1);
}
if (md_get_version(mdfd) <= 0) {
fprintf(stderr, Name ": %s does not appear to be an md device\n",
mddev);
close(mdfd);
exit(1);
}
}
rv =0;
switch(mode) {
case '@':/* Management */
/* readonly, add/remove, readwrite, runstop */
if (readonly>0)
rv = Manage_ro(mddev, mdfd, readonly);
if (!rv && subdevs)
rv = Manage_subdevs(mddev, mdfd, subdevs, subdev, devmodes);
if (!rv && readonly < 0)
rv = Manage_ro(mddev, mdfd, readonly);
if (!rv && runstop)
rv = Manage_runstop(mddev, mdfd, runstop);
break;
case 'A': /* Assemble */
rv = Assemble(mddev, mdfd, uuid, uuidset, configfile, scan, subdevs, subdev, readonly, runstop, verbose, force);
break;
case 'B': /* Build */
rv = Build(mddev, mdfd, chunk, level, raiddisks, subdevs,subdev);
break;
case 'C': /* Create */
rv = Create(mddev, mdfd, chunk, level, layout, size, raiddisks, sparedisks,
subdevs,subdev,runstop, verbose);
break;
case 'D': /* Detail */
for (i=0; i<subdevs; i++)
rv |= Detail(subdev[i]);
break;
case 'E': /* Examine */
for (i=0; i<subdevs; i++)
rv |= Examine(subdev[i]);
break;
}
exit(rv);
return mdfd;
}
int main(int argc, char *argv[])
{
char mode = '\0';
int opt;
char *help_text;
char *c;
int rv;
int i;
int chunk = 0;
int size = 0;
int level = -10;
int layout = -1;
int raiddisks = 0;
int sparedisks = 0;
struct mddev_ident_s ident;
char *configfile = NULL;
int scan = 0;
char devmode = 0;
int runstop = 0;
int readonly = 0;
char *devs[MD_SB_DISKS+1];
int devmodes[MD_SB_DISKS+1];
int devs_found = 0;
int verbose = 0;
int force = 0;
char *mailaddr = NULL;
char *program = NULL;
int delay = 0;
int mdfd = -1;
ident.uuid_set=0;
ident.super_minor= -1;
ident.devices=0;
while ((opt=getopt_long(argc, argv,
short_options, long_options,
NULL)) != -1) {
switch(opt) {
case '@': /* just incase they say --manage */
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
/* setting mode - only once */
if (mode) {
fprintf(stderr, Name ": --%s/-%c not allowed, mode already set to %s\n",
long_options[opt-'A'+1].name,
long_options[opt-'A'+1].val,
long_options[mode-'A'+1].name);
exit(2);
}
mode = opt;
continue;
case 'h':
help_text = Help;
switch (mode) {
case 'C': help_text = Help_create; break;
case 'B': help_text = Help_build; break;
case 'A': help_text = Help_assemble; break;
}
fputs(help_text,stderr);
exit(0);
case 'V':
fputs(Version, stderr);
exit(0);
case 'v': verbose = 1;
continue;
case 1: /* an undecorated option - must be a device name.
* Depending on mode, it could be that:
* All devices listed are "md" devices : --Detail, -As
* No devices are "md" devices : --Examine
* First device is "md", others are component: -A,-B,-C
*/
if (devs_found >= MD_SB_DISKS+1) {
fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n",
optarg, MD_SB_DISKS+1);
exit(2);
}
devs[devs_found] = optarg;
devmodes[devs_found] = devmode;
devs_found++;
continue;
case ':':
case '?':
fputs(Usage, stderr);
exit(2);
default:
/* force mode setting - @==manage if nothing else */
if (!mode) mode = '@';
}
/* We've got a mode, and opt is now something else which
* could depend on the mode */
#define O(a,b) ((a<<8)|b)
switch (O(mode,opt)) {
case O('C','c'):
case O('B','c'): /* chunk or rounding */
if (chunk) {
fprintf(stderr, Name ": chunk/rounding may only be specified once. "
"Second value is %s.\n", optarg);
exit(2);
}
chunk = strtol(optarg, &c, 10);
if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
optarg);
exit(2);
}
continue;
case O('C','z'): /* size */
if (size) {
fprintf(stderr, Name ": size may only be specified once. "
"Second value is %s.\n", optarg);
exit(2);
}
size = strtol(optarg, &c, 10);
if (!optarg[0] || *c || size < 4) {
fprintf(stderr, Name ": invalid size: %s\n",
optarg);
exit(2);
}
continue;
case O('C','l'):
case O('B','l'): /* set raid level*/
if (level != -10) {
fprintf(stderr, Name ": raid level may only be set once. "
"Second value is %s.\n", optarg);
exit(2);
}
level = map_name(pers, optarg);
if (level == -10) {
fprintf(stderr, Name ": invalid raid level: %s\n",
optarg);
exit(2);
}
if (level > 0 && mode == 'B') {
fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
optarg);
exit(2);
}
if (sparedisks > 0 && level < 1) {
fprintf(stderr, Name ": raid level %s is incompatible with spare-disks setting.\n",
optarg);
exit(2);
}
continue;
case O('C','p'): /* raid5 layout */
if (layout >= 0) {
fprintf(stderr,Name ": layout may only be sent once. "
"Second value was %s\n", optarg);
exit(2);
}
switch(level) {
default:
fprintf(stderr, Name ": layout now meaningful for %s arrays.\n",
map_num(pers, level));
exit(2);
case -10:
fprintf(stderr, Name ": raid level must be given before layout.\n");
exit(2);
case 5:
layout = map_name(r5layout, optarg);
if (layout==-10) {
fprintf(stderr, Name ": layout %s not understood for raid5.\n",
optarg);
exit(2);
}
break;
}
continue;
case O('C','n'):
case O('B','n'): /* number of raid disks */
if (raiddisks) {
fprintf(stderr, Name ": raid-disks set twice: %d and %s\n",
raiddisks, optarg);
exit(2);
}
raiddisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
fprintf(stderr, Name ": invalid number of raid disks: %s\n",
optarg);
exit(2);
}
continue;
case O('C','x'): /* number of spare (eXtra) discs */
if (sparedisks) {
fprintf(stderr,Name ": spare-disks set twice: %d and %s\n",
sparedisks, optarg);
exit(2);
}
if (level > -10 && level < 1) {
fprintf(stderr, Name ": spare-disks setting is incompatible with raid level %d\n",
level);
exit(2);
}
sparedisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
fprintf(stderr, Name ": invalid number of spare disks: %s\n",
optarg);
exit(2);
}
continue;
case O('C','f'): /* force honouring of device list */
force=1;
continue;
/* now for the Assemble options */
case O('A','f'): /* force assembly */
force = 1;
continue;
case O('A','u'): /* uuid of array */
if (ident.uuid_set) {
fprintf(stderr, Name ": uuid cannot bet set twice. "
"Second value %s.\n", optarg);
exit(2);
}
if (parse_uuid(optarg, ident.uuid))
ident.uuid_set = 1;
else {
fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
exit(2);
}
continue;
case O('A','c'): /* config file */
case O('F','c'):
if (configfile) {
fprintf(stderr, Name ": configfile cannot be set twice. "
"Second value is %s.\n", optarg);
exit(2);
}
configfile = optarg;
/* FIXME possibly check that config file exists. Even parse it */
continue;
case O('A','s'): /* scan */
scan = 1;
continue;
case O('F','m'): /* mail address */
if (mailaddr)
fprintf(stderr, Name ": only specify one mailaddress. %s ignored.\n",
optarg);
else
mailaddr = optarg;
continue;
case O('F','p'): /* alert program */
if (program)
fprintf(stderr, Name ": only specify one alter program. %s ignored.\n",
optarg);
else
program = optarg;
continue;
case O('F','d'): /* delay in seconds */
if (delay)
fprintf(stderr, Name ": only specify delay once. %s ignored.\n",
optarg);
else {
delay = strtol(optarg, &c, 10);
if (!optarg[0] || *c || delay<1) {
fprintf(stderr, Name ": invalid delay: %s\n",
optarg);
exit(2);
}
}
continue;
/* now the general management options. Some are applicable
* to other modes. None have arguments.
*/
case O('@','a'):
case O('C','a'):
case O('B','a'):
case O('A','a'): /* add a drive */
devmode = 'a';
continue;
case O('@','r'): /* remove a drive */
devmode = 'r';
continue;
case O('@','f'): /* set faulty */
devmode = 'f';
continue;
case O('@','R'):
case O('A','R'):
case O('B','R'):
case O('C','R'): /* Run the array */
if (runstop < 0) {
fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
exit(2);
}
runstop = 1;
continue;
case O('@','S'):
if (runstop > 0) {
fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
exit(2);
}
runstop = -1;
continue;
case O('@','o'):
if (readonly < 0) {
fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
exit(2);
}
readonly = 1;
continue;
case O('@','w'):
if (readonly > 0) {
fprintf(stderr, "mkdctl: Cannot have both readwrite and readonly.\n");
exit(2);
}
readonly = -1;
continue;
}
/* We have now processed all the valid options. Anything else is
* an error
*/
fprintf(stderr, Name ": option %c not valid in mode %c\n",
opt, mode);
exit(2);
}
if (!mode) {
fputs(Usage, stderr);
exit(2);
}
/* Ok, got the option parsing out of the way
* hopefully it's mostly right but there might be some stuff
* missing
*
* That is mosty checked in ther per-mode stuff but...
*
* For @,B,C and A without -s, the first device listed must be an md device
* we check that here and open it.
*/
if (mode=='@' || mode == 'B' || mode == 'C' || (mode == 'A' && ! scan)) {
if (devs_found < 1) {
fprintf(stderr, Name ": an md device must be given in this mode\n");
exit(2);
}
mdfd = open_mddev(devs[0]);
if (mdfd < 0)
exit(1);
}
rv = 0;
switch(mode) {
case '@':/* Management */
/* readonly, add/remove, readwrite, runstop */
if (readonly>0)
rv = Manage_ro(devs[0], mdfd, readonly);
if (!rv && devs_found>1)
rv = Manage_subdevs(devs[0], mdfd,
devs_found-1, devs+1, devmodes+1);
if (!rv && readonly < 0)
rv = Manage_ro(devs[0], mdfd, readonly);
if (!rv && runstop)
rv = Manage_runstop(devs[0], mdfd, runstop);
break;
case 'A': /* Assemble */
if (!scan)
rv = Assemble(devs[0], mdfd, &ident, configfile,
devs_found-1, devs+1,
readonly, runstop, verbose, force);
else if (devs_found>0)
for (i=0; i<devs_found; i++) {
mddev_ident_t array_ident = conf_get_ident(configfile, devs[i]);
mdfd = open_mddev(devs[i]);
if (mdfd < 0) {
rv |= 1;
continue;
}
if (array_ident == NULL) {
fprintf(stderr, Name ": %s not identified in config file.\n",
devs[i]);
rv |= 1;
continue;
}
rv |= Assemble(devs[i], mdfd, array_ident, configfile,
0, NULL,
readonly, runstop, verbose, force);
}
else {
mddev_ident_t array_list = conf_get_ident(configfile, NULL);
if (!array_list) {
fprintf(stderr, Name ": No arrays found in config file\n");
rv = 1;
} else
for (; array_list; array_list = array_list->next) {
mdfd = open_mddev(array_list->devname);
if (mdfd < 0) {
rv |= 1;
continue;
}
rv |= Assemble(array_list->devname, mdfd,
array_list, configfile,
0, NULL,
readonly, runstop, verbose, force);
}
}
break;
case 'B': /* Build */
rv = Build(devs[0], mdfd, chunk, level, raiddisks, devs_found-1,devs+1);
break;
case 'C': /* Create */
rv = Create(devs[0], mdfd, chunk, level, layout, size,
raiddisks, sparedisks,
devs_found-1,devs+1, runstop, verbose, force);
break;
case 'D': /* Detail */
for (i=0; i<devs_found; i++)
rv |= Detail(devs[i]);
break;
case 'E': /* Examine */
for (i=0; i<devs_found; i++)
rv |= Examine(devs[i]);
break;
case 'F': /* Follow */
rv= Monitor(devs_found, devs, mailaddr, program,
delay?delay:60, configfile);
}
exit(rv);
}

42
mdctl.h
View File

@ -56,12 +56,30 @@ extern struct option long_options[];
extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[];
/* structures read from config file */
/* List of mddevice names and uuids */
typedef struct mddev_uuid_s {
/* List of mddevice names and identifiers
* Identifiers can be:
* uuid=128-hex-uuid
* super-minor=decimal-minor-number-from-superblock
* devices=comma,separated,list,of,device,names,with,wildcards
*
* If multiple fields are present, the intersection of all matching
* devices is considered
*/
typedef struct mddev_ident_s {
char *devname;
int uuid_set;
__u32 uuid[4];
struct mddev_uuid_s *next;
} *mddev_uuid_t;
int super_minor; /* -1 if not set */
char *devices; /* comma separated list of device
* names with wild cards
*/
char *spare_group;
struct mddev_ident_s *next;
} *mddev_ident_t;
/* List of device names - wildcards expanded */
typedef struct mddev_dev_s {
@ -74,6 +92,10 @@ typedef struct mapping {
int num;
} mapping_t;
#ifndef Sendmail
#define Sendmail "/usr/lib/sendmail -t"
#endif
extern char *map_num(mapping_t *map, int num);
extern int map_name(mapping_t *map, char *name);
extern mapping_t r5layout[], pers[];
@ -88,8 +110,8 @@ extern int Manage_subdevs(char *devname, int fd,
extern int Assemble(char *mddev, int mdfd,
int uuid[4], int uuidset,
char *conffile, int scan,
mddev_ident_t ident,
char *conffile,
int subdevs, char *subdev[],
int readonly, int runstop,
int verbose, int force);
@ -102,10 +124,14 @@ extern int Build(char *mddev, int mdfd, int chunk, int level,
extern int Create(char *mddev, int mdfd,
int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
int subdevs, char *subdev[],
int runstop, int verbose);
int runstop, int verbose, int force);
extern int Detail(char *dev);
extern int Examine(char *dev);
extern int Monitor(int num_devs, char *devlist[],
char *mailaddr, char *alert_cmd,
int period,
char *config);
extern int md_get_version(int fd);
extern int get_linux_version();
@ -114,5 +140,5 @@ extern int check_ext2(int fd, char *name);
extern int check_reiser(int fd, char *name);
extern int check_raid(int fd, char *name);
extern mddev_uuid_t conf_get_uuids(char *);
extern mddev_ident_t conf_get_ident(char *, char*);
extern mddev_dev_t conf_get_devs(char *);

47
mdctl.spec Normal file
View File

@ -0,0 +1,47 @@
Summary: mdctl is used for controlling Linux md devices (aka RAID arrays)
Name: mdctl
Version: 0.5
Release: 1
Source0: http://www.cse.unsw.edu.au/~neilb/source/mdctl/mdctl-%{version}.tgz
URL: http://www.cse.unsw.edu.au/~neilb/source/mdctl/
Copyright: GPL
Group: Utilities/System
BuildRoot: /var/tmp/%{name}-root
Packager: Danilo Godec <danci@agenda.si>
%description
mdctl is a single program that can be used to control Linux md devices. It
is intended to provide all the functionality of the mdtools and raidtools
but with a very different interface.
mdctl can perform all functions without a configuration file. There is the
option of using a configuration file, but not in the same way that raidtools
uses one.
raidtools uses a configuration file to describe how to create a RAID array,
and also uses this file partially to start a previously created RAID array.
Further, raidtools requires the configuration file for such things as
stopping a raid array, which needs to know nothing about the array.
%prep
%setup -q -n mdctl
%build
make
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/sbin
install -m755 mdctl $RPM_BUILD_ROOT/sbin/
%clean
rm -rf $RPM_BUILD_ROOT
%files
%doc TODO testconfig testconfig2
/sbin/*
%changelog
* Tue Aug 07 2001 Danilo Godec <danci@agenda.si>
- initial RPM build

80
raid5extend.c Normal file
View File

@ -0,0 +1,80 @@
int phys2log(int phys, int stripe, int n, int layout)
{
/* In an 'n' disk array using 'layout',
* in stripe 'stripe', the physical disc 'phys'
* stores what logical chunk?
* -1 mean parity.
*
*/
switch(layout) {
case ALGORITHM_LEFT_ASYMMETRIC:
pd = (n-1) - (stripe % n);
if (phys < pd)
return phys;
else if (phys == pd)
return -1;
else return phys-1;
case ALGORITHM_RIGHT_ASYMMETRIC:
pd = stripe % n;
if (phys < pd)
return phys;
else if (phys == pd)
return -1;
else return phys-1;
case ALGORITHM_LEFT_SYMMETRIC:
pd = (n-1) - (stripe %n);
if (phys < pd)
return phys+ n-1-pd;
else if (phys == pd)
return -1;
else return phys-pd-1;
case ALGORITHM_RIGHT_SYMMETRIC:
pd = stripe % n;
if (phys < pd)
return phys+ n-1-pd;
else if (phys == pd)
return -1;
else return phys-pd-1;
}
return -2;
}
raid5_extend(unsigned long len, int chunksize, int layout, int n, int m, int rfds[], int wfds[])
{
static char buf[4096];
unsigned long blocks = len/4;
unsigned int blocksperchunk= chunksize/4096;
unsigned long b;
for (b=0; b<blocks; b++) {
unsigned long stripe = b / blocksperchunk;
unsigned int offset = b - (stripe*blocksperchunk);
unsigned long chunk = stripe * (n-1);
int src;
for (src=0; src<n; src++) {
int dnum, snum;
if (read(rfds[src], buf, sizeof(buf)) != sizeof(buf)) {
error();
return 0;
}
snum = phys2log(src, stripe, n, layout);
if (snum == -1)
continue;
chunk = stripe*(n-1)+snum;
dstripe = chunk/(m-1);
dnum = log2phys(chunk-(stripe*(m-1)), dstripe, m, layout);
llseek(wfds[dnum], dstripe*chunksize+(offset*4096), 0);
write(wfds[dnum], buf, sizeof(buf));
}
}
}

View File

@ -1,12 +0,0 @@
Hello there, "this is a" conf file
which has several lines
# there are comments
# losts of comments
with comments # really truely
Dev lines are needed
and might have
"blanks in them,
they really could
I think
that empty "" strings are confusing

View File

@ -1,3 +0,0 @@
DEV /dev/hda* /dev/sd?
ARRAY /dev/md0 uuid=1234.5678.abcd.ef09:1234.5678.abcd.ef90