mdctl-v0.4

This commit is contained in:
Neil Brown 2001-07-26 07:00:09 +00:00
parent 682c705194
commit 82b27616de
17 changed files with 855 additions and 39 deletions

View File

@ -107,7 +107,7 @@ int Assemble(char *mddev, int mdfd,
int most_recent = 0;
if (!mddev && !scan) {
fputs(Name ": internal error - Assemble called with no devie or scan\n", stderr);
fputs(Name ": internal error - Assemble called with no device or --scan\n", stderr);
return 1;
}
if (!mddev) {
@ -118,7 +118,7 @@ int Assemble(char *mddev, int mdfd,
fprintf(stderr, Name ": No devices found in config file\n");
return 1;
}
while (device_list) {
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) {
@ -136,11 +136,10 @@ int Assemble(char *mddev, int mdfd,
found++;
close(mdfd);
}
device_list = device_list->next;
}
if (found)
return 0;
fprintf(stderr,Name ": Did not successful Assemble any devices\n");
fprintf(stderr,Name ": Did not successfully Assemble any devices\n");
return 1;
}
@ -206,6 +205,10 @@ int Assemble(char *mddev, int mdfd,
for (i=0; i<MD_SB_DISKS; i++)
best[i] = -1;
if (verbose)
fprintf(stderr, Name ": looking for devices for %s\n",
mddev);
while (subdevs || devlist) {
char *devname;
int this_uuid[4];
@ -250,6 +253,13 @@ int Assemble(char *mddev, int mdfd,
continue;
}
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 (inargv || verbose)
fprintf(stderr, Name ": superblock on %s doesn't match\n",
@ -341,8 +351,8 @@ int Assemble(char *mddev, int mdfd,
devices[j].devname,
mddev,
strerror(errno));
} else
okcnt--;
}
} else if (verbose)
fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
i, mddev);
@ -350,17 +360,84 @@ int Assemble(char *mddev, int mdfd,
if (runstop == 1 ||
(runstop == 0 &&
enough(first_super.level, first_super.raid_disks, okcnt))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0)
if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
fprintf(stderr, Name ": %s has been started with %d drives\n",
mddev, okcnt);
return 0;
}
fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
mddev, strerror(errno));
return 1;
}
if (runstop == -1)
if (runstop == -1) {
fprintf(stderr, Name ": %s assembled from %d drives, but not started.\n",
mddev, okcnt);
return 0;
else return 1;
} else {
/* FIXME */
}
fprintf(stderr, Name ": %s assembled from %d drives - not enough to start it.\n",
mddev, okcnt);
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.
*/
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)) {
fprintf(stderr, Name ": Cannot start array: %s\n",
strerror(errno));
}
}
}

133
Build.c
View File

@ -29,8 +29,141 @@
#include "mdctl.h"
#define REGISTER_DEV _IO (MD_MAJOR, 1)
#define START_MD _IO (MD_MAJOR, 2)
#define STOP_MD _IO (MD_MAJOR, 3)
int Build(char *mddev, int mdfd, int chunk, int level,
int raiddisks,
int subdevs, char *subdev[])
{
/* Build a linear or raid0 arrays without superblocks
* We cannot really do any checks, we just do it.
* For md_version < 0.90.0, we call REGISTER_DEV
* with the device numbers, and then
* START_MD giving the "geometry"
* geometry is 0xpp00cc
* where pp is personality: 1==linear, 2=raid0
* cc = chunk size factor: 0==4k, 1==8k etc.
*
* For md_version >= 0.90.0 we call
* SET_ARRAY_INFO, ADD_NEW_DISK, RUN_ARRAY
*
*/
int i;
int vers;
struct stat stb;
if (raiddisks != subdevs) {
fprintf(stderr, Name ": requested %d devices in array but listed %d\n",
raiddisks, subdevs);
return 1;
}
/* scan all devices, make sure they really are block devices */
for (i=0; i<subdevs; i++) {
if (stat(subdev[i], &stb)) {
fprintf(stderr, Name ": Cannot find %s: %s\n",
subdev[i], strerror(errno));
return 1;
}
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
fprintf(stderr, Name ": %s is not a block device.\n",
subdev[i]);
return 1;
}
}
vers = md_get_version(mdfd);
/* looks Ok, go for it */
if (vers >= 90000) {
mdu_array_info_t array;
array.level = level;
array.size = 0;
array.nr_disks = raiddisks;
array.raid_disks = raiddisks;
array.md_minor = 0;
if (fstat(mdfd, &stb)==0)
array.md_minor = MINOR(stb.st_rdev);
array.not_persistent = 0;
array.state = 0; /* not clean, but no errors */
array.active_disks = raiddisks;
array.working_disks = raiddisks;
array.spare_disks = 0;
array.failed_disks = 0;
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;
}
}
/* now add the devices */
for (i=0; i<subdevs; i++) {
if (stat(subdev[i], &stb)) {
fprintf(stderr, Name ": Wierd: %s has disappeared.\n",
subdev[i]);
goto abort;
}
if ((stb.st_rdev & S_IFMT)!= S_IFBLK) {
fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n",
subdev[i]);
goto abort;
}
if (vers> 90000) {
mdu_disk_info_t disk;
disk.number = i;
disk.raid_disk = i;
disk.state = 6;
disk.major = MAJOR(stb.st_rdev);
disk.minor = MINOR(stb.st_rdev);
if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK failed for %s: %s\n",
subdev[i], strerror(errno));
goto abort;
}
} else {
if (ioctl(mdfd, REGISTER_DEV, &stb.st_rdev)) {
fprintf(stderr, Name ": REGISTER_DEV failed for %s.\n",
subdev[i], strerror(errno));
goto abort;
}
}
}
/* now to start it */
if (vers > 90000) {
mdu_param_t param; /* not used by syscall */
if (ioctl(mdfd, RUN_ARRAY, param)) {
fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
strerror(errno));
goto abort;
}
} else {
int arg;
arg=0;
while (chunk > 4096) {
arg++;
chunk >>= 1;
}
if (level == 0)
chunk |= 0x20000;
else chunk |= 0x10000;
if (ioctl(mdfd, START_MD, arg)) {
fprintf(stderr, Name ": START_MD failed: %s\n",
strerror(errno));
goto abort;
}
}
fprintf(stderr, Name ": array %s built and started.\n",
mddev);
return 0;
abort:
if (vers > 900000)
ioctl(mdfd, STOP_ARRAY, 0);
else
ioctl(mdfd, STOP_MD, 0);
return 1;
}

View File

@ -56,9 +56,9 @@ int Create(char *mddev, int mdfd,
int maxdisc= -1, mindisc = -1;
int i;
int fail=0, warn=0;
struct stat stb;
mdu_array_info_t array;
mdu_param_t param;
if (md_get_version(mdfd) < 9000) {
@ -188,14 +188,42 @@ int Create(char *mddev, int mdfd,
array.level = level;
array.size = size;
array.nr_disks = raiddisks+sparedisks;
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
*/
array.md_minor = 0;
if (fstat(mdfd, &stb)==0)
array.md_minor = MINOR(stb.st_rdev);
array.not_persistent = 0;
array.state = 0; /* not clean, but no errors */
array.active_disks=0;
array.working_disks=0;
array.spare_disks=0;
if (level == 4 || level == 5)
array.state = 1; /* clean, but one drive will be missing */
else
array.state = 0; /* not clean, but no errors */
/* There is lots of redundancy in these disk counts,
* raid_disks is the most meaningful value
* it describes the geometry of the array
* it is constant
* nr_disks is total number of used slots.
* it should be raid_disks+spare_disks
* spare_disks is the number of extra disks present
* see above
* active_disks is the number of working disks in
* active slots. (With raid_disks)
* working_disks is the total number of working disks,
* including spares
* failed_disks is the number of disks marked failed
*
* Ideally, the kernel would keep these (except raid_disks)
* up-to-date as we ADD_NEW_DISK, but it doesn't (yet).
* 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.layout = layout;
array.chunk_size = chunk*1024;
@ -217,13 +245,19 @@ int Create(char *mddev, int mdfd,
}
fstat(fd, &stb);
disk.number = i;
disk.raid_disk = i;
disk.state = 6; /* active and in sync */
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\b",
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
subdev[i], strerror(errno));
return 1;
}
@ -231,6 +265,7 @@ int Create(char *mddev, int mdfd,
/* param is not actually used */
if (runstop == 1 || subdevs >= raiddisks) {
mdu_param_t param;
if (ioctl(mdfd, RUN_ARRAY, &param)) {
fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
strerror(errno));

View File

@ -45,6 +45,9 @@ int Detail(char *dev)
time_t atime;
char *c;
mdp_super_t super;
int have_super = 0;
if (fd < 0) {
fprintf(stderr, Name ": cannot open %s: %s\n",
dev, strerror(errno));
@ -102,11 +105,23 @@ int Detail(char *dev)
c = map_num(r5layout, array.layout);
printf(" Layout : %s\n", c?c:"-unknown-");
}
printf(" Chunk Size : %dK\n", array.chunk_size/1024);
switch (array.level) {
case 0:
case 4:
case 5:
printf(" Chunk Size : %dK\n", array.chunk_size/1024);
break;
case -1:
printf(" Rounding : %dK\n", array.chunk_size/1024);
break;
default: break;
}
printf("\n");
printf(" Number Major Minor RaidDisk State\n");
for (d= 0; d<array.nr_disks; d++) {
mdu_disk_info_t disk;
char *dv;
disk.number = d;
if (ioctl(fd, GET_DISK_INFO, &disk) < 0) {
fprintf(stderr, Name ": cannot get disk detail for disk %d: %s\n",
@ -119,7 +134,28 @@ int Detail(char *dev)
if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active");
if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync");
if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed");
if ((dv=map_dev(disk.major, disk.minor))) {
printf(" %s", dv);
if (!have_super) {
/* try to read the superblock from this device
* to get more info
*/
int fd = open(dv, O_RDONLY);
if (fd >=0 &&
load_super(fd, &super) ==0 &&
super.ctime == array.ctime &&
super.level == array.level)
have_super = 1;
}
}
printf("\n");
}
if (have_super) {
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);
}
return 0;
}

View File

@ -29,6 +29,9 @@
#include "mdctl.h"
#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
#error no endian defined
#endif
#include "md_u.h"
#include "md_p.h"
int Examine(char *dev)
@ -47,7 +50,7 @@ int Examine(char *dev)
* utime, state etc
*
*/
int fd = open(dev, O_RDONLY, 0);
int fd = open(dev, O_RDONLY);
time_t atime;
mdp_super_t super;
int d;
@ -121,18 +124,32 @@ int Examine(char *dev)
printf(" Working Drives : %d\n", super.working_disks);
printf(" Failed Drives : %d\n", super.failed_disks);
printf(" Spare Drives : %d\n", super.spare_disks);
printf(" - checksum not checked yet - \n");
if (calc_sb_csum(&super) == super.sb_csum)
printf(" Checksum : %x - correct\n", super.sb_csum);
else
printf(" Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super));
printf(" Events : %d.%d\n", super.events_hi, super.events_lo);
printf("\n");
if (super.level == 5) {
c = map_num(r5layout, super.layout);
printf(" Layout : %s\n", c?c:"-unknown-");
}
printf(" Chunk Size : %dK\n", super.chunk_size/1024);
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 RaidDisk State\n");
for (d= -1; d<(signed int)super.nr_disks; d++) {
mdp_disk_t *dp;
char *dv;
char nb[5];
if (d>=0) dp = &super.disks[d];
else dp = &super.this_disk;
@ -143,6 +160,8 @@ int Examine(char *dev)
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 ((dv=map_dev(dp->major, dp->minor)))
printf(" %s", dv);
printf("\n");
}
return 0;

View File

@ -27,9 +27,9 @@
# Australia
#
CFLAGS = -Wall,error
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
OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o dlink.o
all : mdctl
mdctl : $(OBJS)

View File

@ -31,6 +31,10 @@
#include "md_u.h"
#include "md_p.h"
#define REGISTER_DEV _IO (MD_MAJOR, 1)
#define START_MD _IO (MD_MAJOR, 2)
#define STOP_MD _IO (MD_MAJOR, 3)
int Manage_ro(char *devname, int fd, int readonly)
{
/* switch to readonly or rw
@ -60,7 +64,7 @@ int Manage_ro(char *devname, int fd, int readonly)
}
} else if (readonly < 0) {
if (ioctl(fd, RESTART_ARRAY_RW, NULL)) {
fprintf(stderr, Name ": fail to re writable for %s: %s\n",
fprintf(stderr, Name ": failed to set writable for %s: %s\n",
devname, strerror(errno));
return 1;
}
@ -75,17 +79,26 @@ int Manage_runstop(char *devname, int fd, int runstop)
*/
mdu_array_info_t array;
mdu_param_t param; /* unused */
if (runstop == -1 && md_get_version(fd) < 9000) {
if (ioctl(fd, STOP_MD, 0)) {
fprintf(stderr, Name ": stopping device %s failed: %s\n",
devname, strerror(errno));
return 1;
}
}
if (md_get_version(fd) < 9000) {
fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
return 1;
}
/*
if (ioctl(fd, GET_ARRAY_INFO, &array)) {
fprintf(stderr, Name ": %s does not appear to be active.\n",
devname);
return 1;
}
*/
if (runstop>0) {
if (ioctl(fd, RUN_ARRAY, &param)) {
fprintf(stderr, Name ": failed to run array %s: %s\n",
@ -175,7 +188,7 @@ int Manage_subdevs(char *devname, int fd,
case 'r':
/* hot remove */
/* FIXME check that is is a current member */
/* FIXME check that it is a current member */
if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) {
fprintf(stderr, Name ": hot remove failed for %s: %s\n",
devnames[i], strerror(errno));

View File

@ -29,7 +29,7 @@
#include "mdctl.h"
char Version[] = Name " - v0.3 - 14 June 2001\n";
char Version[] = Name " - v0.4 - 26 July 2001\n";
/*
* File: ReadMe.c
*

16
TODO
View File

@ -1,12 +1,22 @@
- check superblock checksum in examine
- report "chunk" or "rounding" depending on raid level
- check superblock checksum in examine DONE
- 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
- set md_minor, *_disks for Create - DONE
- for create raid5, how to choose between
all working, but not insync
one missing, one spare, insync
- when RUN_ARRAY, make sure *_disks counts are right
- get --detail to extract extra stuff from superblock,
like uuid DONE
- --detail --brief to give a config file line
- parse config file. DONE
- test...
- when --assemble --scan, if an underlying device is an md device,
then try to assemble that device first.

289
config.c
View File

@ -28,7 +28,8 @@
*/
#include "mdctl.h"
#include "dlink.h"
#include <glob.h>
/*
* Read the config file
*
@ -38,17 +39,299 @@
* Each keeps the returned list and frees it when asked to make
* a new list.
*
* The format of the config file needs to be fairly extensible.
* Now, arrays only have names and uuids and devices merely are.
* But later arrays might want names, and devices might want superblock
* versions, and who knows what else.
* I like free format, abhore backslash line continuation, adore
* indentation for structure and am ok about # comments.
*
* So, each line that isn't blank or a #comment must either start
* with a key word, and not be indented, or must start with a
* non-key-word and must be indented.
*
* Keywords are DEVICE and ARRAY
* DEV{ICE} introduces some devices that might contain raid components.
* e.g.
* DEV style=0 /dev/sda* /dev/hd*
* DEV style=1 /dev/sd[b-f]*
* ARR{AY} describes an array giving md device and attributes like uuid=whatever
* e.g.
* ARRAY /dev/md0 uuid=whatever name=something
* Spaces separate words on each line. Quoting, with "" or '' protects them,
* but may not wrap over lines
*
*/
char DefaultConfFile[] = "/etc/mdctl.conf";
char *keywords[] = { "device", "array", NULL };
/*
* match_keyword returns an index into the keywords array, or -1 for no match
* case is ignored, and at least three characters must be given
*/
int match_keyword(char *word)
{
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;
}
/* conf_word gets one word from the conf file.
* if "allow_key", then accept words at the start of a line,
* otherwise stop when such a word is found.
* We assume that the file pointer is at the end of a word, so the
* next character is a space, or a newline. If not, it is the start of a line.
*/
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);
if (!word) abort();
while (wordfound==0) {
/* at the end of a word.. */
c = getc(file);
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;
}
c = getc(file);
}
}
if (c != EOF) ungetc(c, file);
}
word[len] = 0;
/* printf("word is <%s>\n", word); */
if (!wordfound) {
free(word);
word = NULL;
}
return word;
}
/*
* conf_line reads one logical line from the conffile.
* It skips comments and continues until it finds a line that starts
* with a non blank/comment. This character is pushed back for the next call
* A doubly linked list of words is returned.
* the first word will be a keyword. Other words will have had quotes removed.
*/
char *conf_line(FILE *file)
{
char *w;
char *list;
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);
free(w);
dl_add(list, w2);
}
/* printf("got a line\n");*/
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);
}
struct conf_dev {
struct conf_dev *next;
char *name;
} *cdevlist = NULL;
int devline(char *line)
{
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);
}
}
}
mddev_uuid_t uuidlist = NULL;
void arrayline(char *line)
{
char *w;
char *dev = NULL;
__u32 uuid[4];
int uidset=0;
mddev_uuid_t mu;
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);
}
}
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 = uuidlist;
uuidlist = mu;
}
}
int loaded = 0;
void load_conffile(char *conffile)
{
FILE *f;
char *line;
if (loaded) return;
if (conffile == NULL)
conffile = DefaultConfFile;
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);
}
free_line(line);
}
/* printf("got file\n"); */
}
mddev_uuid_t conf_get_uuids(char *conffile)
{
return NULL;
load_conffile(conffile);
return uuidlist;
}
mddev_dev_t conf_get_devs(char *conffile)
{
return NULL;
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);
}
load_conffile(conffile);
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;
/* printf("one dev is %s\n", t->devname);*/
}
globfree(&globbuf);
return dlist;
}

76
dlink.c Normal file
View File

@ -0,0 +1,76 @@
/* doubly linked lists */
/* This is free software. No strings attached. No copyright claimed */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "dlink.h"
void *dl_head()
{
void *h;
h = dl_alloc(0);
dl_next(h) = h;
dl_prev(h) = h;
return h;
}
void dl_free(void *v)
{
struct __dl_head *vv = v;
free(vv-1);
}
void dl_init(void *v)
{
dl_next(v) = v;
dl_prev(v) = v;
}
void dl_insert(void *head, void *val)
{
dl_next(val) = dl_next(head);
dl_prev(val) = head;
dl_next(dl_prev(val)) = val;
dl_prev(dl_next(val)) = val;
}
void dl_add(void *head, void *val)
{
dl_prev(val) = dl_prev(head);
dl_next(val) = head;
dl_next(dl_prev(val)) = val;
dl_prev(dl_next(val)) = val;
}
void dl_del(void *val)
{
if (dl_prev(val) == 0 || dl_next(val) == 0)
return;
dl_prev(dl_next(val)) = dl_prev(val);
dl_next(dl_prev(val)) = dl_next(val);
dl_prev(val) = dl_next(val) = 0;
}
char *dl_strndup(char *s, int l)
{
char *n;
if (s == NULL)
return NULL;
n = dl_newv(char, l+1);
if (n == NULL)
return NULL;
else
{
strncpy(n, s, l);
n[l] = 0;
return n;
}
}
char *dl_strdup(char *s)
{
return dl_strndup(s, (int)strlen(s));
}

25
dlink.h Normal file
View File

@ -0,0 +1,25 @@
/* doubley linked lists */
/* This is free software. No strings attached. No copyright claimed */
struct __dl_head
{
struct __dl_head * dh_prev;
struct __dl_head * dh_next;
};
#define dl_alloc(size) ((void*)(((char*)calloc(1,(size)+sizeof(struct __dl_head)))+sizeof(struct __dl_head)))
#define dl_new(t) ((t*)dl_alloc(sizeof(t)))
#define dl_newv(t,n) ((t*)dl_alloc(sizeof(t)*n))
#define dl_next(p) *((void**)&(((struct __dl_head*)(p))[-1].dh_next))
#define dl_prev(p) *((void**)&(((struct __dl_head*)(p))[-1].dh_prev))
void *dl_head();
char *dl_strdup(char *);
char *dl_strndup(char *, int);
void dl_insert(void*, void*);
void dl_add(void*, void*);
void dl_del(void*);
void dl_free(void*);
void dl_init(void*);

View File

@ -347,6 +347,7 @@ int main(int argc, char *argv[])
* 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");
@ -366,15 +367,16 @@ int main(int argc, char *argv[])
}
}
rv =0;
switch(mode) {
case '@':/* Management */
/* readonly, add/remove, readwrite, runstop */
if (readonly>1)
if (readonly>0)
rv = Manage_ro(mddev, mdfd, readonly);
if (!rv && subdevs)
rv = Manage_subdevs(mddev, mdfd, subdevs, subdev, devmodes);
if (!rv && readonly < 1)
if (!rv && readonly < 0)
rv = Manage_ro(mddev, mdfd, readonly);
if (!rv && runstop)
rv = Manage_runstop(mddev, mdfd, runstop);

View File

@ -78,6 +78,7 @@ extern char *map_num(mapping_t *map, int num);
extern int map_name(mapping_t *map, char *name);
extern mapping_t r5layout[], pers[];
extern char *map_dev(int major, int minor);
extern int Manage_ro(char *devname, int fd, int readonly);

12
testconfig Normal file
View File

@ -0,0 +1,12 @@
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

3
testconfig2 Normal file
View File

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

95
util.c
View File

@ -56,8 +56,10 @@ int parse_uuid(char *str, int uuid[4])
continue;
else return 0;
uuid[hit/4] <<= 4;
uuid[hit/4] += n;
if (hit<32) {
uuid[hit/8] <<= 4;
uuid[hit/8] += n;
}
hit++;
}
if (hit == 32)
@ -222,6 +224,31 @@ int load_super(int fd, mdp_super_t *super)
return 0;
}
int store_super(int fd, mdp_super_t *super)
{
long size;
long long offset;
if (ioctl(fd, BLKGETSIZE, &size))
return 1;
if (size < MD_RESERVED_SECTORS*2)
return 2;
offset = MD_NEW_SIZE_SECTORS(size);
offset *= 512;
if (lseek64(fd, offset, 0)< 0LL)
return 3;
if (write(fd, super, sizeof(*super)) != sizeof(*super))
return 4;
return 0;
}
int check_ext2(int fd, char *name)
{
@ -333,3 +360,67 @@ int map_name(mapping_t *map, char *name)
}
return -10;
}
/*
* convert a major/minor pair for a block device into a name in /dev, if possible.
* On the first call, walk /dev collecting name.
* Put them in a simple linked listfor now.
*/
struct devmap {
int major, minor;
char *name;
struct devmap *next;
} *devlist = NULL;
int devlist_ready = 0;
#define __USE_XOPEN_EXTENDED
#include <ftw.h>
int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
{
if ((stb->st_mode&S_IFMT)== S_IFBLK) {
char *n = strdup(name);
struct devmap *dm = malloc(sizeof(*dm));
if (dm) {
dm->major = MAJOR(stb->st_rdev);
dm->minor = MINOR(stb->st_rdev);
dm->name = n;
dm->next = devlist;
devlist = dm;
}
}
return 0;
}
char *map_dev(int major, int minor)
{
struct devmap *p;
if (!devlist_ready) {
nftw("/dev", add_dev, 10, FTW_PHYS);
devlist_ready=1;
}
for (p=devlist; p; p=p->next)
if (p->major == major &&
p->minor == minor)
return p->name;
return NULL;
}
int calc_sb_csum(mdp_super_t *super)
{
unsigned int oldcsum = super->sb_csum;
unsigned long long newcsum = 0; /* FIXME why does this make it work?? */
unsigned long csum;
int i;
unsigned int *superc = (int*) super;
super->sb_csum = 0;
for(i=0; i<MD_SB_BYTES/4; i++)
newcsum+= superc[i];
csum = (newcsum& 0xffffffff) + (newcsum>>32);
super->sb_csum = oldcsum;
return csum;
}