mdadm-1.5.0
This commit is contained in:
parent
feb716e9c3
commit
98c6faba80
|
@ -0,0 +1,29 @@
|
||||||
|
Subject: ANNOUNCE: mdadm 1.5.0 - A tool for managing Soft RAID under Linux
|
||||||
|
|
||||||
|
|
||||||
|
I am pleased to announce the availability of
|
||||||
|
mdadm version 1.5.0
|
||||||
|
It is available at
|
||||||
|
http://www.cse.unsw.edu.au/~neilb/source/mdadm/
|
||||||
|
and
|
||||||
|
http://www.{countrycode}.kernel.org/pub/utils/raid/mdadm/
|
||||||
|
|
||||||
|
as a source tar-ball and (at the first site) as an SRPM, and as an RPM for i386.
|
||||||
|
|
||||||
|
mdadm is a tool for creating, managing and monitoring
|
||||||
|
device arrays using the "md" driver in Linux, also
|
||||||
|
known as Software RAID arrays.
|
||||||
|
|
||||||
|
Release 1.5.0 adds:
|
||||||
|
- new command "mdassemble" for use in initrd/initramfs.
|
||||||
|
- raid6 support (for 2.6.2 and later kernels)
|
||||||
|
- RebuildFinished event in monitor mode.
|
||||||
|
- include rebuild status in --detail output.
|
||||||
|
- fixes for assorted compilation problems
|
||||||
|
|
||||||
|
Development of mdadm is sponsored by CSE@UNSW:
|
||||||
|
The School of Computer Science and Engineering
|
||||||
|
at
|
||||||
|
The University of New South Wales
|
||||||
|
|
||||||
|
NeilBrown 22 Jan 2004
|
35
Assemble.c
35
Assemble.c
|
@ -98,8 +98,8 @@ int Assemble(char *mddev, int mdfd,
|
||||||
mdp_super_t first_super, super;
|
mdp_super_t first_super, super;
|
||||||
struct {
|
struct {
|
||||||
char *devname;
|
char *devname;
|
||||||
int major, minor;
|
unsigned int major, minor;
|
||||||
int oldmajor, oldminor;
|
unsigned int oldmajor, oldminor;
|
||||||
long long events;
|
long long events;
|
||||||
time_t utime;
|
time_t utime;
|
||||||
int uptodate;
|
int uptodate;
|
||||||
|
@ -107,16 +107,17 @@ int Assemble(char *mddev, int mdfd,
|
||||||
int raid_disk;
|
int raid_disk;
|
||||||
} *devices;
|
} *devices;
|
||||||
int *best = NULL; /* indexed by raid_disk */
|
int *best = NULL; /* indexed by raid_disk */
|
||||||
int bestcnt = 0;
|
unsigned int bestcnt = 0;
|
||||||
int devcnt = 0, okcnt, sparecnt;
|
int devcnt = 0;
|
||||||
int req_cnt;
|
unsigned int okcnt, sparecnt;
|
||||||
int i;
|
unsigned int req_cnt;
|
||||||
|
unsigned int i;
|
||||||
int most_recent = 0;
|
int most_recent = 0;
|
||||||
int chosen_drive;
|
int chosen_drive;
|
||||||
int change = 0;
|
int change = 0;
|
||||||
int inargv = 0;
|
int inargv = 0;
|
||||||
int start_partial_ok = force || devlist==NULL;
|
int start_partial_ok = force || devlist==NULL;
|
||||||
int num_devs;
|
unsigned int num_devs;
|
||||||
mddev_dev_t tmpdev;
|
mddev_dev_t tmpdev;
|
||||||
|
|
||||||
vers = md_get_version(mdfd);
|
vers = md_get_version(mdfd);
|
||||||
|
@ -224,21 +225,21 @@ int Assemble(char *mddev, int mdfd,
|
||||||
devname);
|
devname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ident->super_minor >= 0 &&
|
if (ident->super_minor != UnSet &&
|
||||||
(!havesuper || ident->super_minor != super.md_minor)) {
|
(!havesuper || ident->super_minor != super.md_minor)) {
|
||||||
if (inargv || verbose)
|
if (inargv || verbose)
|
||||||
fprintf(stderr, Name ": %s has wrong super-minor.\n",
|
fprintf(stderr, Name ": %s has wrong super-minor.\n",
|
||||||
devname);
|
devname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ident->level != -10 &&
|
if (ident->level != UnSet &&
|
||||||
(!havesuper|| ident->level != super.level)) {
|
(!havesuper|| ident->level != (int)super.level)) {
|
||||||
if (inargv || verbose)
|
if (inargv || verbose)
|
||||||
fprintf(stderr, Name ": %s has wrong raid level.\n",
|
fprintf(stderr, Name ": %s has wrong raid level.\n",
|
||||||
devname);
|
devname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ident->raid_disks != -1 &&
|
if (ident->raid_disks != UnSet &&
|
||||||
(!havesuper || ident->raid_disks!= super.raid_disks)) {
|
(!havesuper || ident->raid_disks!= super.raid_disks)) {
|
||||||
if (inargv || verbose)
|
if (inargv || verbose)
|
||||||
fprintf(stderr, Name ": %s requires wrong number of drives.\n",
|
fprintf(stderr, Name ": %s requires wrong number of drives.\n",
|
||||||
|
@ -349,16 +350,16 @@ int Assemble(char *mddev, int mdfd,
|
||||||
> devices[most_recent].events)
|
> devices[most_recent].events)
|
||||||
most_recent = devcnt;
|
most_recent = devcnt;
|
||||||
}
|
}
|
||||||
if (super.level == -4)
|
if ((int)super.level == -4)
|
||||||
/* with multipath, the raid_disk from the superblock is meaningless */
|
/* with multipath, the raid_disk from the superblock is meaningless */
|
||||||
i = devcnt;
|
i = devcnt;
|
||||||
else
|
else
|
||||||
i = devices[devcnt].raid_disk;
|
i = devices[devcnt].raid_disk;
|
||||||
if (i>=0 && i < 10000) {
|
if (i < 10000) {
|
||||||
if (i >= bestcnt) {
|
if (i >= bestcnt) {
|
||||||
int newbestcnt = i+10;
|
unsigned int newbestcnt = i+10;
|
||||||
int *newbest = malloc(sizeof(int)*newbestcnt);
|
int *newbest = malloc(sizeof(int)*newbestcnt);
|
||||||
int c;
|
unsigned int c;
|
||||||
for (c=0; c < newbestcnt; c++)
|
for (c=0; c < newbestcnt; c++)
|
||||||
if (c < bestcnt)
|
if (c < bestcnt)
|
||||||
newbest[c] = best[c];
|
newbest[c] = best[c];
|
||||||
|
@ -392,7 +393,7 @@ int Assemble(char *mddev, int mdfd,
|
||||||
/* note: we ignore error flags in multipath arrays
|
/* note: we ignore error flags in multipath arrays
|
||||||
* as they don't make sense
|
* as they don't make sense
|
||||||
*/
|
*/
|
||||||
if (first_super.level != -4)
|
if ((int)first_super.level != -4)
|
||||||
if (!(devices[j].state & (1<<MD_DISK_SYNC))) {
|
if (!(devices[j].state & (1<<MD_DISK_SYNC))) {
|
||||||
if (!(devices[j].state & (1<<MD_DISK_FAULTY)))
|
if (!(devices[j].state & (1<<MD_DISK_FAULTY)))
|
||||||
sparecnt++;
|
sparecnt++;
|
||||||
|
@ -494,7 +495,7 @@ int Assemble(char *mddev, int mdfd,
|
||||||
|
|
||||||
for (i=0; i<bestcnt; i++) {
|
for (i=0; i<bestcnt; i++) {
|
||||||
int j = best[i];
|
int j = best[i];
|
||||||
int desired_state;
|
unsigned int desired_state;
|
||||||
|
|
||||||
if (i < super.raid_disks)
|
if (i < super.raid_disks)
|
||||||
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
|
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
|
||||||
|
|
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
||||||
|
Changes Prior to this release
|
||||||
|
- new commands "mdassemble" which is a stripped-down equivalent of
|
||||||
|
"mdadm -As", that can be compiled with dietlibc.
|
||||||
|
Thanks to Luca Berra <bluca@comedia.it>.
|
||||||
|
It can be using in an initramfs or initrd.
|
||||||
|
- Fix compiling error with BLKGETSIZE64 and some signed/unsigned
|
||||||
|
comparison warnings.
|
||||||
|
- Add Rebuild Status (% complete) to --detail output.
|
||||||
|
- Support "--monitor --test" which will generate a test alert
|
||||||
|
for each array once, to test notification paths.
|
||||||
|
- Generate RebuildFinished event when rebuild finishes.
|
||||||
|
- Support for raid6 as found in 2.6.2 - thanks to
|
||||||
|
H. Peter Anvin <hpa@zytor.com>
|
||||||
|
- Support partitioned md arrays with a different major number and
|
||||||
|
naming scheme (md_dX in /proc/mdstat, /dev/md/dXpY in /dev).
|
||||||
|
|
||||||
Changes Prior to 1.4.0 release
|
Changes Prior to 1.4.0 release
|
||||||
- Document fact that creating a raid5 array really creates a
|
- Document fact that creating a raid5 array really creates a
|
||||||
degraded array with a spare.
|
degraded array with a spare.
|
||||||
|
|
41
Create.c
41
Create.c
|
@ -71,7 +71,7 @@ int Create(char *mddev, int mdfd,
|
||||||
fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
|
fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (level == -10) {
|
if (level == UnSet) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
Name ": a RAID level is needed to create an array.\n");
|
Name ": a RAID level is needed to create an array.\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -81,9 +81,19 @@ int Create(char *mddev, int mdfd,
|
||||||
Name ": a number of --raid-devices must be given to create an array\n");
|
Name ": a number of --raid-devices must be given to create an array\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (raiddisks < 4 && level == 6) {
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": at least 4 raid-devices needed for level 6\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (raiddisks > 256 && level == 6) {
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": no more than 256 raid-devices supported for level 6\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (raiddisks < 2 && level >= 4) {
|
if (raiddisks < 2 && level >= 4) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
Name ": atleast 2 raid-devices needed for level 4 or 5\n");
|
Name ": at least 2 raid-devices needed for level 4 or 5\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (raiddisks+sparedisks > MD_SB_DISKS) {
|
if (raiddisks+sparedisks > MD_SB_DISKS) {
|
||||||
|
@ -102,12 +112,13 @@ int Create(char *mddev, int mdfd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now set some defaults */
|
/* now set some defaults */
|
||||||
if (layout == -1)
|
if (layout == UnSet)
|
||||||
switch(level) {
|
switch(level) {
|
||||||
default: /* no layout */
|
default: /* no layout */
|
||||||
layout = 0;
|
layout = 0;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
|
case 6:
|
||||||
layout = map_name(r5layout, "default");
|
layout = map_name(r5layout, "default");
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -118,6 +129,7 @@ int Create(char *mddev, int mdfd,
|
||||||
switch(level) {
|
switch(level) {
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
|
case 6:
|
||||||
case 0:
|
case 0:
|
||||||
case -1: /* linear */
|
case -1: /* linear */
|
||||||
if (chunk == 0) {
|
if (chunk == 0) {
|
||||||
|
@ -229,12 +241,19 @@ int Create(char *mddev, int mdfd,
|
||||||
|
|
||||||
/* If this is raid5, we want to configure the last active slot
|
/* If this is raid5, we want to configure the last active slot
|
||||||
* as missing, so that a reconstruct happens (faster than re-parity)
|
* as missing, so that a reconstruct happens (faster than re-parity)
|
||||||
|
* FIX: Can we do this for raid6 as well?
|
||||||
*/
|
*/
|
||||||
if (force == 0 && level == 5 && first_missing >= raiddisks) {
|
if (force == 0 && first_missing >= raiddisks) {
|
||||||
insert_point = raiddisks-1;
|
switch ( level ) {
|
||||||
sparedisks++;
|
case 5:
|
||||||
array.active_disks--;
|
insert_point = raiddisks-1;
|
||||||
missing_disks++;
|
sparedisks++;
|
||||||
|
array.active_disks--;
|
||||||
|
missing_disks++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok, lets try some ioctls */
|
/* Ok, lets try some ioctls */
|
||||||
|
@ -249,8 +268,10 @@ int Create(char *mddev, int mdfd,
|
||||||
if (fstat(mdfd, &stb)==0)
|
if (fstat(mdfd, &stb)==0)
|
||||||
array.md_minor = MINOR(stb.st_rdev);
|
array.md_minor = MINOR(stb.st_rdev);
|
||||||
array.not_persistent = 0;
|
array.not_persistent = 0;
|
||||||
if (level == 5 && (insert_point < raiddisks || first_missing < raiddisks))
|
/*** FIX: Need to do something about RAID-6 here ***/
|
||||||
array.state = 1; /* clean, but one drive will be missing */
|
if ( (level == 5 || level == 6) &&
|
||||||
|
(insert_point < raiddisks || first_missing < raiddisks) )
|
||||||
|
array.state = 1; /* clean, but one+ drive will be missing */
|
||||||
else
|
else
|
||||||
array.state = 0; /* not clean, but no errors */
|
array.state = 0; /* not clean, but no errors */
|
||||||
|
|
||||||
|
|
15
Detail.c
15
Detail.c
|
@ -142,6 +142,17 @@ int Detail(char *dev, int brief, int test)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
{
|
||||||
|
struct mdstat_ent *ms = mdstat_read();
|
||||||
|
struct mdstat_ent *e;
|
||||||
|
for (e=ms; e; e=e->next)
|
||||||
|
if (e->devnum == array.md_minor) {
|
||||||
|
if (e->percent >= 0)
|
||||||
|
printf(" Rebuild Status : %d%% complete\n\n", e->percent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free_mdstat(ms);
|
||||||
|
}
|
||||||
printf(" Number Major Minor RaidDevice State\n");
|
printf(" Number Major Minor RaidDevice State\n");
|
||||||
}
|
}
|
||||||
for (d= 0; d<MD_SB_DISKS; d++) {
|
for (d= 0; d<MD_SB_DISKS; d++) {
|
||||||
|
@ -189,8 +200,8 @@ int Detail(char *dev, int brief, int test)
|
||||||
int fd = open(dv, O_RDONLY);
|
int fd = open(dv, O_RDONLY);
|
||||||
if (fd >=0 &&
|
if (fd >=0 &&
|
||||||
load_super(fd, &super) ==0 &&
|
load_super(fd, &super) ==0 &&
|
||||||
super.ctime == array.ctime &&
|
(unsigned long)super.ctime == (unsigned long)array.ctime &&
|
||||||
super.level == array.level)
|
(unsigned int)super.level == (unsigned int)array.level)
|
||||||
have_super = 1;
|
have_super = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
|
||||||
if (calc_sb_csum(&super) == super.sb_csum)
|
if (calc_sb_csum(&super) == super.sb_csum)
|
||||||
printf(" Checksum : %x - correct\n", super.sb_csum);
|
printf(" Checksum : %x - correct\n", super.sb_csum);
|
||||||
else
|
else
|
||||||
printf(" Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super));
|
printf(" Checksum : %x - expected %lx\n", super.sb_csum, calc_sb_csum(&super));
|
||||||
if (SparcAdjust) {
|
if (SparcAdjust) {
|
||||||
/* 2.2 sparc put the events in the wrong place
|
/* 2.2 sparc put the events in the wrong place
|
||||||
* So we copy the tail of the superblock
|
* So we copy the tail of the superblock
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -78,6 +78,16 @@ mdadm.klibc : $(SRCS) mdadm.h
|
||||||
rm -f $(OBJS)
|
rm -f $(OBJS)
|
||||||
gcc -nostdinc -iwithprefix include -I$(KLIBC)/klibc/include -I$(KLIBC)/linux/include -I$(KLIBC)/klibc/arch/i386/include -I$(KLIBC)/klibc/include/bits32 $(CFLAGS) $(SRCS)
|
gcc -nostdinc -iwithprefix include -I$(KLIBC)/klibc/include -I$(KLIBC)/linux/include -I$(KLIBC)/klibc/arch/i386/include -I$(KLIBC)/klibc/include/bits32 $(CFLAGS) $(SRCS)
|
||||||
|
|
||||||
|
mdassemble : mdassemble.c Assemble.c config.c dlink.c util.c mdadm.h
|
||||||
|
rm -f $(OBJS)
|
||||||
|
diet gcc -o mdassemble mdassemble.c Assemble.c config.c dlink.c util.c
|
||||||
|
|
||||||
|
# This doesn't work
|
||||||
|
mdassemble.klibc : mdassemble.c Assemble.c config.c dlink.c util.c mdadm.h
|
||||||
|
rm -f $(OBJS)
|
||||||
|
gcc -nostdinc -iwithprefix include -I$(KLIBC)/klibc/include -I$(KLIBC)/linux/include -I$(KLIBC)/klibc/arch/i386/include -I$(KLIBC)/klibc/include/bits32 $(CFLAGS) -o mdassemble mdassemble.c Assemble.c config.c dlink.c util.c
|
||||||
|
|
||||||
|
|
||||||
mdadm.man : mdadm.8
|
mdadm.man : mdadm.8
|
||||||
nroff -man mdadm.8 > mdadm.man
|
nroff -man mdadm.8 > mdadm.man
|
||||||
|
|
||||||
|
|
53
Monitor.c
53
Monitor.c
|
@ -32,6 +32,7 @@
|
||||||
#include "md_u.h"
|
#include "md_u.h"
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/signal.h>
|
#include <sys/signal.h>
|
||||||
|
#include <values.h>
|
||||||
|
|
||||||
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
|
static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ static char *percentalerts[] = {
|
||||||
int Monitor(mddev_dev_t devlist,
|
int Monitor(mddev_dev_t devlist,
|
||||||
char *mailaddr, char *alert_cmd,
|
char *mailaddr, char *alert_cmd,
|
||||||
int period, int daemonise, int scan, int oneshot,
|
int period, int daemonise, int scan, int oneshot,
|
||||||
char *config)
|
char *config, int test)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Every few seconds, scan every md device looking for changes
|
* Every few seconds, scan every md device looking for changes
|
||||||
|
@ -150,7 +151,7 @@ int Monitor(mddev_dev_t devlist,
|
||||||
st->utime = 0;
|
st->utime = 0;
|
||||||
st->next = statelist;
|
st->next = statelist;
|
||||||
st->err = 0;
|
st->err = 0;
|
||||||
st->devnum = -1;
|
st->devnum = MAXINT;
|
||||||
st->percent = -2;
|
st->percent = -2;
|
||||||
st->expected_spares = mdlist->spare_disks;
|
st->expected_spares = mdlist->spare_disks;
|
||||||
if (mdlist->spare_group)
|
if (mdlist->spare_group)
|
||||||
|
@ -169,7 +170,7 @@ int Monitor(mddev_dev_t devlist,
|
||||||
st->utime = 0;
|
st->utime = 0;
|
||||||
st->next = statelist;
|
st->next = statelist;
|
||||||
st->err = 0;
|
st->err = 0;
|
||||||
st->devnum = -1;
|
st->devnum = MAXINT;
|
||||||
st->percent = -2;
|
st->percent = -2;
|
||||||
st->expected_spares = -1;
|
st->expected_spares = -1;
|
||||||
st->spare_group = NULL;
|
st->spare_group = NULL;
|
||||||
|
@ -191,8 +192,10 @@ int Monitor(mddev_dev_t devlist,
|
||||||
struct mdstat_ent *mse;
|
struct mdstat_ent *mse;
|
||||||
char *dev = st->devname;
|
char *dev = st->devname;
|
||||||
int fd;
|
int fd;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (test)
|
||||||
|
alert("TestMessage", dev, NULL, mailaddr, alert_cmd);
|
||||||
fd = open(dev, O_RDONLY);
|
fd = open(dev, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if (!st->err)
|
if (!st->err)
|
||||||
|
@ -221,18 +224,20 @@ int Monitor(mddev_dev_t devlist,
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (st->devnum < 0) {
|
if (st->devnum == MAXINT) {
|
||||||
struct stat stb;
|
struct stat stb;
|
||||||
if (fstat(fd, &stb) == 0 &&
|
if (fstat(fd, &stb) == 0 &&
|
||||||
(S_IFMT&stb.st_mode)==S_IFBLK)
|
(S_IFMT&stb.st_mode)==S_IFBLK) {
|
||||||
st->devnum = MINOR(stb.st_rdev);
|
if (MINOR(stb.st_rdev) == 9)
|
||||||
|
st->devnum = MINOR(stb.st_rdev);
|
||||||
|
else
|
||||||
|
st->devnum = -1- (MINOR(stb.st_rdev)>>6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (mse = mdstat ; mse ; mse=mse->next)
|
for (mse = mdstat ; mse ; mse=mse->next)
|
||||||
if (mse->devnum == st->devnum) {
|
if (mse->devnum == st->devnum)
|
||||||
mse->devnum = -1; /* flag it as "used" */
|
mse->devnum = MAXINT; /* flag it as "used" */
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st->utime == array.utime &&
|
if (st->utime == array.utime &&
|
||||||
st->failed == array.failed_disks &&
|
st->failed == array.failed_disks &&
|
||||||
|
@ -266,6 +271,11 @@ int Monitor(mddev_dev_t devlist,
|
||||||
alert(percentalerts[mse->percent/20],
|
alert(percentalerts[mse->percent/20],
|
||||||
dev, NULL, mailaddr, alert_cmd);
|
dev, NULL, mailaddr, alert_cmd);
|
||||||
|
|
||||||
|
if (mse &&
|
||||||
|
mse->percent == -1 &&
|
||||||
|
st->percent >= 0)
|
||||||
|
alert("RebuildFinished", dev, NULL, mailaddr, alert_cmd);
|
||||||
|
|
||||||
if (mse)
|
if (mse)
|
||||||
st->percent = mse->percent;
|
st->percent = mse->percent;
|
||||||
|
|
||||||
|
@ -285,19 +295,19 @@ int Monitor(mddev_dev_t devlist,
|
||||||
}
|
}
|
||||||
change = newstate ^ st->devstate[i];
|
change = newstate ^ st->devstate[i];
|
||||||
if (st->utime && change && !st->err) {
|
if (st->utime && change && !st->err) {
|
||||||
if (i < array.raid_disks &&
|
if (i < (unsigned)array.raid_disks &&
|
||||||
(((newstate&change)&(1<<MD_DISK_FAULTY)) ||
|
(((newstate&change)&(1<<MD_DISK_FAULTY)) ||
|
||||||
((st->devstate[i]&change)&(1<<MD_DISK_ACTIVE)) ||
|
((st->devstate[i]&change)&(1<<MD_DISK_ACTIVE)) ||
|
||||||
((st->devstate[i]&change)&(1<<MD_DISK_SYNC)))
|
((st->devstate[i]&change)&(1<<MD_DISK_SYNC)))
|
||||||
)
|
)
|
||||||
alert("Fail", dev, dv, mailaddr, alert_cmd);
|
alert("Fail", dev, dv, mailaddr, alert_cmd);
|
||||||
else if (i>=array.raid_disks &&
|
else if (i >= (unsigned)array.raid_disks &&
|
||||||
(disc.major || disc.minor) &&
|
(disc.major || disc.minor) &&
|
||||||
st->devid[i] == MKDEV(disc.major, disc.minor) &&
|
st->devid[i] == MKDEV(disc.major, disc.minor) &&
|
||||||
((newstate&change)&(1<<MD_DISK_FAULTY))
|
((newstate&change)&(1<<MD_DISK_FAULTY))
|
||||||
)
|
)
|
||||||
alert("FailSpare", dev, dv, mailaddr, alert_cmd);
|
alert("FailSpare", dev, dv, mailaddr, alert_cmd);
|
||||||
else if (i < array.raid_disks &&
|
else if (i < (unsigned)array.raid_disks &&
|
||||||
(((st->devstate[i]&change)&(1<<MD_DISK_FAULTY)) ||
|
(((st->devstate[i]&change)&(1<<MD_DISK_FAULTY)) ||
|
||||||
((newstate&change)&(1<<MD_DISK_ACTIVE)) ||
|
((newstate&change)&(1<<MD_DISK_ACTIVE)) ||
|
||||||
((newstate&change)&(1<<MD_DISK_SYNC)))
|
((newstate&change)&(1<<MD_DISK_SYNC)))
|
||||||
|
@ -320,21 +330,32 @@ int Monitor(mddev_dev_t devlist,
|
||||||
if (scan) {
|
if (scan) {
|
||||||
struct mdstat_ent *mse;
|
struct mdstat_ent *mse;
|
||||||
for (mse=mdstat; mse; mse=mse->next)
|
for (mse=mdstat; mse; mse=mse->next)
|
||||||
if (mse->devnum >= 0 &&
|
if (mse->devnum != MAXINT &&
|
||||||
(strcmp(mse->level, "raid1")==0 ||
|
(strcmp(mse->level, "raid1")==0 ||
|
||||||
strcmp(mse->level, "raid5")==0 ||
|
strcmp(mse->level, "raid5")==0 ||
|
||||||
strcmp(mse->level, "multipath")==0)
|
strcmp(mse->level, "multipath")==0)
|
||||||
) {
|
) {
|
||||||
struct state *st = malloc(sizeof *st);
|
struct state *st = malloc(sizeof *st);
|
||||||
|
mdu_array_info_t array;
|
||||||
|
int fd;
|
||||||
if (st == NULL)
|
if (st == NULL)
|
||||||
continue;
|
continue;
|
||||||
st->devname = strdup(get_md_name(mse->devnum));
|
st->devname = strdup(get_md_name(mse->devnum));
|
||||||
|
if ((fd = open(st->devname, O_RDONLY)) < 0 ||
|
||||||
|
ioctl(fd, GET_ARRAY_INFO, &array)< 0) {
|
||||||
|
/* no such array */
|
||||||
|
if (fd >=0) close(fd);
|
||||||
|
free(st->devname);
|
||||||
|
free(st);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
st->utime = 0;
|
st->utime = 0;
|
||||||
st->next = statelist;
|
st->next = statelist;
|
||||||
st->err = 1;
|
st->err = 1;
|
||||||
st->devnum = mse->devnum;
|
st->devnum = mse->devnum;
|
||||||
st->percent = -2;
|
st->percent = -2;
|
||||||
st->spare_group = NULL;
|
st->spare_group = NULL;
|
||||||
|
st->expected_spares = -1;
|
||||||
statelist = st;
|
statelist = st;
|
||||||
alert("NewArray", st->devname, NULL, mailaddr, alert_cmd);
|
alert("NewArray", st->devname, NULL, mailaddr, alert_cmd);
|
||||||
new_found = 1;
|
new_found = 1;
|
||||||
|
@ -395,6 +416,7 @@ int Monitor(mddev_dev_t devlist,
|
||||||
else
|
else
|
||||||
sleep(period);
|
sleep(period);
|
||||||
}
|
}
|
||||||
|
test = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -422,6 +444,7 @@ static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd)
|
||||||
}
|
}
|
||||||
if (mailaddr &&
|
if (mailaddr &&
|
||||||
(strncmp(event, "Fail", 4)==0 ||
|
(strncmp(event, "Fail", 4)==0 ||
|
||||||
|
strncmp(event, "Test", 4)==0 ||
|
||||||
strncmp(event, "Degrade", 7)==0)) {
|
strncmp(event, "Degrade", 7)==0)) {
|
||||||
FILE *mp = popen(Sendmail, "w");
|
FILE *mp = popen(Sendmail, "w");
|
||||||
if (mp) {
|
if (mp) {
|
||||||
|
|
2
Query.c
2
Query.c
|
@ -129,7 +129,7 @@ int Query(char *dev)
|
||||||
if (md_get_version(fd) >= 9000 &&
|
if (md_get_version(fd) >= 9000 &&
|
||||||
ioctl(fd, GET_ARRAY_INFO, &array)>= 0) {
|
ioctl(fd, GET_ARRAY_INFO, &array)>= 0) {
|
||||||
if (ioctl(fd, GET_DISK_INFO, &disc) >= 0 &&
|
if (ioctl(fd, GET_DISK_INFO, &disc) >= 0 &&
|
||||||
MKDEV(disc.major,disc.minor) == stb.st_rdev)
|
MKDEV((unsigned)disc.major,(unsigned)disc.minor) == stb.st_rdev)
|
||||||
activity = "active";
|
activity = "active";
|
||||||
else
|
else
|
||||||
activity = "mismatch";
|
activity = "mismatch";
|
||||||
|
|
19
ReadMe.c
19
ReadMe.c
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#include "mdadm.h"
|
#include "mdadm.h"
|
||||||
|
|
||||||
char Version[] = Name " - v1.4.0 - 29 Oct 2003\n";
|
char Version[] = Name " - v1.5.0 - 22 Jan 2004\n";
|
||||||
/*
|
/*
|
||||||
* File: ReadMe.c
|
* File: ReadMe.c
|
||||||
*
|
*
|
||||||
|
@ -112,7 +112,7 @@ struct option long_options[] = {
|
||||||
/* For create or build: */
|
/* For create or build: */
|
||||||
{"chunk", 1, 0, 'c'},
|
{"chunk", 1, 0, 'c'},
|
||||||
{"rounding", 1, 0, 'c'}, /* for linear, chunk is really a rounding number */
|
{"rounding", 1, 0, 'c'}, /* for linear, chunk is really a rounding number */
|
||||||
{"level", 1, 0, 'l'}, /* 0,1,4,5,linear */
|
{"level", 1, 0, 'l'}, /* 0,1,4,5,6,linear */
|
||||||
{"parity", 1, 0, 'p'}, /* {left,right}-{a,}symmetric */
|
{"parity", 1, 0, 'p'}, /* {left,right}-{a,}symmetric */
|
||||||
{"layout", 1, 0, 'p'},
|
{"layout", 1, 0, 'p'},
|
||||||
{"raid-disks",1, 0, 'n'},
|
{"raid-disks",1, 0, 'n'},
|
||||||
|
@ -205,12 +205,12 @@ char OptionHelp[] =
|
||||||
" For create or build:\n"
|
" For create or build:\n"
|
||||||
" --chunk= -c : chunk size of kibibytes\n"
|
" --chunk= -c : chunk size of kibibytes\n"
|
||||||
" --rounding= : rounding factor for linear array (==chunk size)\n"
|
" --rounding= : rounding factor for linear array (==chunk size)\n"
|
||||||
" --level= -l : raid level: 0,1,4,5,linear,mp. 0 or linear for build\n"
|
" --level= -l : raid level: 0,1,4,5,6,linear,mp. 0 or linear for build\n"
|
||||||
" --parity= -p : raid5 parity algorithm: {left,right}-{,a}symmetric\n"
|
" --parity= -p : raid5/6 parity algorithm: {left,right}-{,a}symmetric\n"
|
||||||
" --layout= : same as --parity\n"
|
" --layout= : same as --parity\n"
|
||||||
" --raid-devices= -n : number of active devices in array\n"
|
" --raid-devices= -n : number of active devices in array\n"
|
||||||
" --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
|
" --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
|
||||||
" --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n"
|
" --size= -z : Size (in K) of each drive in RAID1/4/5/6 - optional\n"
|
||||||
" --force -f : Honour devices as listed on command line. Don't\n"
|
" --force -f : Honour devices as listed on command line. Don't\n"
|
||||||
" : insert a missing drive for RAID5.\n"
|
" : insert a missing drive for RAID5.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -270,12 +270,12 @@ char Help_create[] =
|
||||||
" Options that are valid with --create (-C) are:\n"
|
" Options that are valid with --create (-C) are:\n"
|
||||||
" --chunk= -c : chunk size of kibibytes\n"
|
" --chunk= -c : chunk size of kibibytes\n"
|
||||||
" --rounding= : rounding factor for linear array (==chunk size)\n"
|
" --rounding= : rounding factor for linear array (==chunk size)\n"
|
||||||
" --level= -l : raid level: 0,1,4,5,linear,multipath and synonyms\n"
|
" --level= -l : raid level: 0,1,4,5,6,linear,multipath and synonyms\n"
|
||||||
" --parity= -p : raid5 parity algorithm: {left,right}-{,a}symmetric\n"
|
" --parity= -p : raid5/6 parity algorithm: {left,right}-{,a}symmetric\n"
|
||||||
" --layout= : same as --parity\n"
|
" --layout= : same as --parity\n"
|
||||||
" --raid-devices= -n : number of active devices in array\n"
|
" --raid-devices= -n : number of active devices in array\n"
|
||||||
" --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
|
" --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
|
||||||
" --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n"
|
" --size= -z : Size (in K) of each drive in RAID1/4/5/6 - optional\n"
|
||||||
" --force -f : Honour devices as listed on command line. Don't\n"
|
" --force -f : Honour devices as listed on command line. Don't\n"
|
||||||
" : insert a missing drive for RAID5.\n"
|
" : insert a missing drive for RAID5.\n"
|
||||||
" --run -R : insist of running the array even if not all\n"
|
" --run -R : insist of running the array even if not all\n"
|
||||||
|
@ -410,6 +410,7 @@ char Help_monitor[] =
|
||||||
" --scan -s : find mail-address/program in config file\n"
|
" --scan -s : find mail-address/program in config file\n"
|
||||||
" --daemonise -f : Fork and continue in child, parent exits\n"
|
" --daemonise -f : Fork and continue in child, parent exits\n"
|
||||||
" --oneshot -1 : Check for degraded arrays, then exit\n"
|
" --oneshot -1 : Check for degraded arrays, then exit\n"
|
||||||
|
" --test -t : Generate a TestMessage event against each array at startup\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -480,6 +481,8 @@ mapping_t pers[] = {
|
||||||
{ "5", 5},
|
{ "5", 5},
|
||||||
{ "multipath", -4},
|
{ "multipath", -4},
|
||||||
{ "mp", -4},
|
{ "mp", -4},
|
||||||
|
{ "raid6", 6},
|
||||||
|
{ "6", 6},
|
||||||
{ NULL, 0}
|
{ NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
19
config.c
19
config.c
|
@ -211,12 +211,15 @@ void load_partitions(void)
|
||||||
}
|
}
|
||||||
while (fgets(buf, 1024, f)) {
|
while (fgets(buf, 1024, f)) {
|
||||||
int major, minor;
|
int major, minor;
|
||||||
char *name;
|
char *name, *mp;
|
||||||
buf[1023] = '\0';
|
buf[1023] = '\0';
|
||||||
if (buf[0] != ' ')
|
if (buf[0] != ' ')
|
||||||
continue;
|
continue;
|
||||||
if (sscanf(buf, " %d %d ", &major, &minor) != 2)
|
major = strtoul(buf, &mp, 10);
|
||||||
|
if (mp == buf || *mp != ' ')
|
||||||
continue;
|
continue;
|
||||||
|
minor = strtoul(mp, NULL, 10);
|
||||||
|
|
||||||
name = map_dev(major, minor);
|
name = map_dev(major, minor);
|
||||||
if (name) {
|
if (name) {
|
||||||
struct conf_dev *cd;
|
struct conf_dev *cd;
|
||||||
|
@ -262,10 +265,10 @@ void arrayline(char *line)
|
||||||
mddev_ident_t mi;
|
mddev_ident_t mi;
|
||||||
|
|
||||||
mis.uuid_set = 0;
|
mis.uuid_set = 0;
|
||||||
mis.super_minor = -1;
|
mis.super_minor = UnSet;
|
||||||
mis.level = -10;
|
mis.level = UnSet;
|
||||||
mis.raid_disks = -1;
|
mis.raid_disks = UnSet;
|
||||||
mis.spare_disks = -1;
|
mis.spare_disks = UnSet;
|
||||||
mis.devices = NULL;
|
mis.devices = NULL;
|
||||||
mis.devname = NULL;
|
mis.devname = NULL;
|
||||||
mis.spare_group = NULL;
|
mis.spare_group = NULL;
|
||||||
|
@ -296,7 +299,7 @@ void arrayline(char *line)
|
||||||
if (w[12]==0 || endptr[0]!=0 || mis.super_minor < 0) {
|
if (w[12]==0 || endptr[0]!=0 || mis.super_minor < 0) {
|
||||||
fprintf(stderr, Name ": invalid super-minor number: %s\n",
|
fprintf(stderr, Name ": invalid super-minor number: %s\n",
|
||||||
w);
|
w);
|
||||||
mis.super_minor = -1;
|
mis.super_minor = UnSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (strncasecmp(w, "devices=", 8 ) == 0 ) {
|
} else if (strncasecmp(w, "devices=", 8 ) == 0 ) {
|
||||||
|
@ -450,7 +453,7 @@ mddev_dev_t conf_get_devs(char *conffile)
|
||||||
struct conf_dev *cd;
|
struct conf_dev *cd;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
static mddev_dev_t dlist = NULL;
|
static mddev_dev_t dlist = NULL;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
while (dlist) {
|
while (dlist) {
|
||||||
mddev_dev_t t = dlist;
|
mddev_dev_t t = dlist;
|
||||||
|
|
3
dlink.c
3
dlink.c
|
@ -5,6 +5,9 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef __dietlibc__
|
||||||
|
char *strncpy(char *dest, const char *src, size_t n) __THROW;
|
||||||
|
#endif
|
||||||
#include "dlink.h"
|
#include "dlink.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
60
md.4
60
md.4
|
@ -15,9 +15,12 @@ Array of Independent Devices.
|
||||||
.PP
|
.PP
|
||||||
.B md
|
.B md
|
||||||
supports RAID levels 1 (mirroring) 4 (striped array with parity
|
supports RAID levels 1 (mirroring) 4 (striped array with parity
|
||||||
device) and 5 (striped array with distributed parity information).
|
device), 5 (striped array with distributed parity information) and 6
|
||||||
If a single underlying device fails while using one of these levels,
|
(striped array with distributed dual redundancy information.) If a
|
||||||
the array will continue to function.
|
some number of underlying devices fails while using one of these
|
||||||
|
levels, the array will continue to function; this number is one for
|
||||||
|
RAID levels 4 and 5, two for RAID level 6, and all but one (N-1) for
|
||||||
|
RAID level 1.
|
||||||
.PP
|
.PP
|
||||||
.B md
|
.B md
|
||||||
also supports a number of pseudo RAID (non-redundant) configurations
|
also supports a number of pseudo RAID (non-redundant) configurations
|
||||||
|
@ -140,6 +143,16 @@ parity blocks on different devices so there is less contention.
|
||||||
This also allows more parallelism when reading as read requests are
|
This also allows more parallelism when reading as read requests are
|
||||||
distributed over all the devices in the array instead of all but one.
|
distributed over all the devices in the array instead of all but one.
|
||||||
|
|
||||||
|
.SS RAID6
|
||||||
|
|
||||||
|
RAID6 is similar to RAID5, but can handle the loss of any \fItwo\fP
|
||||||
|
devices without data loss. Accordingly, it requires N+2 drives to
|
||||||
|
store N drives worth of data.
|
||||||
|
|
||||||
|
The performance for RAID6 is slightly lower but comparable to RAID5 in
|
||||||
|
normal mode and single disk failure mode. It is very slow in dual
|
||||||
|
disk failure mode, however.
|
||||||
|
|
||||||
.SS MUTIPATH
|
.SS MUTIPATH
|
||||||
|
|
||||||
MULTIPATH is not really a RAID at all as there is only one real device
|
MULTIPATH is not really a RAID at all as there is only one real device
|
||||||
|
@ -156,7 +169,7 @@ another interface.
|
||||||
|
|
||||||
.SS UNCLEAN SHUTDOWN
|
.SS UNCLEAN SHUTDOWN
|
||||||
|
|
||||||
When changes are made to a RAID1, RAID4, or RAID5 array there is a
|
When changes are made to a RAID1, RAID4, RAID5 or RAID6 array there is a
|
||||||
possibility of inconsistency for short periods of time as each update
|
possibility of inconsistency for short periods of time as each update
|
||||||
requires are least two block to be written to different devices, and
|
requires are least two block to be written to different devices, and
|
||||||
these writes probably wont happen at exactly the same time.
|
these writes probably wont happen at exactly the same time.
|
||||||
|
@ -166,33 +179,32 @@ consistent.
|
||||||
|
|
||||||
To handle this situation, the md driver marks an array as "dirty"
|
To handle this situation, the md driver marks an array as "dirty"
|
||||||
before writing any data to it, and marks it as "clean" when the array
|
before writing any data to it, and marks it as "clean" when the array
|
||||||
is being disabled, e.g. at shutdown.
|
is being disabled, e.g. at shutdown. If the md driver finds an array
|
||||||
If the md driver finds an array to be dirty at startup, it proceeds to
|
to be dirty at startup, it proceeds to correct any possibly
|
||||||
correct any possibly inconsistency. For RAID1, this involves copying
|
inconsistency. For RAID1, this involves copying the contents of the
|
||||||
the contents of the first drive onto all other drives.
|
first drive onto all other drives. For RAID4, RAID5 and RAID6 this
|
||||||
For RAID4 or RAID5 this involves recalculating the parity for each
|
involves recalculating the parity for each stripe and making sure that
|
||||||
stripe and making sure that the parity block has the correct data.
|
the parity block has the correct data. This process, known as
|
||||||
This process, known as "resynchronising" or "resync" is performed in
|
"resynchronising" or "resync" is performed in the background. The
|
||||||
the background. The array can still be used, though possibly with
|
array can still be used, though possibly with reduced performance.
|
||||||
reduced performance.
|
|
||||||
|
|
||||||
If a RAID4 or RAID5 array is degraded (missing one drive) when it is
|
If a RAID4, RAID5 or RAID6 array is degraded (missing at least one
|
||||||
restarted after an unclean shutdown, it cannot recalculate parity, and
|
drive) when it is restarted after an unclean shutdown, it cannot
|
||||||
so it is possible that data might be undetectably corrupted.
|
recalculate parity, and so it is possible that data might be
|
||||||
The 2.4 md driver
|
undetectably corrupted. The 2.4 md driver
|
||||||
.B does not
|
.B does not
|
||||||
alert the operator to this condition. The 2.5 md driver will fail to
|
alert the operator to this condition. The 2.5 md driver will fail to
|
||||||
start an array in this condition without manual intervention.
|
start an array in this condition without manual intervention.
|
||||||
|
|
||||||
.SS RECOVERY
|
.SS RECOVERY
|
||||||
|
|
||||||
If the md driver detects any error on a device in a RAID1, RAID4, or
|
If the md driver detects any error on a device in a RAID1, RAID4,
|
||||||
RAID5 array, it immediately disables that device (marking it as faulty)
|
RAID5 or RAID6 array, it immediately disables that device (marking it
|
||||||
and continues operation on the remaining devices. If there is a spare
|
as faulty) and continues operation on the remaining devices. If there
|
||||||
drive, the driver will start recreating on one of the spare drives the
|
is a spare drive, the driver will start recreating on one of the spare
|
||||||
data what was on that failed drive, either by copying a working drive
|
drives the data what was on that failed drive, either by copying a
|
||||||
in a RAID1 configuration, or by doing calculations with the parity
|
working drive in a RAID1 configuration, or by doing calculations with
|
||||||
block on RAID4 and RAID5.
|
the parity block on RAID4, RAID5 or RAID6.
|
||||||
|
|
||||||
While this recovery process is happening, the md driver will monitor
|
While this recovery process is happening, the md driver will monitor
|
||||||
accesses to the array and will slow down the rate of recovery if other
|
accesses to the array and will slow down the rate of recovery if other
|
||||||
|
|
47
mdadm.8
47
mdadm.8
|
@ -1,5 +1,5 @@
|
||||||
.\" -*- nroff -*-
|
.\" -*- nroff -*-
|
||||||
.TH MDADM 8 "" v1.4.0
|
.TH MDADM 8 "" v1.5.0
|
||||||
.SH NAME
|
.SH NAME
|
||||||
mdadm \- manage MD devices
|
mdadm \- manage MD devices
|
||||||
.I aka
|
.I aka
|
||||||
|
@ -29,6 +29,7 @@ md devices,
|
||||||
(mirroring),
|
(mirroring),
|
||||||
.BR RAID4 ,
|
.BR RAID4 ,
|
||||||
.BR RAID5 ,
|
.BR RAID5 ,
|
||||||
|
.BR RAID6 ,
|
||||||
and
|
and
|
||||||
.BR MULTIPATH .
|
.BR MULTIPATH .
|
||||||
|
|
||||||
|
@ -109,9 +110,9 @@ superblocks, erasing old superblocks and stopping active arrays.
|
||||||
.TP
|
.TP
|
||||||
.B "Follow or Monitor"
|
.B "Follow or Monitor"
|
||||||
Monitor one or more md devices and act on any state changes. This is
|
Monitor one or more md devices and act on any state changes. This is
|
||||||
only meaningful for raid1, raid5 or multipath arrays as only these have
|
only meaningful for raid1, 4, 5, 6 or multipath arrays as
|
||||||
interesting state. raid0 or linear never have missing, spare, or
|
only these have interesting state. raid0 or linear never have
|
||||||
failed drives, so there is nothing to monitor.
|
missing, spare, or failed drives, so there is nothing to monitor.
|
||||||
|
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
|
@ -234,8 +235,8 @@ Specify rounding factor for linear array (==chunk size)
|
||||||
.BR -l ", " --level=
|
.BR -l ", " --level=
|
||||||
Set raid level. When used with
|
Set raid level. When used with
|
||||||
.IR --create ,
|
.IR --create ,
|
||||||
options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid5, 4,
|
options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid4, 4,
|
||||||
raid5, 5, multipath, mp. Obviously some of these are synonymous.
|
raid5, 5, raid6, 6, multipath, mp. Obviously some of these are synonymous.
|
||||||
|
|
||||||
When used with
|
When used with
|
||||||
.IR --build ,
|
.IR --build ,
|
||||||
|
@ -279,7 +280,7 @@ number of spare devices.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR -z ", " --size=
|
.BR -z ", " --size=
|
||||||
Amount (in Kibibytes) of space to use from each drive in RAID1/4/5.
|
Amount (in Kibibytes) of space to use from each drive in RAID1/4/5/6.
|
||||||
This must be a multiple of the chunk size, and must leave about 128Kb
|
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.
|
of space at the end of the drive for the RAID superblock.
|
||||||
If this is not specified
|
If this is not specified
|
||||||
|
@ -465,6 +466,14 @@ events. Running
|
||||||
.in -5
|
.in -5
|
||||||
from a cron script will ensure regular notification of any degraded arrays.
|
from a cron script will ensure regular notification of any degraded arrays.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR -t ", " --test
|
||||||
|
Generate a
|
||||||
|
.B TestMessage
|
||||||
|
alert for every array found at startup. This alert gets mailed and
|
||||||
|
passed to the alert program. This can be used for testing that alert
|
||||||
|
message to get through successfully.
|
||||||
|
|
||||||
.SH ASSEMBLE MODE
|
.SH ASSEMBLE MODE
|
||||||
|
|
||||||
.HP 12
|
.HP 12
|
||||||
|
@ -532,7 +541,7 @@ Normally the array will be started after it is assembled. However if
|
||||||
is not given and insufficient drives were listed to start a complete
|
is not given and insufficient drives were listed to start a complete
|
||||||
(non-degraded) array, then the array is not started (to guard against
|
(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
|
usage errors). To insist that the array be started in this case (as
|
||||||
may work for RAID1 or RAID5), give the
|
may work for RAID1, 4, 5 or 6), give the
|
||||||
.B --run
|
.B --run
|
||||||
flag.
|
flag.
|
||||||
|
|
||||||
|
@ -590,7 +599,7 @@ in place of a device name. This will cause
|
||||||
.B mdadm
|
.B mdadm
|
||||||
to leave the corresponding slot in the array empty.
|
to leave the corresponding slot in the array empty.
|
||||||
For a RAID4 or RAID5 array at most one slot can be
|
For a RAID4 or RAID5 array at most one slot can be
|
||||||
"\fBmissing\fP".
|
"\fBmissing\fP"; for a RAID6 array at most two slots.
|
||||||
For a RAID1 array, only one real device needs to be given. All of the
|
For a RAID1 array, only one real device needs to be given. All of the
|
||||||
others can be
|
others can be
|
||||||
"\fBmissing\fP".
|
"\fBmissing\fP".
|
||||||
|
@ -717,8 +726,8 @@ config file to be examined.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
--stop
|
--stop
|
||||||
This devices should active md arrays which will be deactivated, if
|
The devices should be active md arrays which will be deactivated, as
|
||||||
they are not currently in use.
|
long as they are not currently in use.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
--run
|
--run
|
||||||
|
@ -822,6 +831,11 @@ Where
|
||||||
is 20, 40, 60, or 80, this indicates that rebuild has passed that many
|
is 20, 40, 60, or 80, this indicates that rebuild has passed that many
|
||||||
percentage of the total.
|
percentage of the total.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B RebuildFinished
|
||||||
|
An md array that was rebuilding, isn't any more, either because it
|
||||||
|
finished normally or was aborted.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B Fail
|
.B Fail
|
||||||
An active component device of an array has been marked as faulty.
|
An active component device of an array has been marked as faulty.
|
||||||
|
@ -857,12 +871,19 @@ A spare drive has been moved from one array in a
|
||||||
.B spare-group
|
.B spare-group
|
||||||
to another to allow a failed drive to be replaced.
|
to another to allow a failed drive to be replaced.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B TestMessage
|
||||||
|
An array was found at startup, and the
|
||||||
|
.B --test
|
||||||
|
flag was given.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
Only
|
Only
|
||||||
.B Fail
|
.B Fail ,
|
||||||
|
.B FailSpare ,
|
||||||
|
.B DegradedArray ,
|
||||||
and
|
and
|
||||||
.B FailSpare
|
.B TestMessage
|
||||||
cause Email to be sent. All events cause the program to be run.
|
cause Email to be sent. All events cause the program to be run.
|
||||||
The program is run with two or three arguments, they being the event
|
The program is run with two or three arguments, they being the event
|
||||||
name, the array device and possibly a second device.
|
name, the array device and possibly a second device.
|
||||||
|
|
32
mdadm.c
32
mdadm.c
|
@ -58,8 +58,8 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
int chunk = 0;
|
int chunk = 0;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
int level = -10;
|
int level = UnSet;
|
||||||
int layout = -1;
|
int layout = UnSet;
|
||||||
int raiddisks = 0;
|
int raiddisks = 0;
|
||||||
int sparedisks = 0;
|
int sparedisks = 0;
|
||||||
struct mddev_ident_s ident;
|
struct mddev_ident_s ident;
|
||||||
|
@ -89,9 +89,9 @@ int main(int argc, char *argv[])
|
||||||
int mdfd = -1;
|
int mdfd = -1;
|
||||||
|
|
||||||
ident.uuid_set=0;
|
ident.uuid_set=0;
|
||||||
ident.level = -10;
|
ident.level = UnSet;
|
||||||
ident.raid_disks = -1;
|
ident.raid_disks = UnSet;
|
||||||
ident.super_minor= -1;
|
ident.super_minor= UnSet;
|
||||||
ident.devices=0;
|
ident.devices=0;
|
||||||
|
|
||||||
while ((option_index = -1) ,
|
while ((option_index = -1) ,
|
||||||
|
@ -259,13 +259,13 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
case O(CREATE,'l'):
|
case O(CREATE,'l'):
|
||||||
case O(BUILD,'l'): /* set raid level*/
|
case O(BUILD,'l'): /* set raid level*/
|
||||||
if (level != -10) {
|
if (level != UnSet) {
|
||||||
fprintf(stderr, Name ": raid level may only be set once. "
|
fprintf(stderr, Name ": raid level may only be set once. "
|
||||||
"Second value is %s.\n", optarg);
|
"Second value is %s.\n", optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
level = map_name(pers, optarg);
|
level = map_name(pers, optarg);
|
||||||
if (level == -10) {
|
if (level == UnSet) {
|
||||||
fprintf(stderr, Name ": invalid raid level: %s\n",
|
fprintf(stderr, Name ": invalid raid level: %s\n",
|
||||||
optarg);
|
optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
|
@ -294,13 +294,14 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, Name ": layout not meaningful for %s arrays.\n",
|
fprintf(stderr, Name ": layout not meaningful for %s arrays.\n",
|
||||||
map_num(pers, level));
|
map_num(pers, level));
|
||||||
exit(2);
|
exit(2);
|
||||||
case -10:
|
case UnSet:
|
||||||
fprintf(stderr, Name ": raid level must be given before layout.\n");
|
fprintf(stderr, Name ": raid level must be given before layout.\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
|
case 6:
|
||||||
layout = map_name(r5layout, optarg);
|
layout = map_name(r5layout, optarg);
|
||||||
if (layout==-10) {
|
if (layout==UnSet) {
|
||||||
fprintf(stderr, Name ": layout %s not understood for raid5.\n",
|
fprintf(stderr, Name ": layout %s not understood for raid5.\n",
|
||||||
optarg);
|
optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
|
@ -337,7 +338,7 @@ int main(int argc, char *argv[])
|
||||||
sparedisks, optarg);
|
sparedisks, optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
if (level > -10 && level <= 0 && level >= -1) {
|
if (level != UnSet && level <= 0 && level >= -1) {
|
||||||
fprintf(stderr, Name ": spare-devices setting is incompatible with raid level %d\n",
|
fprintf(stderr, Name ": spare-devices setting is incompatible with raid level %d\n",
|
||||||
level);
|
level);
|
||||||
exit(2);
|
exit(2);
|
||||||
|
@ -372,7 +373,7 @@ int main(int argc, char *argv[])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case O(ASSEMBLE,'m'): /* super-minor for array */
|
case O(ASSEMBLE,'m'): /* super-minor for array */
|
||||||
if (ident.super_minor != -1) {
|
if (ident.super_minor != UnSet) {
|
||||||
fprintf(stderr, Name ": super-minor cannot be set twice. "
|
fprintf(stderr, Name ": super-minor cannot be set twice. "
|
||||||
"Second value: %s.\n", optarg);
|
"Second value: %s.\n", optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
|
@ -455,6 +456,9 @@ int main(int argc, char *argv[])
|
||||||
case O(MONITOR,'1'): /* oneshot */
|
case O(MONITOR,'1'): /* oneshot */
|
||||||
oneshot = 1;
|
oneshot = 1;
|
||||||
continue;
|
continue;
|
||||||
|
case O(MONITOR,'t'): /* test */
|
||||||
|
test = 1;
|
||||||
|
continue;
|
||||||
|
|
||||||
/* now the general management options. Some are applicable
|
/* now the general management options. Some are applicable
|
||||||
* to other modes. None have arguments.
|
* to other modes. None have arguments.
|
||||||
|
@ -563,7 +567,7 @@ int main(int argc, char *argv[])
|
||||||
mdfd = open_mddev(devlist->devname);
|
mdfd = open_mddev(devlist->devname);
|
||||||
if (mdfd < 0)
|
if (mdfd < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
if (ident.super_minor == -2) {
|
if ((int)ident.super_minor == -2) {
|
||||||
struct stat stb;
|
struct stat stb;
|
||||||
fstat(mdfd, &stb);
|
fstat(mdfd, &stb);
|
||||||
ident.super_minor = MINOR(stb.st_rdev);
|
ident.super_minor = MINOR(stb.st_rdev);
|
||||||
|
@ -586,7 +590,7 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
case ASSEMBLE:
|
case ASSEMBLE:
|
||||||
if (devs_found == 1 && ident.uuid_set == 0 &&
|
if (devs_found == 1 && ident.uuid_set == 0 &&
|
||||||
ident.super_minor == -1 && !scan ) {
|
ident.super_minor == UnSet && !scan ) {
|
||||||
/* Only a device has been given, so get details from config file */
|
/* Only a device has been given, so get details from config file */
|
||||||
mddev_ident_t array_ident = conf_get_ident(configfile, devlist->devname);
|
mddev_ident_t array_ident = conf_get_ident(configfile, devlist->devname);
|
||||||
mdfd = open_mddev(devlist->devname);
|
mdfd = open_mddev(devlist->devname);
|
||||||
|
@ -733,7 +737,7 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rv= Monitor(devlist, mailaddr, program,
|
rv= Monitor(devlist, mailaddr, program,
|
||||||
delay?delay:60, daemonise, scan, oneshot, configfile);
|
delay?delay:60, daemonise, scan, oneshot, configfile, test);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit(rv);
|
exit(rv);
|
||||||
|
|
24
mdadm.h
24
mdadm.h
|
@ -29,7 +29,9 @@
|
||||||
|
|
||||||
#define __USE_LARGEFILE64
|
#define __USE_LARGEFILE64
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifndef __dietlibc__
|
||||||
extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -40,6 +42,12 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef __dietlibc__NONO
|
||||||
|
int strncmp(const char *s1, const char *s2, size_t n) __THROW __pure__;
|
||||||
|
char *strncpy(char *dest, const char *src, size_t n) __THROW;
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
/*#include <linux/fs.h> */
|
/*#include <linux/fs.h> */
|
||||||
|
@ -49,7 +57,7 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
|
||||||
#define MD_MAJOR 9
|
#define MD_MAJOR 9
|
||||||
|
|
||||||
#ifndef BLKGETSIZE64
|
#ifndef BLKGETSIZE64
|
||||||
#define BLKGETSIZE64 _IOR(0x12,114,sizeof(__u64)) /* return device size in bytes (u64 *arg) */
|
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,20 +91,21 @@ extern char Version[], Usage[], Help[], OptionHelp[],
|
||||||
* If multiple fields are present, the intersection of all matching
|
* If multiple fields are present, the intersection of all matching
|
||||||
* devices is considered
|
* devices is considered
|
||||||
*/
|
*/
|
||||||
|
#define UnSet (0xfffe)
|
||||||
typedef struct mddev_ident_s {
|
typedef struct mddev_ident_s {
|
||||||
char *devname;
|
char *devname;
|
||||||
|
|
||||||
int uuid_set;
|
int uuid_set;
|
||||||
__u32 uuid[4];
|
__u32 uuid[4];
|
||||||
|
|
||||||
int super_minor; /* -1 if not set */
|
unsigned int super_minor;
|
||||||
|
|
||||||
char *devices; /* comma separated list of device
|
char *devices; /* comma separated list of device
|
||||||
* names with wild cards
|
* names with wild cards
|
||||||
*/
|
*/
|
||||||
int level; /* -10 if not set */
|
int level;
|
||||||
int raid_disks; /* -1 if not set */
|
unsigned int raid_disks;
|
||||||
int spare_disks; /* -1 if not set */
|
unsigned int spare_disks;
|
||||||
char *spare_group;
|
char *spare_group;
|
||||||
struct mddev_ident_s *next;
|
struct mddev_ident_s *next;
|
||||||
} *mddev_ident_t;
|
} *mddev_ident_t;
|
||||||
|
@ -170,7 +179,7 @@ extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust);
|
||||||
extern int Monitor(mddev_dev_t devlist,
|
extern int Monitor(mddev_dev_t devlist,
|
||||||
char *mailaddr, char *alert_cmd,
|
char *mailaddr, char *alert_cmd,
|
||||||
int period, int daemonise, int scan, int oneshot,
|
int period, int daemonise, int scan, int oneshot,
|
||||||
char *config);
|
char *config, int test);
|
||||||
|
|
||||||
extern int Kill(char *dev, int force);
|
extern int Kill(char *dev, int force);
|
||||||
|
|
||||||
|
@ -186,13 +195,14 @@ extern mddev_dev_t conf_get_devs(char *conffile);
|
||||||
extern char *conf_get_mailaddr(char *conffile);
|
extern char *conf_get_mailaddr(char *conffile);
|
||||||
extern char *conf_get_program(char *conffile);
|
extern char *conf_get_program(char *conffile);
|
||||||
extern char *conf_line(FILE *file);
|
extern char *conf_line(FILE *file);
|
||||||
|
extern char *conf_word(FILE *file, int allow_key);
|
||||||
extern void free_line(char *line);
|
extern void free_line(char *line);
|
||||||
extern int match_oneof(char *devices, char *devname);
|
extern int match_oneof(char *devices, char *devname);
|
||||||
extern int load_super(int fd, mdp_super_t *super);
|
extern int load_super(int fd, mdp_super_t *super);
|
||||||
extern void uuid_from_super(int uuid[4], mdp_super_t *super);
|
extern void uuid_from_super(int uuid[4], mdp_super_t *super);
|
||||||
extern int same_uuid(int a[4], int b[4]);
|
extern int same_uuid(int a[4], int b[4]);
|
||||||
extern int compare_super(mdp_super_t *first, mdp_super_t *second);
|
extern int compare_super(mdp_super_t *first, mdp_super_t *second);
|
||||||
extern int calc_sb_csum(mdp_super_t *super);
|
extern unsigned long calc_sb_csum(mdp_super_t *super);
|
||||||
extern int store_super(int fd, mdp_super_t *super);
|
extern int store_super(int fd, mdp_super_t *super);
|
||||||
extern int enough(int level, int raid_disks, int avail_disks);
|
extern int enough(int level, int raid_disks, int avail_disks);
|
||||||
extern int ask(char *mesg);
|
extern int ask(char *mesg);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Summary: mdadm is used for controlling Linux md devices (aka RAID arrays)
|
Summary: mdadm is used for controlling Linux md devices (aka RAID arrays)
|
||||||
Name: mdadm
|
Name: mdadm
|
||||||
Version: 1.4.0
|
Version: 1.5.0
|
||||||
Release: 1
|
Release: 1
|
||||||
Source: http://www.cse.unsw.edu.au/~neilb/source/mdadm/mdadm-%{version}.tgz
|
Source: http://www.cse.unsw.edu.au/~neilb/source/mdadm/mdadm-%{version}.tgz
|
||||||
URL: http://www.cse.unsw.edu.au/~neilb/source/mdadm/
|
URL: http://www.cse.unsw.edu.au/~neilb/source/mdadm/
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* mdassemble - assemble Linux "md" devices aka RAID arrays.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||||
|
* Copyright (C) 2003 Luca Berra <bluca@vodka.it>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Neil Brown
|
||||||
|
* Email: <neilb@cse.unsw.edu.au>
|
||||||
|
* Paper: Neil Brown
|
||||||
|
* School of Computer Science and Engineering
|
||||||
|
* The University of New South Wales
|
||||||
|
* Sydney, 2052
|
||||||
|
* Australia
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mdadm.h"
|
||||||
|
#include "md_p.h"
|
||||||
|
|
||||||
|
/* from readme.c */
|
||||||
|
mapping_t pers[] = {
|
||||||
|
{ "linear", -1},
|
||||||
|
{ "raid0", 0},
|
||||||
|
{ "0", 0},
|
||||||
|
{ "stripe", 0},
|
||||||
|
{ "raid1", 1},
|
||||||
|
{ "1", 1},
|
||||||
|
{ "mirror", 1},
|
||||||
|
{ "raid4", 4},
|
||||||
|
{ "4", 4},
|
||||||
|
{ "raid5", 5},
|
||||||
|
{ "5", 5},
|
||||||
|
{ "multipath", -4},
|
||||||
|
{ "mp", -4},
|
||||||
|
{ NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* from mdadm.c */
|
||||||
|
int open_mddev(char *dev)
|
||||||
|
{
|
||||||
|
int mdfd = open(dev, O_RDWR, 0);
|
||||||
|
if (mdfd < 0)
|
||||||
|
fprintf(stderr, Name ": error opening %s: %s\n",
|
||||||
|
dev, strerror(errno));
|
||||||
|
else if (md_get_version(mdfd) <= 0) {
|
||||||
|
fprintf(stderr, Name ": %s does not appear to be an md device\n",
|
||||||
|
dev);
|
||||||
|
close(mdfd);
|
||||||
|
mdfd = -1;
|
||||||
|
}
|
||||||
|
return mdfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *configfile = NULL;
|
||||||
|
int rv;
|
||||||
|
int mdfd = -1;
|
||||||
|
int runstop = 0;
|
||||||
|
int readonly = 0;
|
||||||
|
int verbose = 0;
|
||||||
|
int force = 0;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
mddev_ident_t array_list = conf_get_ident(configfile, NULL);
|
||||||
|
if (!array_list) {
|
||||||
|
fprintf(stderr, Name ": No arrays found in config file\n");
|
||||||
|
rv = 1;
|
||||||
|
} else
|
||||||
|
for (; array_list; array_list = array_list->next) {
|
||||||
|
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,
|
||||||
|
NULL,
|
||||||
|
readonly, runstop, NULL, verbose, force);
|
||||||
|
}
|
||||||
|
}
|
17
mdstat.c
17
mdstat.c
|
@ -114,6 +114,8 @@ struct mdstat_ent *mdstat_read()
|
||||||
for (; (line = conf_line(f)) ; free_line(line)) {
|
for (; (line = conf_line(f)) ; free_line(line)) {
|
||||||
struct mdstat_ent *ent;
|
struct mdstat_ent *ent;
|
||||||
char *w;
|
char *w;
|
||||||
|
int devnum;
|
||||||
|
char *ep;
|
||||||
|
|
||||||
if (strcmp(line, "Personalities")==0)
|
if (strcmp(line, "Personalities")==0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -122,9 +124,16 @@ struct mdstat_ent *mdstat_read()
|
||||||
if (strcmp(line, "unused")==0)
|
if (strcmp(line, "unused")==0)
|
||||||
continue;
|
continue;
|
||||||
/* Better be an md line.. */
|
/* Better be an md line.. */
|
||||||
if (strncmp(line, "md", 2)!= 0
|
if (strncmp(line, "md", 2)!= 0)
|
||||||
|| atoi(line+2)<0) {
|
continue;
|
||||||
fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line);
|
if (strncmp(line, "md_d", 4) == 0)
|
||||||
|
devnum = -1-strtoul(line+4, &ep, 10);
|
||||||
|
else if (strncmp(line, "md", 2) == 0)
|
||||||
|
devnum = strtoul(line+2, &ep, 10);
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (ep == NULL || *ep ) {
|
||||||
|
/* fprintf(stderr, Name ": bad /proc/mdstat line starts: %s\n", line); */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +150,7 @@ struct mdstat_ent *mdstat_read()
|
||||||
ent->active = -1;
|
ent->active = -1;
|
||||||
|
|
||||||
ent->dev = strdup(line);
|
ent->dev = strdup(line);
|
||||||
ent->devnum = atoi(line+2);
|
ent->devnum = devnum;
|
||||||
|
|
||||||
for (w=dl_next(line); w!= line ; w=dl_next(w)) {
|
for (w=dl_next(line); w!= line ; w=dl_next(w)) {
|
||||||
int l = strlen(w);
|
int l = strlen(w);
|
||||||
|
|
85
util.c
85
util.c
|
@ -30,6 +30,7 @@
|
||||||
#include "mdadm.h"
|
#include "mdadm.h"
|
||||||
#include "md_p.h"
|
#include "md_p.h"
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a 128 bit uuid in 4 integers
|
* Parse a 128 bit uuid in 4 integers
|
||||||
|
@ -102,12 +103,18 @@ int md_get_version(int fd)
|
||||||
int get_linux_version()
|
int get_linux_version()
|
||||||
{
|
{
|
||||||
struct utsname name;
|
struct utsname name;
|
||||||
|
char *cp;
|
||||||
int a,b,c;
|
int a,b,c;
|
||||||
if (uname(&name) <0)
|
if (uname(&name) <0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (sscanf(name.release, "%d.%d.%d", &a,&b,&c)!= 3)
|
cp = name.release;
|
||||||
return -1;
|
a = strtoul(cp, &cp, 10);
|
||||||
|
if (*cp != '.') return -1;
|
||||||
|
b = strtoul(cp+1, &cp, 10);
|
||||||
|
if (*cp != '.') return -1;
|
||||||
|
c = strtoul(cp+1, NULL, 10);
|
||||||
|
|
||||||
return (a*1000000)+(b*1000)+c;
|
return (a*1000000)+(b*1000)+c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +131,8 @@ int enough(int level, int raid_disks, int avail_disks)
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
return avail_disks >= raid_disks-1;
|
return avail_disks >= raid_disks-1;
|
||||||
|
case 6:
|
||||||
|
return avail_disks >= raid_disks-2;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +372,7 @@ int map_name(mapping_t *map, char *name)
|
||||||
return map->num;
|
return map->num;
|
||||||
map++;
|
map++;
|
||||||
}
|
}
|
||||||
return -10;
|
return UnSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -392,7 +401,11 @@ char *map_dev(int major, int minor)
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __dietlibc__
|
||||||
int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
|
int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
|
||||||
|
#else
|
||||||
|
int add_dev(const char *name, const struct stat *stb, int flag)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if ((stb->st_mode&S_IFMT)== S_IFBLK) {
|
if ((stb->st_mode&S_IFMT)== S_IFBLK) {
|
||||||
char *n = strdup(name);
|
char *n = strdup(name);
|
||||||
|
@ -412,7 +425,11 @@ char *map_dev(int major, int minor)
|
||||||
{
|
{
|
||||||
struct devmap *p;
|
struct devmap *p;
|
||||||
if (!devlist_ready) {
|
if (!devlist_ready) {
|
||||||
|
#ifndef __dietlibc__
|
||||||
nftw("/dev", add_dev, 10, FTW_PHYS);
|
nftw("/dev", add_dev, 10, FTW_PHYS);
|
||||||
|
#else
|
||||||
|
ftw("/dev", add_dev, 10);
|
||||||
|
#endif
|
||||||
devlist_ready=1;
|
devlist_ready=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +442,7 @@ char *map_dev(int major, int minor)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int calc_sb_csum(mdp_super_t *super)
|
unsigned long calc_sb_csum(mdp_super_t *super)
|
||||||
{
|
{
|
||||||
unsigned int oldcsum = super->sb_csum;
|
unsigned int oldcsum = super->sb_csum;
|
||||||
unsigned long long newcsum = 0;
|
unsigned long long newcsum = 0;
|
||||||
|
@ -487,27 +504,63 @@ char *human_size_brief(long long bytes)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mdp_major = -1;
|
||||||
|
void get_mdp_major(void)
|
||||||
|
{
|
||||||
|
FILE *fl = fopen("/proc/devices", "r");
|
||||||
|
char *w;
|
||||||
|
int have_block = 0;
|
||||||
|
int have_devices = 0;
|
||||||
|
int last_num = -1;
|
||||||
|
if (!fl)
|
||||||
|
return;
|
||||||
|
while ((w = conf_word(fl, 1))) {
|
||||||
|
if (have_block && strcmp(w, "devices:")==0)
|
||||||
|
have_devices = 1;
|
||||||
|
have_block = (strcmp(w, "Block")==0);
|
||||||
|
if (isdigit(w[0]))
|
||||||
|
last_num = atoi(w);
|
||||||
|
if (have_devices && strcmp(w, "mdp")==0)
|
||||||
|
mdp_major = last_num;
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
fclose(fl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MD_MAJOR 9
|
|
||||||
char *get_md_name(int dev)
|
char *get_md_name(int dev)
|
||||||
{
|
{
|
||||||
/* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
|
/* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
|
||||||
|
/* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */
|
||||||
static char devname[50];
|
static char devname[50];
|
||||||
struct stat stb;
|
struct stat stb;
|
||||||
dev_t rdev = MKDEV(MD_MAJOR, dev);
|
dev_t rdev;
|
||||||
|
|
||||||
sprintf(devname, "/dev/md%d", dev);
|
if (dev < 0) {
|
||||||
if (stat(devname, &stb) == 0
|
|
||||||
&& (S_IFMT&stb.st_mode) == S_IFBLK
|
|
||||||
&& (stb.st_rdev == rdev))
|
|
||||||
return devname;
|
|
||||||
|
|
||||||
sprintf(devname, "/dev/md/%d", dev);
|
if (mdp_major < 0) get_mdp_major();
|
||||||
if (stat(devname, &stb) == 0
|
if (mdp_major < 0) return NULL;
|
||||||
&& (S_IFMT&stb.st_mode) == S_IFBLK
|
rdev = MKDEV(mdp_major, (-1-dev)<<6);
|
||||||
&& (stb.st_rdev == rdev))
|
sprintf(devname, "/dev/md/d%d", -1-dev);
|
||||||
return devname;
|
if (stat(devname, &stb) == 0
|
||||||
|
&& (S_IFMT&stb.st_mode) == S_IFBLK
|
||||||
|
&& (stb.st_rdev == rdev))
|
||||||
|
return devname;
|
||||||
|
} else {
|
||||||
|
rdev = MKDEV(MD_MAJOR, dev);
|
||||||
|
sprintf(devname, "/dev/md%d", dev);
|
||||||
|
if (stat(devname, &stb) == 0
|
||||||
|
&& (S_IFMT&stb.st_mode) == S_IFBLK
|
||||||
|
&& (stb.st_rdev == rdev))
|
||||||
|
return devname;
|
||||||
|
|
||||||
|
sprintf(devname, "/dev/md/%d", dev);
|
||||||
|
if (stat(devname, &stb) == 0
|
||||||
|
&& (S_IFMT&stb.st_mode) == S_IFBLK
|
||||||
|
&& (stb.st_rdev == rdev))
|
||||||
|
return devname;
|
||||||
|
}
|
||||||
sprintf(devname, "/dev/.tmp.md%d", dev);
|
sprintf(devname, "/dev/.tmp.md%d", dev);
|
||||||
if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
|
if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in New Issue