mdctl-0.6
This commit is contained in:
parent
5282684628
commit
cd29a5c835
76
Assemble.c
76
Assemble.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,7 +33,7 @@
|
|||
|
||||
int Assemble(char *mddev, int mdfd,
|
||||
mddev_ident_t ident, char *conffile,
|
||||
int subdevs, char **subdev,
|
||||
mddev_dev_t devlist,
|
||||
int readonly, int runstop,
|
||||
int verbose, int force)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
*
|
||||
* If !uuidset and scan, look in conf-file for uuid
|
||||
* If not found, give up
|
||||
* If !subdevs and scan and uuidset, get list of devs from conf-file
|
||||
* If !devlist and scan and uuidset, get list of devs from conf-file
|
||||
*
|
||||
* For each device:
|
||||
* Check superblock - discard if bad
|
||||
|
@ -94,7 +94,6 @@ int Assemble(char *mddev, int mdfd,
|
|||
int old_linux = 0;
|
||||
int vers;
|
||||
mdu_array_info_t array;
|
||||
mddev_dev_t devlist = NULL;
|
||||
mdp_super_t first_super, super;
|
||||
struct {
|
||||
char *devname;
|
||||
|
@ -108,8 +107,10 @@ int Assemble(char *mddev, int mdfd,
|
|||
int devcnt = 0, okcnt, sparecnt;
|
||||
int i;
|
||||
int most_recent = 0;
|
||||
int chosen_drive = -1;
|
||||
int chosen_drive;
|
||||
int change = 0;
|
||||
int inargv = 0;
|
||||
int start_partial_ok = force || devlist==NULL;
|
||||
|
||||
vers = md_get_version(mdfd);
|
||||
if (vers <= 0) {
|
||||
|
@ -139,7 +140,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
* there must be something in the identity
|
||||
*/
|
||||
|
||||
if (subdevs == 0 &&
|
||||
if (!devlist &&
|
||||
ident->uuid_set == 0 &&
|
||||
ident->super_minor < 0 &&
|
||||
ident->devices == NULL) {
|
||||
|
@ -147,8 +148,9 @@ int Assemble(char *mddev, int mdfd,
|
|||
mddev);
|
||||
return 1;
|
||||
}
|
||||
if (subdevs==0)
|
||||
if (devlist == NULL)
|
||||
devlist = conf_get_devs(conffile);
|
||||
else inargv = 1;
|
||||
|
||||
first_super.md_magic = 0;
|
||||
for (i=0; i<MD_SB_DISKS; i++)
|
||||
|
@ -158,23 +160,15 @@ int Assemble(char *mddev, int mdfd,
|
|||
fprintf(stderr, Name ": looking for devices for %s\n",
|
||||
mddev);
|
||||
|
||||
while (subdevs || devlist) {
|
||||
while ( devlist) {
|
||||
char *devname;
|
||||
int this_uuid[4];
|
||||
int dfd;
|
||||
struct stat stb;
|
||||
int inargv;
|
||||
int havesuper=0;
|
||||
|
||||
if (subdevs) {
|
||||
devname = *subdev++;
|
||||
subdevs--;
|
||||
inargv=1;
|
||||
} else {
|
||||
devname = devlist->devname;
|
||||
devlist = devlist->next;
|
||||
inargv=0;
|
||||
}
|
||||
devname = devlist->devname;
|
||||
devlist = devlist->next;
|
||||
|
||||
if (ident->devices &&
|
||||
!match_oneof(ident->devices, devname))
|
||||
|
@ -190,11 +184,11 @@ int Assemble(char *mddev, int mdfd,
|
|||
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",
|
||||
} else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
|
||||
fprintf(stderr, Name ": %s is not a block device.\n",
|
||||
devname);
|
||||
close(dfd);
|
||||
} if (load_super(dfd, &super)) {
|
||||
} else if (load_super(dfd, &super)) {
|
||||
if (inargv || verbose)
|
||||
fprintf( stderr, Name ": no RAID superblock on %s\n",
|
||||
devname);
|
||||
|
@ -219,14 +213,25 @@ int Assemble(char *mddev, int mdfd,
|
|||
devname);
|
||||
continue;
|
||||
}
|
||||
if (ident->level != -10 &&
|
||||
(!havesuper|| ident->level != super.level)) {
|
||||
if (inargv || verbose)
|
||||
fprintf(stderr, Name ": %s has wrong raid level.\n",
|
||||
devname);
|
||||
continue;
|
||||
}
|
||||
if (ident->raid_disks != -1 &&
|
||||
(!havesuper || ident->raid_disks!= super.raid_disks)) {
|
||||
if (inargv || verbose)
|
||||
fprintf(stderr, Name ": %s requires wrong number of drives.\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",
|
||||
|
@ -244,6 +249,9 @@ int Assemble(char *mddev, int mdfd,
|
|||
devname);
|
||||
continue;
|
||||
}
|
||||
if (verbose)
|
||||
fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n",
|
||||
devname, mddev, super.this_disk.raid_disk);
|
||||
devices[devcnt].devname = devname;
|
||||
devices[devcnt].major = MAJOR(stb.st_rdev);
|
||||
devices[devcnt].minor = MINOR(stb.st_rdev);
|
||||
|
@ -277,8 +285,9 @@ int Assemble(char *mddev, int mdfd,
|
|||
sparecnt=0;
|
||||
for (i=0; i< MD_SB_DISKS;i++) {
|
||||
int j = best[i];
|
||||
int event_margin = !force;
|
||||
if (j < 0) continue;
|
||||
if (devices[j].events+1 >=
|
||||
if (devices[j].events+event_margin >=
|
||||
devices[most_recent].events) {
|
||||
devices[j].uptodate = 1;
|
||||
if (i < first_super.raid_disks)
|
||||
|
@ -293,6 +302,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
* and add it.
|
||||
*/
|
||||
int fd;
|
||||
chosen_drive = -1;
|
||||
for (i=0; i<first_super.raid_disks; i++) {
|
||||
int j = best[i];
|
||||
if (j>=0 &&
|
||||
|
@ -344,6 +354,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
* If there are differences and --force is given, then update this chosen
|
||||
* superblock.
|
||||
*/
|
||||
chosen_drive = -1;
|
||||
for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) {
|
||||
int j = best[i];
|
||||
int fd;
|
||||
|
@ -368,6 +379,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
|
||||
for (i=0; i<MD_SB_DISKS; i++) {
|
||||
int j = best[i];
|
||||
int active_sync = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
|
||||
if (j<0)
|
||||
continue;
|
||||
if (!devices[j].uptodate)
|
||||
|
@ -379,12 +391,12 @@ int Assemble(char *mddev, int mdfd,
|
|||
super.disks[j].minor = devices[j].minor;
|
||||
}
|
||||
if (devices[j].uptodate &&
|
||||
(super.disks[i].state & (1 << MD_DISK_FAULTY))) {
|
||||
(super.disks[i].state != active_sync)) {
|
||||
if (force) {
|
||||
fprintf(stderr, Name ": "
|
||||
"clearing FAULT flag for device %d in %s for %s\n",
|
||||
"clearing FAULTY flag for device %d in %s for %s\n",
|
||||
j, mddev, devices[j].devname);
|
||||
super.disks[i].state &= ~(1<<MD_DISK_FAULTY);
|
||||
super.disks[i].state = active_sync;
|
||||
change |= 2;
|
||||
} else {
|
||||
fprintf(stderr, Name ": "
|
||||
|
@ -460,7 +472,9 @@ int Assemble(char *mddev, int mdfd,
|
|||
|
||||
if (runstop == 1 ||
|
||||
(runstop == 0 &&
|
||||
enough(first_super.level, first_super.raid_disks, okcnt))) {
|
||||
( first_super.raid_disks == okcnt
|
||||
|| start_partial_ok && 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 drive%s",
|
||||
mddev, okcnt, okcnt==1?"":"s");
|
||||
|
@ -478,7 +492,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
mddev, okcnt, okcnt==1?"":"s");
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it.\n",
|
||||
fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it (use --run to insist).\n",
|
||||
mddev, okcnt, okcnt==1?"":"s");
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -486,7 +500,7 @@ int Assemble(char *mddev, int mdfd,
|
|||
* been updated to point to the current locations of devices.
|
||||
* so we can just start the array
|
||||
*/
|
||||
int dev;
|
||||
unsigned long dev;
|
||||
dev = MKDEV(devices[chosen_drive].major,
|
||||
devices[chosen_drive].minor);
|
||||
if (ioctl(mdfd, START_ARRAY, dev)) {
|
||||
|
|
66
Build.c
66
Build.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -35,7 +35,7 @@
|
|||
|
||||
int Build(char *mddev, int mdfd, int chunk, int level,
|
||||
int raiddisks,
|
||||
int subdevs, char *subdev[])
|
||||
mddev_dev_t devlist)
|
||||
{
|
||||
/* Build a linear or raid0 arrays without superblocks
|
||||
* We cannot really do any checks, we just do it.
|
||||
|
@ -53,30 +53,34 @@ int Build(char *mddev, int mdfd, int chunk, int level,
|
|||
int i;
|
||||
int vers;
|
||||
struct stat stb;
|
||||
int subdevs = 0;
|
||||
mddev_dev_t dv;
|
||||
|
||||
/* scan all devices, make sure they really are block devices */
|
||||
for (dv = devlist; dv; dv=dv->next) {
|
||||
if (stat(dv->devname, &stb)) {
|
||||
fprintf(stderr, Name ": Cannot find %s: %s\n",
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
|
||||
fprintf(stderr, Name ": %s is not a block device.\n",
|
||||
dv->devname);
|
||||
return 1;
|
||||
}
|
||||
subdevs++;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (vers >= 9000) {
|
||||
mdu_array_info_t array;
|
||||
array.level = level;
|
||||
array.size = 0;
|
||||
|
@ -85,12 +89,14 @@ int Build(char *mddev, int mdfd, int chunk, int level,
|
|||
array.md_minor = 0;
|
||||
if (fstat(mdfd, &stb)==0)
|
||||
array.md_minor = MINOR(stb.st_rdev);
|
||||
array.not_persistent = 0;
|
||||
array.not_persistent = 1;
|
||||
array.state = 0; /* not clean, but no errors */
|
||||
array.active_disks = raiddisks;
|
||||
array.working_disks = raiddisks;
|
||||
array.spare_disks = 0;
|
||||
array.failed_disks = 0;
|
||||
if (chunk == 0)
|
||||
chunk = 64;
|
||||
array.chunk_size = chunk*1024;
|
||||
if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
|
||||
fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
|
||||
|
@ -99,18 +105,18 @@ int Build(char *mddev, int mdfd, int chunk, int level,
|
|||
}
|
||||
}
|
||||
/* now add the devices */
|
||||
for (i=0; i<subdevs; i++) {
|
||||
if (stat(subdev[i], &stb)) {
|
||||
for ((i=0), (dv = devlist) ; dv ; i++, dv=dv->next) {
|
||||
if (stat(dv->devname, &stb)) {
|
||||
fprintf(stderr, Name ": Wierd: %s has disappeared.\n",
|
||||
subdev[i]);
|
||||
dv->devname);
|
||||
goto abort;
|
||||
}
|
||||
if ((stb.st_rdev & S_IFMT)!= S_IFBLK) {
|
||||
if ((stb.st_mode & S_IFMT)!= S_IFBLK) {
|
||||
fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n",
|
||||
subdev[i]);
|
||||
dv->devname);
|
||||
goto abort;
|
||||
}
|
||||
if (vers> 90000) {
|
||||
if (vers>= 9000) {
|
||||
mdu_disk_info_t disk;
|
||||
disk.number = i;
|
||||
disk.raid_disk = i;
|
||||
|
@ -119,27 +125,27 @@ int Build(char *mddev, int mdfd, int chunk, int level,
|
|||
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));
|
||||
dv->devname, 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));
|
||||
dv->devname, strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* now to start it */
|
||||
if (vers > 90000) {
|
||||
if (vers >= 9000) {
|
||||
mdu_param_t param; /* not used by syscall */
|
||||
if (ioctl(mdfd, RUN_ARRAY, param)) {
|
||||
if (ioctl(mdfd, RUN_ARRAY, ¶m)) {
|
||||
fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
|
||||
strerror(errno));
|
||||
goto abort;
|
||||
}
|
||||
} else {
|
||||
int arg;
|
||||
unsigned long arg;
|
||||
arg=0;
|
||||
while (chunk > 4096) {
|
||||
arg++;
|
||||
|
@ -159,7 +165,7 @@ int Build(char *mddev, int mdfd, int chunk, int level,
|
|||
return 0;
|
||||
|
||||
abort:
|
||||
if (vers > 900000)
|
||||
if (vers >= 9000)
|
||||
ioctl(mdfd, STOP_ARRAY, 0);
|
||||
else
|
||||
ioctl(mdfd, STOP_MD, 0);
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
Changes Prior to 0.6 release
|
||||
|
||||
- Remove the limit on the number of device names that can be
|
||||
given on the command line.
|
||||
- Fix bug in --assemble --force where it would only update a
|
||||
single superblock.
|
||||
- Fix bogus printing of big numbers not being block devices
|
||||
when given names of devices that don't exist.
|
||||
- When --assemble --force, consider superblocks with an event
|
||||
count that is 1 behind as out-of-date. Normally they are
|
||||
considered up-to-date (as the kernel assumes this too).
|
||||
- When marking drives as not-failed in the superblock,
|
||||
we also mark them as ACTIVE and SYNC.
|
||||
- Don't start arrays for which not all drives are available unless:
|
||||
--scan which implies that all drives were found automatically
|
||||
--run which means the user knows what they want
|
||||
--force which means that we are fixing something broken
|
||||
- Make sure all device numbers passed as 3rd arg of ioctl
|
||||
are passed as unsigned lock, so that it works on SPARC
|
||||
- If HOT_ADD_DISK failes for -a, then only try ADD_NEW_DISK
|
||||
if we cannot read from the array, i.e. if the array is
|
||||
not started yet.
|
||||
- man page update
|
||||
- Taught Examine to handle --scan. It examines all devices listed
|
||||
on DEVICE lines in the config file.
|
||||
- Added --brief (-b) flag for Examine and Detail to print out
|
||||
and mdctl.conf compatible description with uuid=, level=,
|
||||
disks= and - for Examine - devices=
|
||||
--examine --brief collects all devices the make the one array and
|
||||
list them as one entry.
|
||||
- Added level= and disks= options to ARRAY lines in config files
|
||||
so --brief output could be used as-is.
|
||||
- Make parity style ({left,right}-{,a}symmetric) consistantly use -,
|
||||
never _.
|
||||
- Add "Array Size" to --detail output
|
||||
- Change "Size" to "Device Size" and exclude from Detail of arrays
|
||||
that do not have a consistent device size.
|
||||
- Add Human readable MiB or GiB value on size lines of Detail and Examine
|
||||
- --assemble --scan doesn't complain about active drives
|
||||
- require number of spares given in -x to be listed.
|
||||
- Made --build actually work.
|
||||
Changes Prior to 0.5 release
|
||||
|
||||
--assemble:
|
||||
spare drives are handled properly.
|
||||
|
||||
--force can be used to recover from 2-drive failures on RAID5
|
||||
If you belive that /dev/hda1 /dev/hdb1 /dev/hdc1 /dev/hdd1 should
|
||||
make a raid5 array, but it has experienced multiple failures and
|
||||
wont start, then
|
||||
|
||||
mdctl --assemble --force /dev/md0 /dev/hd[abcd]1
|
||||
|
||||
Should update the superblock on the newest failed drive and
|
||||
restart the array in degraded mode. You should then remove the
|
||||
remaining failed drive and re-add it (if you are happy that it
|
||||
might work).
|
||||
|
||||
Ofcourse whenever you have a 2-drive failure, you have a risk
|
||||
of corruption in data that hasn't be changed for a long time. So
|
||||
this doesn't give you your array back all nice and happy, but it
|
||||
does allow you to recover data that might not be corrupt.
|
||||
|
||||
More flexibility in identifying a RAID array in the mdctl.conf
|
||||
e.g.
|
||||
array /dev/md4 super-minor=4
|
||||
|
||||
assembles /dev/md4 from all devices found that have a raid
|
||||
superblock that says the minor number of the array is 4.
|
||||
If the blocks with the right minor number do not all have the
|
||||
same UUID, an error is flags and no assembly happens.
|
||||
|
||||
array /dev/md3 devices=/dev/hd[abc]2
|
||||
|
||||
Assembles /dev/md3 drom /dev/hda2 /dev/hdb2 and/dev/hdc2. All
|
||||
devices must exist and have raid superblock with the same uuid.
|
||||
|
||||
If two identity specifiers are used, only devices that match all
|
||||
of them are considered, so
|
||||
|
||||
array /dev/md2 devices=/dev/hd?2 super-minor=2
|
||||
|
||||
will assemble /dev/md2 using all /dev/hd?2 devices which have a
|
||||
raid superblock with minor number 2.
|
||||
|
||||
--create:
|
||||
When listing devices for --create, the word "missing" can be
|
||||
used to indicate that the respective slot does not have a
|
||||
working drive currently. This is similar to the "failed-disk"
|
||||
directive in mkraid/raidtab.
|
||||
e.g.
|
||||
mdctl --create --level=5 -raid-disks=4 --spare-disks=2
|
||||
/dev/md0 /dev/sda /dev/sdb missing /dev/sdc /dev/sdd /dev/sde
|
||||
|
||||
will create a raid5 array with the third slot empty, and two
|
||||
spares.
|
||||
|
||||
By default, raid5 arrays are created with the last slot empty
|
||||
and drive listed for the last slot added as a spare. If a
|
||||
"missing" slot is given, or if --force is given, then --create
|
||||
does exactly what you ask and doesn't try to be clever.
|
||||
|
||||
|
||||
--follow / --monitor:
|
||||
|
||||
This is a new mode. I couldn't stop my self from picking a name
|
||||
starting with F (as current modes start A,B,C,D,E) but I
|
||||
relented and provided an alternate name that is somewhat more
|
||||
meaningful.
|
||||
|
||||
In this mode, mdctl does not exit, but runs continuously and
|
||||
periodically polls all the md devices to see if they have had
|
||||
any interested state change.
|
||||
The changes that it currently notices are:
|
||||
Fail - an active disc fails
|
||||
FailSpare - a spare, that was presumably being build, fails
|
||||
ActiveSpare - a spare becomes active, presumably after a rebuild.
|
||||
|
||||
Options:
|
||||
--mail mailaddress - send Email on any Fail* event
|
||||
--program program - run the program on any event.
|
||||
Args are: eventname mddevice subdevice(if-known)
|
||||
--delay seconds - change from the default 60second pause
|
||||
between polls.
|
||||
|
||||
I plan to add functionality to this mode to allow sharing of
|
||||
spare drives. If an array is marks "spare-group=fred", and it
|
||||
has a failed drive and no spares, and if some other array is
|
||||
also "spare-group=fred" and it has no failed drives, but does
|
||||
have a spare drive that is big enough, the spare will be moved
|
||||
to the first array.
|
||||
|
||||
I also have the idea of adding a --grow mode which will re-organise
|
||||
the data on an N disk raid0/4/5 array to be on an N+M disk array.
|
||||
I have no concrete plans for this though.
|
||||
|
||||
I got rid of the "v" in the archive file name, and include the
|
||||
version number in the directory created by the archive.
|
||||
|
||||
There is now a man page and mdctl.spec (for rpm) thanks to
|
||||
Danilo Godec <danci@agenda.si>.
|
||||
|
||||
Ofcourse, the man page is now out of date and despite being based on
|
||||
the --help output, is not wholy correct. After I get --follow
|
||||
working properly, I plan to revise the various documentation and/or
|
||||
the code to make sure the two match.
|
||||
|
38
Create.c
38
Create.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,7 +33,7 @@
|
|||
|
||||
int Create(char *mddev, int mdfd,
|
||||
int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
|
||||
int subdevs, char *subdev[],
|
||||
int subdevs, mddev_dev_t devlist,
|
||||
int runstop, int verbose, int force)
|
||||
{
|
||||
/*
|
||||
|
@ -53,8 +53,10 @@ int Create(char *mddev, int mdfd,
|
|||
* RUN_ARRAY
|
||||
*/
|
||||
int minsize, maxsize;
|
||||
int maxdisc= -1, mindisc = -1;
|
||||
char *mindisc = NULL;
|
||||
char *maxdisc = NULL;
|
||||
int i;
|
||||
mddev_dev_t dv;
|
||||
int fail=0, warn=0;
|
||||
struct stat stb;
|
||||
int first_missing = MD_SB_DISKS*2;
|
||||
|
@ -93,7 +95,7 @@ int Create(char *mddev, int mdfd,
|
|||
fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
|
||||
return 1;
|
||||
}
|
||||
if (subdevs < raiddisks) {
|
||||
if (subdevs < raiddisks+sparedisks) {
|
||||
fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -121,11 +123,11 @@ 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];
|
||||
for (dv=devlist; dv; dv=dv->next) {
|
||||
char *dname = dv->devname;
|
||||
int dsize, freesize;
|
||||
int fd;
|
||||
if (strcasecmp(subdev[i], "missing")==0) {
|
||||
if (strcasecmp(dname, "missing")==0) {
|
||||
if (first_missing > i)
|
||||
first_missing = i;
|
||||
missing_disks ++;
|
||||
|
@ -165,12 +167,12 @@ int Create(char *mddev, int mdfd,
|
|||
close(fd);
|
||||
continue;
|
||||
}
|
||||
if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) {
|
||||
maxdisc = i;
|
||||
if (maxdisc == NULL || (maxdisc && freesize > maxsize)) {
|
||||
maxdisc = dname;
|
||||
maxsize = freesize;
|
||||
}
|
||||
if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) {
|
||||
mindisc = i;
|
||||
if (mindisc ==NULL || (mindisc && freesize < minsize)) {
|
||||
mindisc = dname;
|
||||
minsize = freesize;
|
||||
}
|
||||
warn |= check_ext2(fd, dname);
|
||||
|
@ -183,7 +185,7 @@ int Create(char *mddev, int mdfd,
|
|||
return 1;
|
||||
}
|
||||
if (size == 0) {
|
||||
if (mindisc == -1) {
|
||||
if (mindisc == NULL) {
|
||||
fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -193,7 +195,7 @@ int Create(char *mddev, int mdfd,
|
|||
}
|
||||
if ((maxsize-size)*100 > maxsize) {
|
||||
fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
|
||||
subdev[maxdisc], size);
|
||||
maxdisc, size);
|
||||
warn = 1;
|
||||
}
|
||||
|
||||
|
@ -267,7 +269,7 @@ int Create(char *mddev, int mdfd,
|
|||
return 1;
|
||||
}
|
||||
|
||||
for (i=0; i<subdevs; i++) {
|
||||
for (i=0, dv = devlist ; dv ; dv=dv->next, i++) {
|
||||
int fd;
|
||||
struct stat stb;
|
||||
mdu_disk_info_t disk;
|
||||
|
@ -280,15 +282,15 @@ int Create(char *mddev, int mdfd,
|
|||
disk.state = 6; /* active and in sync */
|
||||
else
|
||||
disk.state = 0;
|
||||
if (strcasecmp(subdev[i], "missing")==0) {
|
||||
if (strcasecmp(dv->devname, "missing")==0) {
|
||||
disk.major = 0;
|
||||
disk.minor = 0;
|
||||
disk.state = 1; /* faulty */
|
||||
} else {
|
||||
fd = open(subdev[i], O_RDONLY, 0);
|
||||
fd = open(dv->devname, O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
|
||||
subdev[i]);
|
||||
dv->devname);
|
||||
return 1;
|
||||
}
|
||||
fstat(fd, &stb);
|
||||
|
@ -298,7 +300,7 @@ int Create(char *mddev, int mdfd,
|
|||
}
|
||||
if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
|
||||
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
|
||||
subdev[i], strerror(errno));
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
149
Detail.c
149
Detail.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -31,7 +31,7 @@
|
|||
#include "md_p.h"
|
||||
#include "md_u.h"
|
||||
|
||||
int Detail(char *dev)
|
||||
int Detail(char *dev, int brief)
|
||||
{
|
||||
/*
|
||||
* Print out details for an md array by using
|
||||
|
@ -77,48 +77,59 @@ int Detail(char *dev)
|
|||
return 1;
|
||||
}
|
||||
/* Ok, we have some info to print... */
|
||||
printf("%s:\n", dev);
|
||||
printf(" Version : %02d.%02d.%02d\n",
|
||||
array.major_version, array.minor_version, array.patch_version);
|
||||
atime = array.ctime;
|
||||
printf(" Creation Time : %.24s\n", ctime(&atime));
|
||||
c = map_num(pers, array.level);
|
||||
printf(" Raid Level : %s\n", c?c:"-unknown-");
|
||||
printf(" Size : %d\n", array.size);
|
||||
printf(" Raid Disks : %d\n", array.raid_disks);
|
||||
printf(" Total Disks : %d\n", array.nr_disks);
|
||||
printf("Preferred Minor : %d\n", array.md_minor);
|
||||
printf(" Persistance : Superblock is %spersistant\n",
|
||||
array.not_persistent?"not ":"");
|
||||
printf("\n");
|
||||
atime = array.utime;
|
||||
printf(" Update Time : %.24s\n", ctime(&atime));
|
||||
printf(" State : %s, %serrors\n",
|
||||
(array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
|
||||
(array.state&(1<<MD_SB_ERRORS))?"":"no-");
|
||||
printf(" Active Drives : %d\n", array.active_disks);
|
||||
printf(" Working Drives : %d\n", array.working_disks);
|
||||
printf(" Failed Drives : %d\n", array.failed_disks);
|
||||
printf(" Spare Drives : %d\n", array.spare_disks);
|
||||
printf("\n");
|
||||
if (array.level == 5) {
|
||||
c = map_num(r5layout, array.layout);
|
||||
printf(" Layout : %s\n", c?c:"-unknown-");
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (brief)
|
||||
printf("ARRAY %s level=%s disks=%d", dev, c?c:"-unknown-",array.raid_disks );
|
||||
else {
|
||||
int array_size;
|
||||
if (ioctl(fd, BLKGETSIZE, &array_size))
|
||||
array_size = 0;
|
||||
else array_size>>= 1;
|
||||
printf("%s:\n", dev);
|
||||
printf(" Version : %02d.%02d.%02d\n",
|
||||
array.major_version, array.minor_version, array.patch_version);
|
||||
atime = array.ctime;
|
||||
printf(" Creation Time : %.24s\n", ctime(&atime));
|
||||
printf(" Raid Level : %s\n", c?c:"-unknown-");
|
||||
if (array_size)
|
||||
printf(" Array Size : %d%s\n", array_size, human_size(array_size));
|
||||
if (array.level >= 1)
|
||||
printf(" Device Size : %d%s\n", array.size, human_size(array.size));
|
||||
printf(" Raid Disks : %d\n", array.raid_disks);
|
||||
printf(" Total Disks : %d\n", array.nr_disks);
|
||||
printf("Preferred Minor : %d\n", array.md_minor);
|
||||
printf(" Persistance : Superblock is %spersistant\n",
|
||||
array.not_persistent?"not ":"");
|
||||
printf("\n");
|
||||
atime = array.utime;
|
||||
printf(" Update Time : %.24s\n", ctime(&atime));
|
||||
printf(" State : %s, %serrors\n",
|
||||
(array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
|
||||
(array.state&(1<<MD_SB_ERRORS))?"":"no-");
|
||||
printf(" Active Drives : %d\n", array.active_disks);
|
||||
printf(" Working Drives : %d\n", array.working_disks);
|
||||
printf(" Failed Drives : %d\n", array.failed_disks);
|
||||
printf(" Spare Drives : %d\n", array.spare_disks);
|
||||
printf("\n");
|
||||
if (array.level == 5) {
|
||||
c = map_num(r5layout, array.layout);
|
||||
printf(" Layout : %s\n", c?c:"-unknown-");
|
||||
}
|
||||
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");
|
||||
printf("\n");
|
||||
printf(" Number Major Minor RaidDisk State\n");
|
||||
}
|
||||
for (d= 0; d<array.raid_disks+array.spare_disks; d++) {
|
||||
mdu_disk_info_t disk;
|
||||
char *dv;
|
||||
|
@ -128,34 +139,40 @@ int Detail(char *dev)
|
|||
d, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
printf(" %5d %5d %5d %5d ",
|
||||
disk.number, disk.major, disk.minor, disk.raid_disk);
|
||||
if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty");
|
||||
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;
|
||||
}
|
||||
if (!brief) {
|
||||
printf(" %5d %5d %5d %5d ",
|
||||
disk.number, disk.major, disk.minor, disk.raid_disk);
|
||||
if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty");
|
||||
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");
|
||||
}
|
||||
printf("\n");
|
||||
if ((dv=map_dev(disk.major, disk.minor))) {
|
||||
if (!brief) 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;
|
||||
}
|
||||
}
|
||||
if (!brief) printf("\n");
|
||||
}
|
||||
if (have_super) {
|
||||
if (brief) printf(" UUID=");
|
||||
else printf(" UUID : ");
|
||||
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);
|
||||
printf("%08x:%08x:%08x:%08x", super.set_uuid0, super.set_uuid1,
|
||||
super.set_uuid2, super.set_uuid3);
|
||||
else
|
||||
printf("%08x", super.set_uuid0);
|
||||
if (!brief) printf("\n");
|
||||
}
|
||||
if (brief) printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
273
Examine.c
273
Examine.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,13 +28,14 @@
|
|||
*/
|
||||
|
||||
#include "mdctl.h"
|
||||
#include "dlink.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)
|
||||
int Examine(mddev_dev_t devlist, int brief, char *conffile)
|
||||
{
|
||||
|
||||
/* Read the raid superblock from a device and
|
||||
|
@ -49,120 +50,186 @@ int Examine(char *dev)
|
|||
*
|
||||
* utime, state etc
|
||||
*
|
||||
* If (brief) gather devices for same array and just print a mdctl.conf line including devices=
|
||||
* if devlist==NULL, use conf_get_devs(
|
||||
*/
|
||||
int fd = open(dev, O_RDONLY);
|
||||
int fd;
|
||||
time_t atime;
|
||||
mdp_super_t super;
|
||||
int d;
|
||||
char *c;
|
||||
int rv;
|
||||
int rv = 0;
|
||||
int err;
|
||||
int scan= 0;
|
||||
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,Name ": cannot open %s: %s\n",
|
||||
dev, strerror(errno));
|
||||
struct array {
|
||||
mdp_super_t super;
|
||||
void *devs;
|
||||
struct array *next;
|
||||
} *arrays = NULL;
|
||||
|
||||
if (devlist == NULL) {
|
||||
devlist = conf_get_devs(conffile);
|
||||
scan=1;
|
||||
}
|
||||
if (devlist == NULL) {
|
||||
fprintf(stderr, Name ": No devices listed in %s\n", conffile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rv = load_super(fd, &super);
|
||||
close(fd);
|
||||
switch(rv) {
|
||||
case 1:
|
||||
fprintf(stderr, Name ": cannot find device size for %s: %s\n",
|
||||
dev, strerror(errno));
|
||||
return 1;
|
||||
case 2:
|
||||
for (; devlist ; devlist=devlist->next) {
|
||||
fd = open(devlist->devname, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (!scan)
|
||||
fprintf(stderr,Name ": cannot open %s: %s\n",
|
||||
devlist->devname, strerror(errno));
|
||||
err = 1;
|
||||
}
|
||||
else {
|
||||
err = load_super(fd, &super);
|
||||
close(fd);
|
||||
}
|
||||
if (err && (brief||scan))
|
||||
continue;
|
||||
if (err) rv =1;
|
||||
switch(err) {
|
||||
case 1:
|
||||
fprintf(stderr, Name ": cannot find device size for %s: %s\n",
|
||||
devlist->devname, strerror(errno));
|
||||
continue;
|
||||
case 2:
|
||||
/* fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n",
|
||||
dev, size);
|
||||
devlist->devname, size);
|
||||
*/
|
||||
fprintf(stderr, Name ": %s is too small for md\n",
|
||||
dev);
|
||||
return 1;
|
||||
case 3:
|
||||
fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
|
||||
dev, strerror(errno));
|
||||
return 1;
|
||||
case 4:
|
||||
fprintf(stderr, Name ": Cannot read superblock on %s\n",
|
||||
dev);
|
||||
return 1;
|
||||
case 5:
|
||||
fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
|
||||
dev, MD_SB_MAGIC, super.md_magic);
|
||||
return 1;
|
||||
case 6:
|
||||
fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
|
||||
dev, super.major_version);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, Name ": %s is too small for md\n",
|
||||
devlist->devname);
|
||||
continue;
|
||||
case 3:
|
||||
fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
|
||||
devlist->devname, strerror(errno));
|
||||
continue;
|
||||
case 4:
|
||||
fprintf(stderr, Name ": Cannot read superblock on %s\n",
|
||||
devlist->devname);
|
||||
continue;
|
||||
case 5:
|
||||
fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
|
||||
devlist->devname, MD_SB_MAGIC, super.md_magic);
|
||||
continue;
|
||||
case 6:
|
||||
fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
|
||||
devlist->devname, super.major_version);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ok, its good enough to try, though the checksum could be wrong */
|
||||
printf("%s:\n",dev);
|
||||
printf(" Magic : %08x\n", super.md_magic);
|
||||
printf(" Version : %02d.%02d.%02d\n", super.major_version, super.minor_version,
|
||||
super.patch_version);
|
||||
if (super.minor_version >= 90)
|
||||
printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1,
|
||||
super.set_uuid2, super.set_uuid3);
|
||||
else
|
||||
printf(" UUID : %08x\n", super.set_uuid0);
|
||||
/* Ok, its good enough to try, though the checksum could be wrong */
|
||||
if (brief) {
|
||||
struct array *ap;
|
||||
char *d;
|
||||
for (ap=arrays; ap; ap=ap->next) {
|
||||
if (compare_super(&ap->super, &super)==0)
|
||||
break;
|
||||
}
|
||||
if (!ap) {
|
||||
ap = malloc(sizeof(*ap));
|
||||
ap->super = super;
|
||||
ap->devs = dl_head();
|
||||
ap->next = arrays;
|
||||
arrays = ap;
|
||||
}
|
||||
d = dl_strdup(devlist->devname);
|
||||
dl_add(ap->devs, d);
|
||||
} else {
|
||||
printf("%s:\n",devlist->devname);
|
||||
printf(" Magic : %08x\n", super.md_magic);
|
||||
printf(" Version : %02d.%02d.%02d\n", super.major_version, super.minor_version,
|
||||
super.patch_version);
|
||||
if (super.minor_version >= 90)
|
||||
printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1,
|
||||
super.set_uuid2, super.set_uuid3);
|
||||
else
|
||||
printf(" UUID : %08x\n", super.set_uuid0);
|
||||
|
||||
atime = super.ctime;
|
||||
printf(" Creation Time : %.24s\n", ctime(&atime));
|
||||
c=map_num(pers, super.level);
|
||||
printf(" Raid Level : %s\n", c?c:"-unknown-");
|
||||
printf(" Size : %d\n", super.size);
|
||||
printf(" Raid Disks : %d\n", super.raid_disks);
|
||||
printf(" Total Disks : %d\n", super.nr_disks);
|
||||
printf("Preferred Minor : %d\n", super.md_minor);
|
||||
printf("\n");
|
||||
atime = super.utime;
|
||||
printf(" Update Time : %.24s\n", ctime(&atime));
|
||||
printf(" State : %s, %serrors\n",
|
||||
(super.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
|
||||
(super.state&(1<<MD_SB_ERRORS))?"":"no-");
|
||||
printf(" Active Drives : %d\n", super.active_disks);
|
||||
printf(" Working Drives : %d\n", super.working_disks);
|
||||
printf(" Failed Drives : %d\n", super.failed_disks);
|
||||
printf(" Spare Drives : %d\n", super.spare_disks);
|
||||
if (calc_sb_csum(&super) == super.sb_csum)
|
||||
printf(" Checksum : %x - correct\n", super.sb_csum);
|
||||
else
|
||||
printf(" Checksum : %x - expected %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-");
|
||||
atime = super.ctime;
|
||||
printf(" Creation Time : %.24s\n", ctime(&atime));
|
||||
c=map_num(pers, super.level);
|
||||
printf(" Raid Level : %s\n", c?c:"-unknown-");
|
||||
printf(" Device Size : %d%s\n", super.size, human_size(super.size));
|
||||
printf(" Raid Disks : %d\n", super.raid_disks);
|
||||
printf(" Total Disks : %d\n", super.nr_disks);
|
||||
printf("Preferred Minor : %d\n", super.md_minor);
|
||||
printf("\n");
|
||||
atime = super.utime;
|
||||
printf(" Update Time : %.24s\n", ctime(&atime));
|
||||
printf(" State : %s, %serrors\n",
|
||||
(super.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
|
||||
(super.state&(1<<MD_SB_ERRORS))?"":"no-");
|
||||
printf(" Active Drives : %d\n", super.active_disks);
|
||||
printf(" Working Drives : %d\n", super.working_disks);
|
||||
printf(" Failed Drives : %d\n", super.failed_disks);
|
||||
printf(" Spare Drives : %d\n", super.spare_disks);
|
||||
if (calc_sb_csum(&super) == super.sb_csum)
|
||||
printf(" Checksum : %x - correct\n", super.sb_csum);
|
||||
else
|
||||
printf(" Checksum : %x - expected %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-");
|
||||
}
|
||||
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.raid_disks+super.spare_disks); d++) {
|
||||
mdp_disk_t *dp;
|
||||
char *dv;
|
||||
char nb[5];
|
||||
if (d>=0) dp = &super.disks[d];
|
||||
else dp = &super.this_disk;
|
||||
sprintf(nb, "%4d", d);
|
||||
printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb,
|
||||
dp->number, dp->major, dp->minor, dp->raid_disk);
|
||||
if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty");
|
||||
if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
|
||||
if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
|
||||
if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
|
||||
if ((dv=map_dev(dp->major, dp->minor)))
|
||||
printf(" %s", dv);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (brief) {
|
||||
struct array *ap;
|
||||
for (ap=arrays; ap; ap=ap->next) {
|
||||
char sep='=';
|
||||
char *c=map_num(pers, ap->super.level);
|
||||
char *d;
|
||||
printf("ARRAY /dev/md%d level=%s disks=%d UUID=",
|
||||
ap->super.md_minor, c?c:"-unknown-", ap->super.raid_disks);
|
||||
if (ap->super.minor_version >= 90)
|
||||
printf("%08x:%08x:%08x:%08x", ap->super.set_uuid0, ap->super.set_uuid1,
|
||||
ap->super.set_uuid2, ap->super.set_uuid3);
|
||||
else
|
||||
printf("%08x", ap->super.set_uuid0);
|
||||
printf("\n devices");
|
||||
for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) {
|
||||
printf("%c%s", sep, d);
|
||||
sep=',';
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf(" Number Major Minor RaidDisk State\n");
|
||||
for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) {
|
||||
mdp_disk_t *dp;
|
||||
char *dv;
|
||||
char nb[5];
|
||||
if (d>=0) dp = &super.disks[d];
|
||||
else dp = &super.this_disk;
|
||||
sprintf(nb, "%4d", d);
|
||||
printf("%4s %5d %5d %5d %5d ", d < 0 ? "this" : nb,
|
||||
dp->number, dp->major, dp->minor, dp->raid_disk);
|
||||
if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty");
|
||||
if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
|
||||
if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
|
||||
if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
|
||||
if ((dv=map_dev(dp->major, dp->minor)))
|
||||
printf(" %s", dv);
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
|
17
Makefile
17
Makefile
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
#
|
||||
# Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
# Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -27,18 +27,29 @@
|
|||
# Australia
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall,error,strict-prototypes -ggdb
|
||||
|
||||
INSTALL = /usr/bin/install
|
||||
DESTDIR = /sbin
|
||||
|
||||
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
|
||||
|
||||
all : mdctl mdctl.man
|
||||
|
||||
mdctl : $(OBJS)
|
||||
$(CC) -o mdctl $^
|
||||
|
||||
mdctl.man : mdctl.8
|
||||
nroff -man mdctl.8 > mdctl.man
|
||||
|
||||
$(OBJS) : mdctl.h
|
||||
|
||||
install : mdctl
|
||||
$(INSTALL) -m 755 mdctl $(DESTDIR)/sbin
|
||||
|
||||
clean :
|
||||
rm -f mdctl $(OBJS) core
|
||||
rm -f mdctl $(OBJS) core mdctl.man
|
||||
|
||||
dist : clean
|
||||
./makedist
|
||||
|
|
50
Manage.c
50
Manage.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -116,8 +116,8 @@ int Manage_runstop(char *devname, int fd, int runstop)
|
|||
}
|
||||
|
||||
int Manage_subdevs(char *devname, int fd,
|
||||
int devcnt, char *devnames[], int devmodes[])
|
||||
{
|
||||
mddev_dev_t devlist)
|
||||
{
|
||||
/* do something to each dev.
|
||||
* devmode can be
|
||||
* 'a' - add the device
|
||||
|
@ -128,37 +128,49 @@ int Manage_subdevs(char *devname, int fd,
|
|||
*/
|
||||
mdu_array_info_t array;
|
||||
mdu_disk_info_t disc;
|
||||
mddev_dev_t dv;
|
||||
struct stat stb;
|
||||
int i,j;
|
||||
int save_errno;
|
||||
static buf[4096];
|
||||
|
||||
if (ioctl(fd, GET_ARRAY_INFO, &array)) {
|
||||
fprintf(stderr, Name ": cannot get array info for %s\n",
|
||||
devname);
|
||||
return 1;
|
||||
}
|
||||
for (i=0 ; i<devcnt; i++) {
|
||||
if (stat(devnames[i], &stb)) {
|
||||
for (dv = devlist ; dv; dv=dv->next) {
|
||||
if (stat(dv->devname, &stb)) {
|
||||
fprintf(stderr, Name ": cannot find %s: %s\n",
|
||||
devnames[i], strerror(errno));
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
|
||||
fprintf(stderr, Name ": %s is not a block device.\n",
|
||||
devnames[i]);
|
||||
dv->devname);
|
||||
return 1;
|
||||
}
|
||||
switch(devmodes[i]){
|
||||
switch(dv->disposition){
|
||||
default:
|
||||
fprintf(stderr, Name ": internal error - devmode[%d]=%d\n",
|
||||
i, devmodes[i]);
|
||||
i, dv->disposition);
|
||||
return 1;
|
||||
case 'a':
|
||||
/* add the device - hot or cold */
|
||||
if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) {
|
||||
if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) {
|
||||
fprintf(stderr, Name ": hot added %s\n",
|
||||
devnames[i]);
|
||||
dv->devname);
|
||||
continue;
|
||||
}
|
||||
save_errno = errno;
|
||||
if (read(fd, buf, sizeof(buf)) > 0) {
|
||||
/* array is active, so don't try to add.
|
||||
* i.e. something is wrong
|
||||
*/
|
||||
fprintf(stderr, Name ": hot add failed for %s: %s\n",
|
||||
dv->devname, strerror(save_errno));
|
||||
return 1;
|
||||
}
|
||||
/* try ADD_NEW_DISK.
|
||||
* we might be creating, we might be assembling,
|
||||
* it is hard to tell.
|
||||
|
@ -180,32 +192,32 @@ int Manage_subdevs(char *devname, int fd,
|
|||
disc.minor = MINOR(stb.st_rdev);
|
||||
if (ioctl(fd,ADD_NEW_DISK, &disc)) {
|
||||
fprintf(stderr, Name ": add new disk failed for %s: %s\n",
|
||||
devnames[i], strerror(errno));
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, Name ": added %s\n", devnames[i]);
|
||||
fprintf(stderr, Name ": added %s\n", dv->devname);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
/* hot remove */
|
||||
/* FIXME check that it is a current member */
|
||||
if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) {
|
||||
if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) {
|
||||
fprintf(stderr, Name ": hot remove failed for %s: %s\n",
|
||||
devnames[i], strerror(errno));
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, Name ": hot removed %s\n", devnames[i]);
|
||||
fprintf(stderr, Name ": hot removed %s\n", dv->devname);
|
||||
break;
|
||||
|
||||
case 'f': /* set faulty */
|
||||
/* FIXME check current member */
|
||||
if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) {
|
||||
if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
|
||||
fprintf(stderr, Name ": set disk faulty failed for %s: %s\n",
|
||||
devnames[i], strerror(errno));
|
||||
dv->devname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, Name ": set %s faulty in %s\n",
|
||||
devnames[i], devname);
|
||||
dv->devname, devname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
20
Monitor.c
20
Monitor.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
|
||||
|
||||
int Monitor(int num_devs, char *devlist[],
|
||||
int Monitor(mddev_dev_t devlist,
|
||||
char *mailaddr, char *alert_cmd,
|
||||
int period,
|
||||
char *config)
|
||||
|
@ -75,10 +75,12 @@ int Monitor(int num_devs, char *devlist[],
|
|||
int finished = 0;
|
||||
while (! finished) {
|
||||
mddev_ident_t mdlist = NULL;
|
||||
mddev_dev_t dv;
|
||||
int dnum=0;
|
||||
if (num_devs == 0)
|
||||
if (devlist== NULL)
|
||||
mdlist = conf_get_ident(config, NULL);
|
||||
while (dnum < num_devs || mdlist) {
|
||||
dv = devlist;
|
||||
while (dv || mdlist) {
|
||||
mddev_ident_t mdident;
|
||||
struct state *st;
|
||||
mdu_array_info_t array;
|
||||
|
@ -87,9 +89,10 @@ int Monitor(int num_devs, char *devlist[],
|
|||
char *event = NULL;
|
||||
int i;
|
||||
char *event_disc = NULL;
|
||||
if (num_devs) {
|
||||
dev = devlist[dnum++];
|
||||
if (dv) {
|
||||
dev = dv->devname;
|
||||
mdident = conf_get_ident(config, dev);
|
||||
dv = dv->next;
|
||||
} else {
|
||||
mdident = mdlist;
|
||||
dev = mdident->devname;
|
||||
|
@ -171,6 +174,11 @@ int Monitor(int num_devs, char *devlist[],
|
|||
|
||||
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd)
|
||||
{
|
||||
if (!cmd && !mailaddr) {
|
||||
time_t now = time(0);
|
||||
|
||||
printf("%0.15s: %s on %s %s\n", ctime(&now)+4, event, dev, disc?disc:"unknown device");
|
||||
}
|
||||
if (cmd) {
|
||||
int pid = fork();
|
||||
switch(pid) {
|
||||
|
|
22
ReadMe.c
22
ReadMe.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "mdctl.h"
|
||||
|
||||
char Version[] = Name " - v0.5 - 23 August 2001\n";
|
||||
char Version[] = Name " - v0.6 - 7 March 2002\n";
|
||||
/*
|
||||
* File: ReadMe.c
|
||||
*
|
||||
|
@ -78,7 +78,7 @@ char Version[] = Name " - v0.5 - 23 August 2001\n";
|
|||
* command, subsequent Manage commands can finish the job.
|
||||
*/
|
||||
|
||||
char short_options[]="-ABCDEFhVvc:l:p:m:n:x:u:c:d:z:sarfRSow";
|
||||
char short_options[]="-ABCDEFhVvbc:l:p:m:n:x:u:c:d:z:sarfRSow";
|
||||
struct option long_options[] = {
|
||||
{"manage", 0, 0, '@'},
|
||||
{"assemble", 0, 0, 'A'},
|
||||
|
@ -122,6 +122,9 @@ struct option long_options[] = {
|
|||
{"readonly", 0, 0, 'o'},
|
||||
{"readwrite", 0, 0, 'w'},
|
||||
|
||||
/* For Detail/Examine */
|
||||
{"brief", 0, 0, 'b'},
|
||||
|
||||
/* For Follow/monitor */
|
||||
{"mail", 1, 0, 'm'},
|
||||
{"program", 1, 0, 'p'},
|
||||
|
@ -174,7 +177,7 @@ char Help[] =
|
|||
" --paritiy= -p : raid5 parity algorith: {left,right}-{,a}symmetric\n"
|
||||
" --layout= : same as --parity\n"
|
||||
" --raid-disks= -n : number of active devices in array\n"
|
||||
" --spare-disks= -x : number of spares (eXtras) to allow space for\n"
|
||||
" --spare-disks= -x : number of spares (eXtras) devices in initial array\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"
|
||||
|
@ -188,6 +191,9 @@ char Help[] =
|
|||
" --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 detail or examine:\n"
|
||||
" --brief -b : Just print device name and UUID\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"
|
||||
|
@ -306,10 +312,10 @@ char Help_assemble[] =
|
|||
/* name/number mappings */
|
||||
|
||||
mapping_t r5layout[] = {
|
||||
{ "left_asymmetric", 0},
|
||||
{ "right_asymmetric", 1},
|
||||
{ "left_symmetric", 2},
|
||||
{ "right_symmetric", 3},
|
||||
{ "left-asymmetric", 0},
|
||||
{ "right-asymmetric", 1},
|
||||
{ "left-symmetric", 2},
|
||||
{ "right-symmetric", 3},
|
||||
|
||||
{ "default", 2},
|
||||
{ "la", 0},
|
||||
|
|
38
TODO
38
TODO
|
@ -1,21 +1,47 @@
|
|||
|
||||
|
||||
?? Allow -S /dev/md? - current complains subsequent not a/d/r
|
||||
|
||||
* write proc.c to parse /proc/mdstat file, and maybe /proc/partitions too.
|
||||
Build list of arrays: name, rebuild-percent
|
||||
|
||||
* --detail --scan to read mdctl.conf, and then iterate over these,
|
||||
but assume --brief. --verbose can override
|
||||
check each subdevice to see if it is in conf_get_devs.
|
||||
Warn if not.
|
||||
|
||||
* Support multipath ... maybe...
|
||||
|
||||
* --follow to syslog
|
||||
|
||||
* --follow to move spares around
|
||||
|
||||
* --follow to notice other events:
|
||||
rebuild started
|
||||
spare activated
|
||||
spare removed
|
||||
spare added
|
||||
|
||||
------------------------------------
|
||||
- --examine --scan scans all drives and build an mdctl.conf file DONE
|
||||
|
||||
- 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
|
||||
- --verbose and --force flags.
|
||||
- --verbose and --force flags. DONE
|
||||
|
||||
- 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...
|
||||
one missing, one spare, insync DONE (--force)
|
||||
- and for raid1 - some failed drives... (missing)
|
||||
|
||||
- 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
|
||||
- --detail --brief to give a config file line DONE
|
||||
- parse config file. DONE
|
||||
- test...
|
||||
|
||||
|
@ -23,7 +49,7 @@
|
|||
then try to assemble that device first.
|
||||
|
||||
|
||||
- mdctl -S /dev/md0 /dev/md1 gives internal error
|
||||
- mdctl -S /dev/md0 /dev/md1 gives internal error FIXED
|
||||
|
||||
- mdctl --detail --scan print summary of what it can find?
|
||||
|
||||
|
@ -74,4 +100,4 @@ New mode: --Monitor (or --Follow)
|
|||
rebuild started
|
||||
spare activated
|
||||
spare removed
|
||||
spare added
|
||||
spare added
|
||||
|
|
10
config.c
10
config.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -229,6 +229,8 @@ void arrayline(char *line)
|
|||
|
||||
mis.uuid_set = 0;
|
||||
mis.super_minor = -1;
|
||||
mis.level = -10;
|
||||
mis.raid_disks = -1;
|
||||
mis.devices = NULL;
|
||||
mis.devname = NULL;
|
||||
|
||||
|
@ -273,6 +275,12 @@ void arrayline(char *line)
|
|||
w);
|
||||
else
|
||||
mis.spare_group = strdup(w+12);
|
||||
} else if (strncasecmp(w, "level=", 6) == 0 ) {
|
||||
/* this is mainly for compatability with --brief output */
|
||||
mis.level = map_name(pers, w+6);
|
||||
} else if (strncasecmp(w, "disks=", 6) == 0 ) {
|
||||
/* again, for compat */
|
||||
mis.raid_disks = atoi(w+6);
|
||||
} else {
|
||||
fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
|
||||
w);
|
||||
|
|
2
makedist
2
makedist
|
@ -16,6 +16,6 @@ then
|
|||
exit 1
|
||||
fi
|
||||
trap "rm $target/$base; exit" 1 2 3
|
||||
( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude=RCS mdctl-$version ; rm mdctl-$version ) > $target/$base
|
||||
( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude mdctl --exclude=RCS mdctl-$version ; rm mdctl-$version ) > $target/$base
|
||||
chmod a+r $target/$base
|
||||
ls -l $target/$base
|
||||
|
|
674
mdctl.8
674
mdctl.8
|
@ -1,185 +1,379 @@
|
|||
.\" -*- nroff -*-
|
||||
.TH mdctl 8
|
||||
.SH NAME
|
||||
mdctl \- a single program that can be used to control Linux md devices
|
||||
mdctl \- manage MD devices
|
||||
.I aka
|
||||
Linux Software Raid.
|
||||
|
||||
.SH SYNOPSIS
|
||||
|
||||
.BI mdctl
|
||||
[mode] <raiddevice> [options]
|
||||
.BI mdctl " [mode] <raiddevice> [options] <subdevices>"
|
||||
|
||||
.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.
|
||||
real block devices. This allows multiple devices (typically disk
|
||||
drives or partitions there-of) to be combined into a single device to
|
||||
hold (for example) a single filesystem.
|
||||
Some RAID levels included redundancy and so can survive some degree of
|
||||
device failure.
|
||||
|
||||
If you're using the
|
||||
.B /proc
|
||||
filesystem,
|
||||
.B /proc/mdstat
|
||||
gives you informations about md devices status.
|
||||
Linux Software RAID devices are implemented through the md (Multiple Devices) device driver.
|
||||
|
||||
Currently, Linux supports linear md devices, RAID0 (striping), RAID1
|
||||
(mirrroring), RAID4 and RAID5. For information on the various levels of
|
||||
RAID, check out:
|
||||
Currently, Linux supports
|
||||
.B LINEAR
|
||||
md devices,
|
||||
.B RAID0
|
||||
(striping),
|
||||
.B RAID1
|
||||
(mirroring),
|
||||
.B RAID4
|
||||
and
|
||||
.B RAID5.
|
||||
|
||||
http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
|
||||
Recent kernels (2002) also support a mode known as
|
||||
.BR MULTIPATH .
|
||||
.B mdctl
|
||||
does not support MULTIPATH as yet.
|
||||
|
||||
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.
|
||||
.B mdctl
|
||||
is a program that can be used to create and manage MD devices. As
|
||||
such it provides a similar set of functionality to the
|
||||
.B raidtools
|
||||
packages.
|
||||
The key differences between
|
||||
.B mdctl
|
||||
and
|
||||
.B raidtools
|
||||
are:
|
||||
.IP \(bu 4
|
||||
.B mdctl
|
||||
is a single program and not a collection of programs.
|
||||
.IP \(bu 4
|
||||
.B mdctl
|
||||
can perform (almost) all of its functions without having a
|
||||
configuration file. Also mdctl helps with management of the configuration
|
||||
file.
|
||||
.IP \(bu 4
|
||||
.B mdctl
|
||||
can provide information about your arrays (through Detail and Examine)
|
||||
that
|
||||
.B raidtools
|
||||
cannot.
|
||||
.IP \(bu 4
|
||||
.B raidtools
|
||||
can manage MULTIPATH devices which
|
||||
.B mdctl
|
||||
cannot yet manage.
|
||||
|
||||
.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
|
||||
mdctl has 7 major modes of operation:
|
||||
.TP
|
||||
.B Assemble
|
||||
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.
|
||||
checks that the components
|
||||
do form a bona fide array, and can, on request, fiddle superblock
|
||||
information so as to assemble a faulty array.
|
||||
|
||||
.IP "\fBBuild\fP"
|
||||
This is for building legacy arrays without superblocks.
|
||||
.TP
|
||||
.B Build
|
||||
Build a legacy array without per-device superblocks.
|
||||
|
||||
.IP "\fBManage\fP"
|
||||
.TP
|
||||
.B Create
|
||||
Create a new array with per-device superblocks.
|
||||
'''It can progress
|
||||
'''in several step create-add-add-run or it can all happen with one command.
|
||||
|
||||
.TP
|
||||
.B Detail
|
||||
Display the details of a given md device. Details include the RAID
|
||||
level, the number of devices, which ones are faulty (if any), and the
|
||||
array UUID.
|
||||
|
||||
.TP
|
||||
.B Examine
|
||||
Examine a device to see if it is part of an md array, and print out
|
||||
the details of that array.
|
||||
This mode can also be used to examine a large number of devices and to
|
||||
print out a summary of the arrays found in a format suitable for the
|
||||
.B mdctl.conf
|
||||
configuration file.
|
||||
|
||||
.TP
|
||||
.B "Follow or Monitor"
|
||||
Monitor one or more md devices and act on any state changes.
|
||||
|
||||
.TP
|
||||
.B Manage
|
||||
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.
|
||||
readonly, readwrite.
|
||||
'''If an array is only partially setup by the
|
||||
'''Create or Assemble commands, subsequent Manage commands can finish the
|
||||
'''job.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
Available options are:
|
||||
|
||||
.IP "\fB\-C\fP, \fB\-\-create\fP"
|
||||
Create a new array
|
||||
.TP
|
||||
.BR -A ", " --assemble
|
||||
Assemble an existing array.
|
||||
|
||||
.IP "\fB-A\fP, \fB\-\-assemble\fP"
|
||||
Assemble an existing array
|
||||
.TP
|
||||
.BR -B ", " --build
|
||||
Build a legacy array without superblocks.
|
||||
|
||||
.IP "\fB\-B\fP, \fB\-\-build\fP"
|
||||
Build a legacy array without superblock
|
||||
.TP
|
||||
.BR -C ", " --create
|
||||
Create a new array.
|
||||
|
||||
.IP "\fB\-D\fP, \fB\-\-detail\fP"
|
||||
Print detail of a given md array
|
||||
.TP
|
||||
.BR -D ", " --detail
|
||||
Print detail of one or more md devices.
|
||||
|
||||
.IP "\fB\-E\fP, \fB\-\-examine\fP"
|
||||
Print content of md superblock on device
|
||||
.TP
|
||||
.BR -E ", " --examine
|
||||
Print content of md superblock on device(s).
|
||||
|
||||
.IP "\fB\-h\fP, \fB\-\-help\fP"
|
||||
This help message or, after above option, mode specific help message
|
||||
.TP
|
||||
.BR -F ", " --follow ", " --monitor
|
||||
Select
|
||||
.B Monitor
|
||||
mode.
|
||||
|
||||
.IP "\fB\-V\fP, \fB\-\-version\fP"
|
||||
Print version information for mdctl
|
||||
.TP
|
||||
.BR -h ", " --help
|
||||
Display help message or, after above option, mode specific help message.
|
||||
|
||||
.IP "\fB\-v\fP, \fB\-\-verbose\fP"
|
||||
Be more verbose about what is happening
|
||||
.TP
|
||||
.BR -V ", " --version
|
||||
Print version information for mdctl.
|
||||
|
||||
.TP
|
||||
.BR -v ", " --verbose
|
||||
Be more verbose about what is happening.
|
||||
|
||||
.TP
|
||||
.BR -b ", " --brief
|
||||
Be less verbose. This is used with
|
||||
.B --detail
|
||||
and
|
||||
.BR --examine .
|
||||
|
||||
.SH For create or build:
|
||||
|
||||
.IP "\fB\-c\fP, \fB\-\-chunk=\fP"
|
||||
chunk size of kibibytes
|
||||
.TP
|
||||
.BR -c ", " --chunk=
|
||||
Specify chunk size of kibibytes. The default is 64.
|
||||
|
||||
.IP "\fB\-\-rounding=\fP"
|
||||
rounding factor for linear array (==chunk size)
|
||||
.TP
|
||||
.BR --rounding=
|
||||
Specify 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
|
||||
.TP
|
||||
.BR -l ", " --level=
|
||||
Set raid level. Options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid5, 4,
|
||||
raid5, 5. Obviously some of these are synonymous.
|
||||
Only the first 4 are valid when Building.
|
||||
|
||||
.IP "\fB\-p\fP, \fB\-\-parity=\fP"
|
||||
raid5 parity algorithm: {left,right}-{,a}symmetric
|
||||
.TP
|
||||
.BR -p ", " --parity=
|
||||
Set raid5 parity algorithm. Options are:
|
||||
{left,right}-{,a}symmetric, la, ra, ls, rs. The default is left-symmetric.
|
||||
|
||||
.IP "\fB\-\-layout=\fP"
|
||||
.TP
|
||||
.BR --layout=
|
||||
same as --parity
|
||||
|
||||
.IP "\fB\-n\fP, \fB\-\-raid-disks=\fP"
|
||||
number of active devices in array
|
||||
.TP
|
||||
.BR -n ", " --raid-disks=
|
||||
number of active devices in array.
|
||||
|
||||
.IP "\fB\-x\fP, \fB\-\-spare-disks=\fP"
|
||||
number of spares (eXtras) to allow space for
|
||||
.TP
|
||||
.BR -x ", " --spare-disks=
|
||||
number of spare (eXtra) disks in initial array. Spares can be added
|
||||
and removed later.
|
||||
|
||||
.IP "\fB\-z\fP, \fB\-\-size=\fP"
|
||||
Size (in K) of each drive in RAID1/4/5 - optional
|
||||
.TP
|
||||
.BR -z ", " --size=
|
||||
Amount (in Kibibytes) of space to use from each drive in RAID1/4/5.
|
||||
This must be a multiple of the chunk size, and must leave about 128Kb
|
||||
of space at the end of the drive for the RAID superblock.
|
||||
If this is not specified
|
||||
(as it normally is not) the smallest drive (or partition) sets the
|
||||
size, though if there is a variance among the drives of greater than 1%, a warning is
|
||||
issued.
|
||||
|
||||
.SH For assemble:
|
||||
|
||||
.IP "\fB\-u\fP, \fB\-\-uuid=\fP"
|
||||
uuid of array to assemble. Devices which don't have this uuid are excluded
|
||||
.TP
|
||||
.BR -u ", " --uuid=
|
||||
uuid of array to assemble. Devices which don't have this uuid are
|
||||
excluded
|
||||
|
||||
.IP "\fB\-c\fP, \fB\-\-config=\fP"
|
||||
config file
|
||||
.TP
|
||||
.BR -m ", " --super-minor=
|
||||
Minor number of device that array was created for. Devices which
|
||||
don't have this minor number are excluded. If you create an array as
|
||||
/dev/md1, then all superblock will contain the minor number 1, even if
|
||||
the array is later assembled as /dev/md2.
|
||||
|
||||
.IP "\fB\-s\fP, \fB\-\-scan\fP"
|
||||
.TP
|
||||
.BR -c ", " --config=
|
||||
config file. Default is
|
||||
.BR /etc/mdctl.conf .
|
||||
|
||||
.TP
|
||||
.BR -s ", " --scan
|
||||
scan config file for missing information
|
||||
|
||||
.IP "\fB\-f\fP, \fB\-\-force\fP"
|
||||
.TP
|
||||
.BR -f ", " --force
|
||||
Assemble the array even if some superblocks appear out-of-date
|
||||
|
||||
.TP
|
||||
.BR -R ", " --run
|
||||
Attempt to start the array even if fewer drives were given than are
|
||||
needed for a full array. Normally if not all drives are found and
|
||||
.B --scan
|
||||
is not used, then the array will be assembled but not started.
|
||||
With
|
||||
.B --run
|
||||
an attempt will be made to start it anyway.
|
||||
|
||||
.SH General management
|
||||
|
||||
.IP "\fB\-a\fP, \fB\-\-add\fP"
|
||||
add, or hotadd subsequent devices
|
||||
.TP
|
||||
.BR -a ", " --add
|
||||
'''add, or
|
||||
hotadd listed devices.
|
||||
|
||||
.IP "\fB\-r\fP, \fB\-\-remove\fP"
|
||||
remove subsequent devices
|
||||
.TP
|
||||
.BR -r ", " --remove
|
||||
remove listed devices. The must not be active. i.e. they should
|
||||
be failed or spare devices.
|
||||
|
||||
.IP "\fB\-f\fP, \fB\-\-fail\fP"
|
||||
mark subsequent devices a faulty
|
||||
.TP
|
||||
.BR -f ", " --fail
|
||||
mark listed devices as faulty.
|
||||
|
||||
.IP "\fB\-\-set-faulty\fP"
|
||||
same as --fail
|
||||
.TP
|
||||
.BR --set-faulty
|
||||
same as --fail.
|
||||
|
||||
.IP "\fB\-R\fP, \fB\-\-run\fP"
|
||||
start a partially built array
|
||||
.TP
|
||||
.BR -R ", " --run
|
||||
start a partially built array.
|
||||
|
||||
.IP "\fB\-S\fP, \fB\-\-stop\fP"
|
||||
deactivate array, releasing all resources
|
||||
.TP
|
||||
.BR -S ", " --stop
|
||||
deactivate array, releasing all resources.
|
||||
|
||||
.IP "\fB\-o\fP, \fB\-\-readonly\fP"
|
||||
mark array as readonly
|
||||
.TP
|
||||
.BR -o ", " --readonly
|
||||
mark array as readonly.
|
||||
|
||||
.IP "\fB\-w\fP, \fB\-\-readwrite\fP"
|
||||
mark array as readwrite
|
||||
.TP
|
||||
.BR -w ", " --readwrite
|
||||
mark array as readwrite.
|
||||
|
||||
|
||||
.SH ASSEMBLY MODE
|
||||
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --assemble
|
||||
.I device options...
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --assemble --scan
|
||||
.I options...
|
||||
|
||||
.PP
|
||||
This usage assembles one or more raid arrays from pre-existing components.
|
||||
For each array, mdctl needs to know the md device, the identity of the
|
||||
array, 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 identity can be given with the
|
||||
.B --uuid
|
||||
option, with the
|
||||
.B --super-minor
|
||||
option, 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.
|
||||
|
||||
Devices can be given on the
|
||||
.B --assemble
|
||||
command line or from the config file. Only devices which have an md
|
||||
superblock which contains the right identity 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/mdctl.conf
|
||||
is used.
|
||||
|
||||
If
|
||||
.B --scan
|
||||
is not given, then the config file will only be used to find the
|
||||
identity of md arrays.
|
||||
|
||||
Normally the array will be started after it is assembled. However is
|
||||
.B --scan
|
||||
is not given and insufficient drives were lists to start a complete
|
||||
(non-degraded) array, then the array is not started (to guard against
|
||||
usage errors). To insist that the array be started in this case (as
|
||||
may work for RAID1 or RAID5), give the
|
||||
.B --run
|
||||
flag.
|
||||
|
||||
|
||||
.SH BUILD MODE
|
||||
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --build
|
||||
.I device
|
||||
.BI --chunk= X
|
||||
.BI --level= Y
|
||||
.BI --raid-disks= Z
|
||||
.I devices
|
||||
|
||||
.PP
|
||||
This usage is similar to
|
||||
.BR --create .
|
||||
The difference is that it creates a legacy array without a superblock. With
|
||||
these arrays there is no difference 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, raid0, or linear. All devices must be listed
|
||||
and the array will be started once complete.
|
||||
|
||||
.SH CREATE MODE
|
||||
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --create
|
||||
.I device
|
||||
.BI --chunk= X
|
||||
.BI --level= Y
|
||||
.br
|
||||
.BI --raid-disks= Z
|
||||
.I devices
|
||||
|
||||
.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.
|
||||
.PP
|
||||
This usage will initialise a new md array, associate some devices with
|
||||
it, and activate the array.
|
||||
|
||||
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
|
||||
|
@ -190,97 +384,191 @@ 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.
|
||||
'''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.
|
||||
The General Management options that are valid with --create are:
|
||||
.TP
|
||||
.B --run
|
||||
insist of running the array even if some devices look like they might
|
||||
be in use.
|
||||
|
||||
.IP "\fB\-\-readonly\fP"
|
||||
.TP
|
||||
.B --readonly
|
||||
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
|
||||
|
||||
.SH DETAIL MODE
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --detail
|
||||
.RB [ --brief ]
|
||||
.I device ...
|
||||
.PP
|
||||
|
||||
.B mdctl
|
||||
--build device -chunk=X --level=Y --raid-disks=Z devices
|
||||
This usage sill print out the details of the given array including a
|
||||
list of component devices. To determine names for the devices,
|
||||
.B mdctl
|
||||
searches
|
||||
.B /dev
|
||||
for device files with the right major and minor numbers.
|
||||
|
||||
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.
|
||||
With
|
||||
.B --brief
|
||||
.B mdctl
|
||||
prints a single line that identifies the level, number of disks, and
|
||||
UUID of the array. This line is suitable for inclusion in
|
||||
.BR /etc/mdctl.conf .
|
||||
|
||||
The level may only be 0 or linear. All devices must be listed and the array
|
||||
will be started once complete.
|
||||
.SH EXAMINE MODE
|
||||
.HP 12
|
||||
Usage:
|
||||
.B mdctl --examine
|
||||
.RB [ --scan ]
|
||||
.RB [ --brief ]
|
||||
.I device ...
|
||||
.PP
|
||||
This usage will examine some block devices to see if that have a valid
|
||||
RAID superblock on them. The information in each valid raid
|
||||
superblock will be printed.
|
||||
|
||||
.SH BUGS
|
||||
no known bugs.
|
||||
If
|
||||
.B --scan
|
||||
is used, the no devices should be listed, and the complete set of
|
||||
devices identified in the configuration file are checked.
|
||||
.B --scan
|
||||
implies
|
||||
.B --brief
|
||||
but this implication can be countered by specifying
|
||||
.BR --verbose .
|
||||
|
||||
With
|
||||
.B --brief
|
||||
.B mdctl
|
||||
will output an config file entry of each distinct array that was
|
||||
found. This entry will list the UUID, the raid level, and a list of
|
||||
the individual devices on which a superblock for that array was found.
|
||||
This output will by syntactically suitable for inclusion in the
|
||||
configuration file, but should
|
||||
.B NOT
|
||||
be used blindly. Often the array description that you want in the
|
||||
configuration file is much less specific than that given by
|
||||
.BR "mdctl -Bs" .
|
||||
For example, you normally do not want to list the devices,
|
||||
particularly if they are SCSI devices.
|
||||
|
||||
'''.SH BUGS
|
||||
'''no known bugs.
|
||||
|
||||
.SH FILES
|
||||
|
||||
.SS /proc/mdstat
|
||||
|
||||
If you're using the
|
||||
.B /proc
|
||||
filesystem,
|
||||
.B /proc/mdstat
|
||||
gives you informations about md devices status.
|
||||
This file is not currently used by
|
||||
.BR mdctl .
|
||||
|
||||
.SS /etc/mdctl.conf
|
||||
|
||||
The config file is line oriented with, as usual, blank lines and lines
|
||||
beginning with a hash (or pound sign or sharp or number sign,
|
||||
whichever you like to call it) ignored.
|
||||
Lines that start with a blank are treated as continuations of the
|
||||
previous line (I don't like trailing slashes).
|
||||
|
||||
Each line contains a sequence of space-separated words, the first of
|
||||
which identified the type of line. Keywords are case-insensitive, and
|
||||
the first work on a line can be abbreviated to 3 letters.
|
||||
|
||||
There are two types of lines. ARRAY and DEVICE.
|
||||
|
||||
The DEVICE lines usually come first. All remaining words on the line
|
||||
are treated as names of devices, possibly containing wild cards (see
|
||||
.IR glob (7)).
|
||||
These list all the devices that
|
||||
.B mdctl
|
||||
is allowed to scan
|
||||
when looking for devices with RAID superblocks.
|
||||
Each line can contain multiple device names, and there can be multiple
|
||||
DEVICE lines. For example:
|
||||
.IP
|
||||
DEVICE /dev/hda* /dev/hdc*
|
||||
.br
|
||||
DEV /dev/sd*
|
||||
.br
|
||||
DEVICE /dev/discs/disc*/disc
|
||||
.PP
|
||||
The ARRAY lines identify actual arrays. The second word on the line
|
||||
should be the name of the device where the array is normally
|
||||
assembled, such as /dev/md1.
|
||||
Subsequent words identify the array. If multiple identities are given,
|
||||
then the array much match ALL identities to be considered a match.
|
||||
Each identity word has a tag, and equals sign, and some value.
|
||||
The options are:
|
||||
|
||||
.TP
|
||||
.B uuid=
|
||||
The value should be a 128 bit uuid in hexadecimal, with punctuation
|
||||
interspersed if desired. This must match the uuid stored in the
|
||||
superblock.
|
||||
.TP
|
||||
.B super-minor=
|
||||
The value is an integer which indicates the minor number that was
|
||||
stored in the superblock when the array was created. When an array is
|
||||
created as /dev/mdX, then the minor number X is stored.
|
||||
.TP
|
||||
.B devices=
|
||||
The value is a comma separated list of device names. Precisely these
|
||||
devices will be used to assemble the array. Note that the devices
|
||||
listed there must also be listed on a DEVICE line.
|
||||
.TP
|
||||
.B level=
|
||||
The value is a raid level. This is normally used to identify an
|
||||
array, but is supported so that the output of
|
||||
.B "mdctl --examine --scan"
|
||||
can be use directly in the configuration file.
|
||||
.TP
|
||||
.B disks=
|
||||
The value is the number of disks in a complete active array. As with
|
||||
.B level=
|
||||
this is mainly for compatibility with the output of
|
||||
.BR "mdctl --examine --scan" .
|
||||
|
||||
.SH TODO
|
||||
|
||||
Finish and document Follow mode.
|
||||
|
||||
.SH SEE ALSO
|
||||
For information on the various levels of
|
||||
RAID, check out:
|
||||
|
||||
.IP
|
||||
.UR http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
|
||||
http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
|
||||
.UE
|
||||
.PP
|
||||
for new releases of the RAID driver check out:
|
||||
|
||||
.IP
|
||||
.UR ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
|
||||
ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
|
||||
.UE
|
||||
.PP
|
||||
or
|
||||
.IP
|
||||
.UR http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/
|
||||
http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/
|
||||
.URk
|
||||
.PP
|
||||
.IR raidtab (5),
|
||||
.IR raid0run (8),
|
||||
.IR raidstop (8),
|
||||
|
|
115
mdctl.c
115
mdctl.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -64,14 +64,17 @@ int main(int argc, char *argv[])
|
|||
int sparedisks = 0;
|
||||
struct mddev_ident_s ident;
|
||||
char *configfile = NULL;
|
||||
char *cp;
|
||||
int scan = 0;
|
||||
char devmode = 0;
|
||||
int runstop = 0;
|
||||
int readonly = 0;
|
||||
char *devs[MD_SB_DISKS+1];
|
||||
int devmodes[MD_SB_DISKS+1];
|
||||
mddev_dev_t devlist = NULL;
|
||||
mddev_dev_t *devlistend = & devlist;
|
||||
mddev_dev_t dv;
|
||||
int devs_found = 0;
|
||||
int verbose = 0;
|
||||
int brief = 0;
|
||||
int force = 0;
|
||||
|
||||
char *mailaddr = NULL;
|
||||
|
@ -81,6 +84,8 @@ int main(int argc, char *argv[])
|
|||
int mdfd = -1;
|
||||
|
||||
ident.uuid_set=0;
|
||||
ident.level = -10;
|
||||
ident.raid_disks = -1;
|
||||
ident.super_minor= -1;
|
||||
ident.devices=0;
|
||||
|
||||
|
@ -124,19 +129,36 @@ int main(int argc, char *argv[])
|
|||
case 'v': verbose = 1;
|
||||
continue;
|
||||
|
||||
case 'b': brief = 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
|
||||
* All devices listed are "md" devices : --Detail, -As
|
||||
* No devices are "md" devices : --Examine
|
||||
* First device is "md", others are component: -A,-B,-C
|
||||
* Only accept on device before mode is determined.
|
||||
* If mode is @, then require devmode for other devices.
|
||||
*/
|
||||
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);
|
||||
if (devs_found > 0 && !mode ) {
|
||||
fprintf(stderr, Name ": Must give mode flag before second device name at %s\n", optarg);
|
||||
exit(2);
|
||||
}
|
||||
devs[devs_found] = optarg;
|
||||
devmodes[devs_found] = devmode;
|
||||
if (devs_found > 0 && mode == '@' && !devmode) {
|
||||
fprintf(stderr, Name ": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg);
|
||||
exit(2);
|
||||
}
|
||||
dv = malloc(sizeof(*dv));
|
||||
if (dv == NULL) {
|
||||
fprintf(stderr, Name ": malloc failed\n");
|
||||
exit(3);
|
||||
}
|
||||
dv->devname = optarg;
|
||||
dv->disposition = devmode;
|
||||
dv->next = NULL;
|
||||
*devlistend = dv;
|
||||
devlistend = &dv->next;
|
||||
|
||||
devs_found++;
|
||||
continue;
|
||||
|
||||
|
@ -205,6 +227,7 @@ int main(int argc, char *argv[])
|
|||
optarg);
|
||||
exit(2);
|
||||
}
|
||||
ident.level = level;
|
||||
continue;
|
||||
|
||||
case O('C','p'): /* raid5 layout */
|
||||
|
@ -246,6 +269,7 @@ int main(int argc, char *argv[])
|
|||
optarg);
|
||||
exit(2);
|
||||
}
|
||||
ident.raid_disks = raiddisks;
|
||||
continue;
|
||||
|
||||
case O('C','x'): /* number of spare (eXtra) discs */
|
||||
|
@ -276,7 +300,7 @@ int main(int argc, char *argv[])
|
|||
continue;
|
||||
case O('A','u'): /* uuid of array */
|
||||
if (ident.uuid_set) {
|
||||
fprintf(stderr, Name ": uuid cannot bet set twice. "
|
||||
fprintf(stderr, Name ": uuid cannot be set twice. "
|
||||
"Second value %s.\n", optarg);
|
||||
exit(2);
|
||||
}
|
||||
|
@ -288,6 +312,19 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
continue;
|
||||
|
||||
case O('A','m'): /* super-minor for array */
|
||||
if (ident.super_minor >= 0) {
|
||||
fprintf(stderr, Name ": super-minor cannot be set twice. "
|
||||
"Second value: %s.\n", optarg);
|
||||
exit(2);
|
||||
}
|
||||
ident.super_minor = strtoul(optarg, &cp, 10);
|
||||
if (!optarg[0] || *cp) {
|
||||
fprintf(stderr, Name ": Bad super-minor number: %s.\n", optarg);
|
||||
exit(2);
|
||||
}
|
||||
continue;
|
||||
|
||||
case O('A','c'): /* config file */
|
||||
case O('F','c'):
|
||||
if (configfile) {
|
||||
|
@ -299,6 +336,7 @@ int main(int argc, char *argv[])
|
|||
/* FIXME possibly check that config file exists. Even parse it */
|
||||
continue;
|
||||
case O('A','s'): /* scan */
|
||||
case O('E','s'):
|
||||
scan = 1;
|
||||
continue;
|
||||
|
||||
|
@ -409,7 +447,7 @@ int main(int argc, char *argv[])
|
|||
fprintf(stderr, Name ": an md device must be given in this mode\n");
|
||||
exit(2);
|
||||
}
|
||||
mdfd = open_mddev(devs[0]);
|
||||
mdfd = open_mddev(devlist->devname);
|
||||
if (mdfd < 0)
|
||||
exit(1);
|
||||
}
|
||||
|
@ -420,36 +458,36 @@ int main(int argc, char *argv[])
|
|||
case '@':/* Management */
|
||||
/* readonly, add/remove, readwrite, runstop */
|
||||
if (readonly>0)
|
||||
rv = Manage_ro(devs[0], mdfd, readonly);
|
||||
rv = Manage_ro(devlist->devname, mdfd, readonly);
|
||||
if (!rv && devs_found>1)
|
||||
rv = Manage_subdevs(devs[0], mdfd,
|
||||
devs_found-1, devs+1, devmodes+1);
|
||||
rv = Manage_subdevs(devlist->devname, mdfd,
|
||||
devlist->next);
|
||||
if (!rv && readonly < 0)
|
||||
rv = Manage_ro(devs[0], mdfd, readonly);
|
||||
rv = Manage_ro(devlist->devname, mdfd, readonly);
|
||||
if (!rv && runstop)
|
||||
rv = Manage_runstop(devs[0], mdfd, runstop);
|
||||
rv = Manage_runstop(devlist->devname, mdfd, runstop);
|
||||
break;
|
||||
case 'A': /* Assemble */
|
||||
if (!scan)
|
||||
rv = Assemble(devs[0], mdfd, &ident, configfile,
|
||||
devs_found-1, devs+1,
|
||||
rv = Assemble(devlist->devname, mdfd, &ident, configfile,
|
||||
devlist->next,
|
||||
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]);
|
||||
for (dv = devlist ; dv ; dv=dv->next) {
|
||||
mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
|
||||
mdfd = open_mddev(dv->devname);
|
||||
if (mdfd < 0) {
|
||||
rv |= 1;
|
||||
continue;
|
||||
}
|
||||
if (array_ident == NULL) {
|
||||
fprintf(stderr, Name ": %s not identified in config file.\n",
|
||||
devs[i]);
|
||||
dv->devname);
|
||||
rv |= 1;
|
||||
continue;
|
||||
}
|
||||
rv |= Assemble(devs[i], mdfd, array_ident, configfile,
|
||||
0, NULL,
|
||||
rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
|
||||
NULL,
|
||||
readonly, runstop, verbose, force);
|
||||
}
|
||||
else {
|
||||
|
@ -459,36 +497,43 @@ int main(int argc, char *argv[])
|
|||
rv = 1;
|
||||
} else
|
||||
for (; array_list; array_list = array_list->next) {
|
||||
mdu_array_info_t array;
|
||||
mdfd = open_mddev(array_list->devname);
|
||||
if (mdfd < 0) {
|
||||
rv |= 1;
|
||||
continue;
|
||||
}
|
||||
if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
|
||||
/* already assembled, skip */
|
||||
continue;
|
||||
rv |= Assemble(array_list->devname, mdfd,
|
||||
array_list, configfile,
|
||||
0, NULL,
|
||||
NULL,
|
||||
readonly, runstop, verbose, force);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B': /* Build */
|
||||
rv = Build(devs[0], mdfd, chunk, level, raiddisks, devs_found-1,devs+1);
|
||||
rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next);
|
||||
break;
|
||||
case 'C': /* Create */
|
||||
rv = Create(devs[0], mdfd, chunk, level, layout, size,
|
||||
rv = Create(devlist->devname, mdfd, chunk, level, layout, size,
|
||||
raiddisks, sparedisks,
|
||||
devs_found-1,devs+1, runstop, verbose, force);
|
||||
devs_found-1, devlist->next, runstop, verbose, force);
|
||||
break;
|
||||
case 'D': /* Detail */
|
||||
for (i=0; i<devs_found; i++)
|
||||
rv |= Detail(devs[i]);
|
||||
for (dv=devlist ; dv; dv=dv->next)
|
||||
rv |= Detail(dv->devname, brief);
|
||||
break;
|
||||
case 'E': /* Examine */
|
||||
for (i=0; i<devs_found; i++)
|
||||
rv |= Examine(devs[i]);
|
||||
if (devlist == NULL && scan==0) {
|
||||
fprintf(stderr, Name ": No devices to examine\n");
|
||||
exit(2);
|
||||
}
|
||||
rv = Examine(devlist, devlist?brief:!verbose, configfile);
|
||||
break;
|
||||
case 'F': /* Follow */
|
||||
rv= Monitor(devs_found, devs, mailaddr, program,
|
||||
rv= Monitor(devlist, mailaddr, program,
|
||||
delay?delay:60, configfile);
|
||||
}
|
||||
exit(rv);
|
||||
|
|
24
mdctl.h
24
mdctl.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -76,7 +76,8 @@ typedef struct mddev_ident_s {
|
|||
char *devices; /* comma separated list of device
|
||||
* names with wild cards
|
||||
*/
|
||||
|
||||
int level; /* -10 if not set */
|
||||
int raid_disks; /* -1 if not set */
|
||||
char *spare_group;
|
||||
struct mddev_ident_s *next;
|
||||
} *mddev_ident_t;
|
||||
|
@ -84,6 +85,9 @@ typedef struct mddev_ident_s {
|
|||
/* List of device names - wildcards expanded */
|
||||
typedef struct mddev_dev_s {
|
||||
char *devname;
|
||||
char disposition; /* 'a' for add, 'r' for remove, 'f' for fail.
|
||||
* Not set for names read from .config
|
||||
*/
|
||||
struct mddev_dev_s *next;
|
||||
} *mddev_dev_t;
|
||||
|
||||
|
@ -106,29 +110,29 @@ extern char *map_dev(int major, int minor);
|
|||
extern int Manage_ro(char *devname, int fd, int readonly);
|
||||
extern int Manage_runstop(char *devname, int fd, int runstop);
|
||||
extern int Manage_subdevs(char *devname, int fd,
|
||||
int devcnt, char *devnames[], int devmodes[]);
|
||||
mddev_dev_t devlist);
|
||||
|
||||
|
||||
extern int Assemble(char *mddev, int mdfd,
|
||||
mddev_ident_t ident,
|
||||
char *conffile,
|
||||
int subdevs, char *subdev[],
|
||||
mddev_dev_t devlist,
|
||||
int readonly, int runstop,
|
||||
int verbose, int force);
|
||||
|
||||
extern int Build(char *mddev, int mdfd, int chunk, int level,
|
||||
int raiddisks,
|
||||
int subdevs, char *subdev[]);
|
||||
mddev_dev_t devlist);
|
||||
|
||||
|
||||
extern int Create(char *mddev, int mdfd,
|
||||
int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
|
||||
int subdevs, char *subdev[],
|
||||
int subdevs, mddev_dev_t devlist,
|
||||
int runstop, int verbose, int force);
|
||||
|
||||
extern int Detail(char *dev);
|
||||
extern int Examine(char *dev);
|
||||
extern int Monitor(int num_devs, char *devlist[],
|
||||
extern int Detail(char *dev, int brief);
|
||||
extern int Examine(mddev_dev_t devlist, int brief, char *conffile);
|
||||
extern int Monitor(mddev_dev_t devlist,
|
||||
char *mailaddr, char *alert_cmd,
|
||||
int period,
|
||||
char *config);
|
||||
|
@ -142,3 +146,5 @@ extern int check_raid(int fd, char *name);
|
|||
|
||||
extern mddev_ident_t conf_get_ident(char *, char*);
|
||||
extern mddev_dev_t conf_get_devs(char *);
|
||||
|
||||
extern char *human_size(long kbytes);
|
||||
|
|
|
@ -0,0 +1,476 @@
|
|||
mdctl(8) mdctl(8)
|
||||
|
||||
|
||||
|
||||
NNAAMMEE
|
||||
mdctl - manage MD devices _a_k_a Linux Software Raid.
|
||||
|
||||
|
||||
SSYYNNOOPPSSIISS
|
||||
mmddccttll _[_m_o_d_e_] _<_r_a_i_d_d_e_v_i_c_e_> _[_o_p_t_i_o_n_s_] _<_s_u_b_d_e_v_i_c_e_s_>
|
||||
|
||||
|
||||
DDEESSCCRRIIPPTTIIOONN
|
||||
RAID devices are virtual devices created from two or more
|
||||
real block devices. This allows multiple devices (typi-
|
||||
cally disk drives or partitions there-of) to be combined
|
||||
into a single device to hold (for example) a single
|
||||
filesystem. Some RAID levels included redundancy and so
|
||||
can survive some degree of device failure.
|
||||
|
||||
Linux Software RAID devices are implemented through the md
|
||||
(Multiple Devices) device driver.
|
||||
|
||||
Currently, Linux supports LLIINNEEAARR md devices, RRAAIIDD00 (strip-
|
||||
ing), RRAAIIDD11 (mirroring), RRAAIIDD44 and RRAAIIDD55..
|
||||
|
||||
Recent kernels (2002) also support a mode known as MMUULLTTII--
|
||||
PPAATTHH. mmddccttll does not support MULTIPATH as yet.
|
||||
|
||||
mmddccttll is a program that can be used to create and manage
|
||||
MD devices. As such it provides a similar set of func-
|
||||
tionality to the rraaiiddttoooollss packages. The key differences
|
||||
between mmddccttll and rraaiiddttoooollss are:
|
||||
|
||||
+o mmddccttll is a single program and not a collection of pro-
|
||||
grams.
|
||||
|
||||
+o mmddccttll can perform (almost) all of its functions with-
|
||||
out having a configuration file. Also mdctl helps
|
||||
with management of the configuration file.
|
||||
|
||||
+o mmddccttll can provide information about your arrays
|
||||
(through Detail and Examine) that rraaiiddttoooollss cannot.
|
||||
|
||||
+o rraaiiddttoooollss can manage MULTIPATH devices which mmddccttll
|
||||
cannot yet manage.
|
||||
|
||||
|
||||
MMOODDEESS
|
||||
mdctl has 7 major modes of operation:
|
||||
|
||||
AAsssseemmbbllee
|
||||
Assemble the parts of a previously created array
|
||||
into an active array. Components can be explicitly
|
||||
given or can be searched for. mmddccttll checks that
|
||||
the components do form a bona fide array, and can,
|
||||
on request, fiddle superblock information so as to
|
||||
assemble a faulty array.
|
||||
|
||||
|
||||
BBuuiilldd Build a legacy array without per-device
|
||||
superblocks.
|
||||
|
||||
|
||||
CCrreeaattee Create a new array with per-device superblocks.
|
||||
|
||||
|
||||
DDeettaaiill Display the details of a given md device. Details
|
||||
include the RAID level, the number of devices,
|
||||
which ones are faulty (if any), and the array UUID.
|
||||
|
||||
|
||||
EExxaammiinnee
|
||||
Examine a device to see if it is part of an md
|
||||
array, and print out the details of that array.
|
||||
This mode can also be used to examine a large num-
|
||||
ber of devices and to print out a summary of the
|
||||
arrays found in a format suitable for the
|
||||
mmddccttll..ccoonnff configuration file.
|
||||
|
||||
|
||||
FFoollllooww oorr MMoonniittoorr
|
||||
Monitor one or more md devices and act on any state
|
||||
changes.
|
||||
|
||||
|
||||
MMaannaaggee This is for odd bits an pieces like hotadd,
|
||||
hotremove, setfaulty, stop, readonly, readwrite.
|
||||
|
||||
|
||||
OOPPTTIIOONNSS
|
||||
Available options are:
|
||||
|
||||
|
||||
--AA, ----aasssseemmbbllee
|
||||
Assemble an existing array.
|
||||
|
||||
|
||||
--BB, ----bbuuiilldd
|
||||
Build a legacy array without superblocks.
|
||||
|
||||
|
||||
--CC, ----ccrreeaattee
|
||||
Create a new array.
|
||||
|
||||
|
||||
--DD, ----ddeettaaiill
|
||||
Print detail of one or more md devices.
|
||||
|
||||
|
||||
--EE, ----eexxaammiinnee
|
||||
Print content of md superblock on device(s).
|
||||
|
||||
|
||||
--FF, ----ffoollllooww, ----mmoonniittoorr
|
||||
Select MMoonniittoorr mode.
|
||||
|
||||
|
||||
--hh, ----hheellpp
|
||||
Display help message or, after above option, mode
|
||||
specific help message.
|
||||
|
||||
|
||||
--VV, ----vveerrssiioonn
|
||||
Print version information for mdctl.
|
||||
|
||||
|
||||
--vv, ----vveerrbboossee
|
||||
Be more verbose about what is happening.
|
||||
|
||||
|
||||
--bb, ----bbrriieeff
|
||||
Be less verbose. This is used with ----ddeettaaiill and
|
||||
----eexxaammiinnee.
|
||||
|
||||
|
||||
FFoorr ccrreeaattee oorr bbuuiilldd::
|
||||
--cc, ----cchhuunnkk==
|
||||
Specify chunk size of kibibytes. The default is
|
||||
64.
|
||||
|
||||
|
||||
----rroouunnddiinngg==
|
||||
Specify rounding factor for linear array (==chunk
|
||||
size)
|
||||
|
||||
|
||||
--ll, ----lleevveell==
|
||||
Set raid level. Options are: linear, raid0, 0,
|
||||
stripe, raid1, 1, mirror, raid5, 4, raid5, 5.
|
||||
Obviously some of these are synonymous. Only the
|
||||
first 4 are valid when Building.
|
||||
|
||||
|
||||
--pp, ----ppaarriittyy==
|
||||
Set raid5 parity algorithm. Options are:
|
||||
{left,right}-{,a}symmetric, la, ra, ls, rs. The
|
||||
default is left-symmetric.
|
||||
|
||||
|
||||
----llaayyoouutt==
|
||||
same as --parity
|
||||
|
||||
|
||||
--nn, ----rraaiidd--ddiisskkss==
|
||||
number of active devices in array.
|
||||
|
||||
|
||||
--xx, ----ssppaarree--ddiisskkss==
|
||||
number of spare (eXtra) disks in initial array.
|
||||
Spares can be added and removed later.
|
||||
|
||||
|
||||
--zz, ----ssiizzee==
|
||||
Amount (in Kibibytes) of space to use from each
|
||||
drive in RAID1/4/5. This must be a multiple of the
|
||||
chunk size, and must leave about 128Kb of space at
|
||||
the end of the drive for the RAID superblock. If
|
||||
this is not specified (as it normally is not) the
|
||||
smallest drive (or partition) sets the size, though
|
||||
if there is a variance among the drives of greater
|
||||
than 1%, a warning is issued.
|
||||
|
||||
|
||||
FFoorr aasssseemmbbllee::
|
||||
--uu, ----uuuuiidd==
|
||||
uuid of array to assemble. Devices which don't have
|
||||
this uuid are excluded
|
||||
|
||||
|
||||
--mm, ----ssuuppeerr--mmiinnoorr==
|
||||
Minor number of device that array was created for.
|
||||
Devices which don't have this minor number are
|
||||
excluded. If you create an array as /dev/md1, then
|
||||
all superblock will contain the minor number 1,
|
||||
even if the array is later assembled as /dev/md2.
|
||||
|
||||
|
||||
--cc, ----ccoonnffiigg==
|
||||
config file. Default is //eettcc//mmddccttll..ccoonnff.
|
||||
|
||||
|
||||
--ss, ----ssccaann
|
||||
scan config file for missing information
|
||||
|
||||
|
||||
--ff, ----ffoorrccee
|
||||
Assemble the array even if some superblocks appear
|
||||
out-of-date
|
||||
|
||||
|
||||
--RR, ----rruunn
|
||||
Attempt to start the array even if fewer drives
|
||||
were given than are needed for a full array. Nor-
|
||||
mally if not all drives are found and ----ssccaann is not
|
||||
used, then the array will be assembled but not
|
||||
started. With ----rruunn an attempt will be made to
|
||||
start it anyway.
|
||||
|
||||
|
||||
GGeenneerraall mmaannaaggeemmeenntt
|
||||
--aa, ----aadddd
|
||||
hotadd listed devices.
|
||||
|
||||
|
||||
--rr, ----rreemmoovvee
|
||||
remove listed devices. The must not be active.
|
||||
i.e. they should be failed or spare devices.
|
||||
|
||||
|
||||
--ff, ----ffaaiill
|
||||
mark listed devices as faulty.
|
||||
|
||||
|
||||
----sseett--ffaauullttyy
|
||||
same as --fail.
|
||||
|
||||
|
||||
--RR, ----rruunn
|
||||
start a partially built array.
|
||||
|
||||
|
||||
--SS, ----ssttoopp
|
||||
deactivate array, releasing all resources.
|
||||
|
||||
|
||||
--oo, ----rreeaaddoonnllyy
|
||||
mark array as readonly.
|
||||
|
||||
|
||||
--ww, ----rreeaaddwwrriittee
|
||||
mark array as readwrite.
|
||||
|
||||
|
||||
|
||||
AASSSSEEMMBBLLYY MMOODDEE
|
||||
Usage: mmddccttll ----aasssseemmbbllee _d_e_v_i_c_e _o_p_t_i_o_n_s_._._.
|
||||
|
||||
Usage: mmddccttll ----aasssseemmbbllee ----ssccaann _o_p_t_i_o_n_s_._._.
|
||||
|
||||
|
||||
This usage assembles one or more raid arrays from pre-
|
||||
existing components. For each array, mdctl needs to know
|
||||
the md device, the identity of the array, and a number of
|
||||
sub devices. These can be found in a number of ways.
|
||||
|
||||
The md device is either given before ----ssccaann or is found
|
||||
from the config file. In the latter case, multiple md
|
||||
devices can be started with a single mdctl command.
|
||||
|
||||
The identity can be given with the ----uuuuiidd option, with the
|
||||
----ssuuppeerr--mmiinnoorr option, can be found in in the config file,
|
||||
or will be taken from the super block on the first subde-
|
||||
vice listed on the command line.
|
||||
|
||||
Devices can be given on the ----aasssseemmbbllee command line or
|
||||
from the config file. Only devices which have an md
|
||||
superblock which contains the right identity will be con-
|
||||
sidered for any device.
|
||||
|
||||
The config file is only used if explicitly named with
|
||||
----ccoonnffiigg or requested with ----ssccaann.. In the later case,
|
||||
//eettcc//mmddccttll..ccoonnff is used.
|
||||
|
||||
If ----ssccaann is not given, then the config file will only be
|
||||
used to find the identity of md arrays.
|
||||
|
||||
Normally the array will be started after it is assembled.
|
||||
However is ----ssccaann is not given and insufficient drives
|
||||
were lists to start a complete (non-degraded) array, then
|
||||
the array is not started (to guard against usage errors).
|
||||
To insist that the array be started in this case (as may
|
||||
work for RAID1 or RAID5), give the ----rruunn flag.
|
||||
|
||||
|
||||
|
||||
BBUUIILLDD MMOODDEE
|
||||
Usage: mmddccttll ----bbuuiilldd _d_e_v_i_c_e ----cchhuunnkk==_X ----lleevveell==_Y ----rraaiidd--
|
||||
ddiisskkss==_Z _d_e_v_i_c_e_s
|
||||
|
||||
|
||||
This usage is similar to ----ccrreeaattee. The difference is that
|
||||
it creates a legacy array without a superblock. With these
|
||||
arrays there is no difference 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, raid0, or linear. All devices
|
||||
must be listed and the array will be started once com-
|
||||
plete.
|
||||
|
||||
|
||||
CCRREEAATTEE MMOODDEE
|
||||
Usage: mmddccttll ----ccrreeaattee _d_e_v_i_c_e ----cchhuunnkk==_X ----lleevveell==_Y
|
||||
----rraaiidd--ddiisskkss==_Z _d_e_v_i_c_e_s
|
||||
|
||||
|
||||
This usage will initialise a new md array, associate some
|
||||
devices with it, and activate the array.
|
||||
|
||||
As devices are added, they are checked to see if they con-
|
||||
tain 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 automati-
|
||||
cally be run, though the presence of a ----rruunn can override
|
||||
this caution.
|
||||
|
||||
|
||||
The General Management options that are valid with --cre-
|
||||
ate are:
|
||||
|
||||
----rruunn insist of running the array even if some devices
|
||||
look like they might be in use.
|
||||
|
||||
|
||||
----rreeaaddoonnllyy
|
||||
start the array readonly - not supported yet.
|
||||
|
||||
|
||||
DDEETTAAIILL MMOODDEE
|
||||
Usage: mmddccttll ----ddeettaaiill [----bbrriieeff] _d_e_v_i_c_e _._._.
|
||||
|
||||
|
||||
This usage sill print out the details of the given array
|
||||
including a list of component devices. To determine names
|
||||
for the devices, mmddccttll searches //ddeevv for device files with
|
||||
the right major and minor numbers.
|
||||
|
||||
With ----bbrriieeff mmddccttll prints a single line that identifies
|
||||
the level, number of disks, and UUID of the array. This
|
||||
line is suitable for inclusion in //eettcc//mmddccttll..ccoonnff.
|
||||
|
||||
|
||||
EEXXAAMMIINNEE MMOODDEE
|
||||
Usage: mmddccttll ----eexxaammiinnee [----ssccaann] [----bbrriieeff] _d_e_v_i_c_e _._._.
|
||||
|
||||
This usage will examine some block devices to see if that
|
||||
have a valid RAID superblock on them. The information in
|
||||
each valid raid superblock will be printed.
|
||||
|
||||
If ----ssccaann is used, the no devices should be listed, and
|
||||
the complete set of devices identified in the configura-
|
||||
tion file are checked. ----ssccaann implies ----bbrriieeff but this
|
||||
implication can be countered by specifying ----vveerrbboossee.
|
||||
|
||||
With ----bbrriieeff mmddccttll will output an config file entry of
|
||||
each distinct array that was found. This entry will list
|
||||
the UUID, the raid level, and a list of the individual
|
||||
devices on which a superblock for that array was found.
|
||||
This output will by syntactically suitable for inclusion
|
||||
in the configuration file, but should NNOOTT be used blindly.
|
||||
Often the array description that you want in the configu-
|
||||
ration file is much less specific than that given by mmddccttll
|
||||
--BBss. For example, you normally do not want to list the
|
||||
devices, particularly if they are SCSI devices.
|
||||
|
||||
|
||||
|
||||
FFIILLEESS
|
||||
//pprroocc//mmddssttaatt
|
||||
If you're using the //pprroocc filesystem, //pprroocc//mmddssttaatt gives
|
||||
you informations about md devices status. This file is
|
||||
not currently used by mmddccttll.
|
||||
|
||||
|
||||
//eettcc//mmddccttll..ccoonnff
|
||||
The config file is line oriented with, as usual, blank
|
||||
lines and lines beginning with a hash (or pound sign or
|
||||
sharp or number sign, whichever you like to call it)
|
||||
ignored. Lines that start with a blank are treated as
|
||||
continuations of the previous line (I don't like trailing
|
||||
slashes).
|
||||
|
||||
Each line contains a sequence of space-separated words,
|
||||
the first of which identified the type of line. Keywords
|
||||
are case-insensitive, and the first work on a line can be
|
||||
abbreviated to 3 letters.
|
||||
|
||||
There are two types of lines. ARRAY and DEVICE.
|
||||
|
||||
The DEVICE lines usually come first. All remaining words
|
||||
on the line are treated as names of devices, possibly con-
|
||||
taining wild cards (see _g_l_o_b(7)). These list all the
|
||||
devices that mmddccttll is allowed to scan when looking for
|
||||
devices with RAID superblocks. Each line can contain mul-
|
||||
tiple device names, and there can be multiple DEVICE
|
||||
lines. For example:
|
||||
|
||||
DEVICE /dev/hda* /dev/hdc*
|
||||
DEV /dev/sd*
|
||||
DEVICE /dev/discs/disc*/disc
|
||||
|
||||
The ARRAY lines identify actual arrays. The second word
|
||||
on the line should be the name of the device where the
|
||||
array is normally assembled, such as /dev/md1. Subsequent
|
||||
words identify the array. If multiple identities are
|
||||
given, then the array much match ALL identities to be con-
|
||||
sidered a match. Each identity word has a tag, and equals
|
||||
sign, and some value. The options are:
|
||||
|
||||
|
||||
uuuuiidd== The value should be a 128 bit uuid in hexadecimal,
|
||||
with punctuation interspersed if desired. This
|
||||
must match the uuid stored in the superblock.
|
||||
|
||||
ssuuppeerr--mmiinnoorr==
|
||||
The value is an integer which indicates the minor
|
||||
number that was stored in the superblock when the
|
||||
array was created. When an array is created as
|
||||
/dev/mdX, then the minor number X is stored.
|
||||
|
||||
ddeevviicceess==
|
||||
The value is a comma separated list of device
|
||||
names. Precisely these devices will be used to
|
||||
assemble the array. Note that the devices listed
|
||||
there must also be listed on a DEVICE line.
|
||||
|
||||
lleevveell== The value is a raid level. This is normally used
|
||||
to identify an array, but is supported so that the
|
||||
output of mmddccttll ----eexxaammiinnee ----ssccaann can be use
|
||||
directly in the configuration file.
|
||||
|
||||
ddiisskkss== The value is the number of disks in a complete
|
||||
active array. As with lleevveell== this is mainly for
|
||||
compatibility with the output of mmddccttll ----eexxaammiinnee
|
||||
----ssccaann.
|
||||
|
||||
|
||||
TTOODDOO
|
||||
Finish and document Follow mode.
|
||||
|
||||
|
||||
SSEEEE AALLSSOO
|
||||
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/peo-
|
||||
ple/mingo/raid-patches
|
||||
|
||||
or
|
||||
|
||||
http://www.cse.unsw.edu.au/~neilb/patches/linux-
|
||||
stable/
|
||||
|
||||
_r_a_i_d_t_a_b(5), _r_a_i_d_0_r_u_n(8), _r_a_i_d_s_t_o_p(8), _m_k_r_a_i_d(8)
|
||||
|
||||
|
||||
|
||||
mdctl(8)
|
15
util.c
15
util.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mdctl - manage Linux "md" devices aka RAID arrays.
|
||||
*
|
||||
* Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -424,3 +424,16 @@ int calc_sb_csum(mdp_super_t *super)
|
|||
super->sb_csum = oldcsum;
|
||||
return csum;
|
||||
}
|
||||
|
||||
char *human_size(long kbytes)
|
||||
{
|
||||
static char buf[30];
|
||||
|
||||
if (kbytes < 2000)
|
||||
buf[0]=0;
|
||||
else if (kbytes < 2*1024*1024)
|
||||
sprintf(buf, " (%d MiB)", kbytes>>10);
|
||||
else
|
||||
sprintf(buf, " (%d GiB)", kbytes>>20);
|
||||
return buf;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue