mdadm-1.4.0 mdadm-1.4.0
authorNeil Brown <neilb@suse.de>
Tue, 28 Oct 2003 23:20:01 +0000 (23:20 +0000)
committerNeil Brown <neilb@suse.de>
Tue, 28 Oct 2003 23:20:01 +0000 (23:20 +0000)
13 files changed:
ANNOUNCE-1.4.0 [new file with mode: 0644]
Assemble.c
ChangeLog
Detail.c
Examine.c
Makefile
Monitor.c
ReadMe.c
config.c
mdadm.8
mdadm.c
mdadm.h
mdadm.spec

diff --git a/ANNOUNCE-1.4.0 b/ANNOUNCE-1.4.0
new file mode 100644 (file)
index 0000000..22d8952
--- /dev/null
@@ -0,0 +1,29 @@
+Subject:  ANNOUNCE: mdadm 1.4.0 - A tools for managing Soft RAID under Linux
+
+
+I am pleased to announce the availability of 
+   mdadm version 1.4.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.4.0 adds:
+    SparesMissing event in --monitor mode if a number of spares is declared
+       in mdadm.conf, but that number of spares isn't found.
+    --update=summaries option for --assemble mode to update some summary information
+        in the superblock
+    --test option for --detail to get a useful exit status.
+
+Development of mdadm is sponsored by CSE@UNSW: 
+  The School of Computer Science and Engineering
+at
+  The University of New South Wales
+
+NeilBrown  29 Oct 2003
index cddb76f..794b00d 100644 (file)
@@ -292,6 +292,33 @@ int Assemble(char *mddev, int mdfd,
                                        fprintf(stderr, Name ": updating superblock of %s with minor number %d\n",
                                                devname, super.md_minor);
                        }
+                       if (strcmp(update, "summaries") == 0) {
+                               /* set nr_disks, active_disks, working_disks,
+                                * failed_disks, spare_disks based on disks[] 
+                                * array in superblock.
+                                * Also make sure extra slots aren't 'failed'
+                                */
+                               super.nr_disks = super.active_disks =
+                                       super.working_disks = super.failed_disks =
+                                       super.spare_disks = 0;
+                               for (i=0; i < MD_SB_DISKS ; i++) 
+                                       if (super.disks[i].major ||
+                                           super.disks[i].minor) {
+                                               int state = super.disks[i].state;
+                                               if (state & (1<<MD_DISK_REMOVED))
+                                                       continue;
+                                               super.nr_disks++;
+                                               if (state & (1<<MD_DISK_ACTIVE))
+                                                       super.active_disks++;
+                                               if (state & (1<<MD_DISK_FAULTY))
+                                                       super.failed_disks++;
+                                               else
+                                                       super.working_disks++;
+                                               if (state == 0)
+                                                       super.spare_disks++;
+                                       } else if (i >= super.raid_disks && super.disks[i].number == 0)
+                                               super.disks[i].state = 0;
+                       }
                        super.sb_csum = calc_sb_csum(&super);
                        dfd = open(devname, O_RDWR, 0);
                        if (dfd < 0) 
index 73dd5af..6cfea5b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Changes Prior to 1.4.0 release
+    -   Document fact that creating a raid5 array really creates a
+        degraded array with a spare.   
+    -   Add "spares=" tag to config file and generate it wit --detail and
+        --examine
+    -   Add "SparesMissing" event when --monitor first sees an array and
+       it doesn't have the enough spare devices.
+    -   Add --update=summaries for --assemble to update summary
+        information in superblock, and correct other inconsistancies in
+       the superblock.
+    -   Add --test option to --detail to set a meaningful exit status.
+       
 Changes Prior to 1.3.0 release
     -   Make 'size' and unsigned long in Create to allow creation of
         larger arrays.
index 9b04efd..d508988 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -31,7 +31,7 @@
 #include       "md_p.h"
 #include       "md_u.h"
 
-int Detail(char *dev, int brief)
+int Detail(char *dev, int brief, int test)
 {
        /*
         * Print out details for an md array by using
@@ -45,27 +45,29 @@ int Detail(char *dev, int brief)
        time_t atime;
        char *c;
        char *devices = NULL;
+       int spares = 0;
 
        mdp_super_t super;
        int have_super = 0;
+       int rv = test ? 4 : 1;
 
        if (fd < 0) {
                fprintf(stderr, Name ": cannot open %s: %s\n",
                        dev, strerror(errno));
-               return 1;
+               return rv;
        }
        vers = md_get_version(fd);
        if (vers < 0) {
                fprintf(stderr, Name ": %s does not appear to be an md device\n",
                        dev);
                close(fd);
-               return 1;
+               return rv;
        }
        if (vers < 9000) {
                fprintf(stderr, Name ": cannot get detail for md device %s: driver version too old.\n",
                        dev);
                close(fd);
-               return 1;
+               return rv;
        }
        if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
                if (errno == ENODEV)
@@ -75,8 +77,9 @@ int Detail(char *dev, int brief)
                        fprintf(stderr, Name ": cannot get array detail for %s: %s\n",
                                dev, strerror(errno));
                close(fd);
-               return 1;
+               return rv;
        }
+       rv = 0;
        /* Ok, we have some info to print... */
        c = map_num(pers, array.level);
        if (brief) 
@@ -162,7 +165,12 @@ int Detail(char *dev, int brief)
                        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 (disk.state == 0) printf(" spare");
+                       if (disk.state == 0) { printf(" spare"); spares++; }
+               }
+               if (test && d < array.raid_disks && disk.state & (1<<MD_DISK_FAULTY)) {
+                       if ((rv & 1) && (array.level ==4 || array.level == 5))
+                               rv |= 2;
+                       rv |= 1;
                }
                if ((dv=map_dev(disk.major, disk.minor))) {
                        if (brief) {
@@ -188,6 +196,7 @@ int Detail(char *dev, int brief)
                }
                if (!brief) printf("\n");
        }
+       if (spares && brief) printf(" spares=%d", spares);
        if (have_super) {
                if (brief) printf(" UUID=");
                else printf("           UUID : ");
@@ -201,5 +210,6 @@ int Detail(char *dev, int brief)
        }
        if (brief && devices) printf("\n   devices=%s", devices);
        if (brief) printf("\n");
-       return 0;
+       if (test && (rv&2)) rv &= ~1;
+       return rv;
 }
index 6263866..983f90a 100644 (file)
--- a/Examine.c
+++ b/Examine.c
@@ -60,6 +60,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
        char *c;
        int rv = 0;
        int err;
+       int spares = 0;
 
        struct array {
                mdp_super_t super;
@@ -205,7 +206,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
                                if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
                                if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
                                if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
-                               if (dp->state == 0) printf(" spare");
+                               if (dp->state == 0) { printf(" spare"); spares++; }
                                if ((dv=map_dev(dp->major, dp->minor)))
                                        printf("   %s", dv);
                                printf("\n");
@@ -237,6 +238,7 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
                        char *d;
                        printf("ARRAY /dev/md%d level=%s num-devices=%d UUID=",
                               ap->super.md_minor, c?c:"-unknown-", ap->super.raid_disks);
+                       if (spares) printf(" spares=%d", spares);
                        if (ap->super.minor_version >= 90)
                                printf("%08x:%08x:%08x:%08x", ap->super.set_uuid0, ap->super.set_uuid1,
                                       ap->super.set_uuid2, ap->super.set_uuid3);
index 986c979..6cbe0b0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -96,7 +96,7 @@ install : mdadm mdadm.8 md.4 mdadm.conf.5
        $(INSTALL) -D -m 644 mdadm.conf.5 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5
 
 clean : 
-       rm -f mdadm $(OBJS) core *.man mdadm.tcc mdadm.uclibc mdadm.static *.orig *.porig *.rej
+       rm -f mdadm $(OBJS) core *.man mdadm.tcc mdadm.uclibc mdadm.static *.orig *.porig *.rej *.alt
 
 dist : clean
        ./makedist
index 3bc3263..826eaa7 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -97,6 +97,7 @@ int Monitor(mddev_dev_t devlist,
                int err;
                char *spare_group;
                int active, working, failed, spare, raid;
+               int expected_spares;
                int devstate[MD_SB_DISKS];
                int devid[MD_SB_DISKS];
                int percent;
@@ -151,6 +152,7 @@ int Monitor(mddev_dev_t devlist,
                        st->err = 0;
                        st->devnum = -1;
                        st->percent = -2;
+                       st->expected_spares = mdlist->spare_disks;
                        if (mdlist->spare_group)
                                st->spare_group = strdup(mdlist->spare_group);
                        else
@@ -169,6 +171,7 @@ int Monitor(mddev_dev_t devlist,
                        st->err = 0;
                        st->devnum = -1;
                        st->percent = -2;
+                       st->expected_spares = -1;
                        st->spare_group = NULL;
                        statelist = st;
                }
@@ -248,6 +251,10 @@ int Monitor(mddev_dev_t devlist,
                                )
                                alert("DegradedArray", dev, NULL, mailaddr, alert_cmd);
 
+                       if (st->utime == 0 && /* new array */
+                           st->expected_spares > 0 && 
+                           array.spare_disks < st->expected_spares) 
+                               alert("SparesMissing", dev, NULL, mailaddr, alert_cmd);
                        if (mse &&
                            st->percent == -1 && 
                            mse->percent >= 0)
index 830a3b3..579a1a8 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -29,7 +29,7 @@
 
 #include "mdadm.h"
 
-char Version[] = Name " - v1.3.0 - 29 Jul 2003\n";
+char Version[] = Name " - v1.4.0 - 29 Oct 2003\n";
 /*
  * File: ReadMe.c
  *
@@ -86,7 +86,7 @@ char Version[] = Name " - v1.3.0 - 29 Jul 2003\n";
  *     This mode never exits but just monitors arrays and reports changes.
  */
 
-char short_options[]="-ABCDEFGQhVvbc:l:p:m:n:x:u:c:d:z:U:sarfRSow1";
+char short_options[]="-ABCDEFGQhVvbc:l:p:m:n:x:u:c:d:z:U:sarfRSow1t";
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
     {"misc",      0, 0, '#'},
@@ -141,6 +141,7 @@ struct option long_options[] = {
     /* For Detail/Examine */
     {"brief",    0, 0, 'b'},
     {"sparc2.2",  0, 0, 22},
+    {"test",      0, 0, 't'},
 
     /* For Follow/monitor */
     {"mail",      1, 0, 'm'},
@@ -221,7 +222,7 @@ char OptionHelp[] =
 "  --config=     -c   : config file\n"
 "  --scan        -s   : scan config file for missing information\n"
 "  --force       -f   : Assemble the array even if some superblocks appear out-of-date\n"
-"  --update=     -U   : Update superblock: either sparc2.2 or super-minor\n"
+"  --update=     -U   : Update superblock: one of sparc2.2, super-minor or summaries\n"
 "\n"
 " For detail or examine:\n"
 "  --brief       -b   : Just print device name and UUID\n"
@@ -344,7 +345,7 @@ char Help_assemble[] =
 "                       for a full array are present\n"
 "  --force       -f   : Assemble the array even if some superblocks appear\n"
 "                     : out-of-date.  This involves modifying the superblocks.\n"
-"  --update=     -U   : Update superblock: either sparc2.2 or super-minor\n"
+"  --update=     -U   : Update superblock: one of sparc2.2, super-minor or summaries\n"
 ;
 
 char Help_manage[] =
@@ -385,6 +386,7 @@ char Help_misc[] =
 "  --stop        -S   : deactivate array, releasing all resources\n"
 "  --readonly    -o   : mark array as readonly\n"
 "  --readwrite   -w   : mark array as readwrite\n"
+"  --test        -t   : exit status 0 if ok, 1 if degrade, 2 if dead, 4 if missing\n"
 ;
 
 char Help_monitor[] =
index 68b453c..f02697e 100644 (file)
--- a/config.c
+++ b/config.c
@@ -265,6 +265,7 @@ void arrayline(char *line)
        mis.super_minor = -1;
        mis.level = -10;
        mis.raid_disks = -1;
+       mis.spare_disks = -1;
        mis.devices = NULL;
        mis.devname = NULL;
        mis.spare_group = NULL;
@@ -315,10 +316,13 @@ void arrayline(char *line)
                        mis.level = map_name(pers, w+6);
                } else if (strncasecmp(w, "disks=", 6) == 0 ) {
                        /* again, for compat */
-                       mis.raid_disks = atoi(w+6);                        
+                       mis.raid_disks = atoi(w+6);
                } else if (strncasecmp(w, "num-devices=", 12) == 0 ) {
                        /* again, for compat */
-                       mis.raid_disks = atoi(w+12);                       
+                       mis.raid_disks = atoi(w+12);
+               } else if (strncasecmp(w, "spares=", 7) == 0 ) {
+                       /* for warning if not all spares present */
+                       mis.spare_disks = atoi(w+7);
                } else {
                        fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
                                w);
diff --git a/mdadm.8 b/mdadm.8
index c9d164d..abe843e 100644 (file)
--- a/mdadm.8
+++ b/mdadm.8
@@ -1,5 +1,5 @@
 .\" -*- nroff -*-
-.TH MDADM 8 "" v1.3.0
+.TH MDADM 8 "" v1.4.0
 .SH NAME
 mdadm \- manage MD devices
 .I aka
@@ -328,8 +328,9 @@ an attempt will be made to start it anyway.
 .TP
 .BR -U ", " --update=
 Update the superblock on each device while assembling the array.  The
-argument given to this flag can be either
-.B sparc2.2
+argument given to this flag can be one of
+.BR sparc2.2 ,
+.BR summaries ,
 or
 .BR super-minor .
 
@@ -348,9 +349,13 @@ The
 option will update the
 .B "prefered minor"
 field on each superblock to match the minor number of the array being
-assembled.  This is not need on 2.6 and later kernels as they make
+assembled.  This is not needed on 2.6 and later kernels as they make
 this adjustment automatically.
 
+The
+.B summaries
+option will correct the summaries in the superblock. That is the
+counts of total, working, active, failed, and spare devices.
 
 .SH For Manage mode:
 
@@ -412,6 +417,14 @@ over-written with zeros.  With
 the block where the superblock would be is over-written even if it
 doesn't appear to be valid.
 
+.TP
+.BR -t ", " --test
+When used with
+.BR --detail ,
+the exit status of
+.I mdadm
+is set to reflect the status of the device.
+
 .SH For Monitor mode:
 .TP
 .BR -m ", " --mail
@@ -582,6 +595,15 @@ For a RAID1 array, only one real device needs to be given.  All of the
 others can be
 "\fBmissing\fP".
 
+When creating a RAID5 array,
+.B mdadm
+will automatically create a degraded array with an extra spare drive.
+This is because building the spare into a degraded array is in general faster than resyncing
+the parity on a non-degraded, but not clean, array.  This feature can
+be over-ridden with the
+-I --force
+option.
+
 '''If the 
 '''.B --size
 '''option is given, it is not necessary to list any component-devices in this command.
@@ -651,6 +673,28 @@ or
 will cause the output to be less detailed and the format to be
 suitable for inclusion in
 .BR /etc/mdadm.conf .
+The exit status of
+.I mdadm
+will normally be 0 unless
+.I mdadm
+failed to get useful information about the device(s).  However if the
+.B --test
+option is given, then the exit status will be:
+.RS
+.TP
+0
+The array is functioning normally.
+.TP
+1
+The array has at least one failed device.
+.TP
+2
+The array has multiple failed devices and hence is unusable (raid4 or
+raid5).
+.TP
+4
+There was an error while trying to get information about the device.
+.RE
 
 .TP
 --examine
diff --git a/mdadm.c b/mdadm.c
index f5da6fa..22c6835 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -78,6 +78,7 @@ int main(int argc, char *argv[])
        int verbose = 0;
        int brief = 0;
        int force = 0;
+       int test = 0;
 
        char *mailaddr = NULL;
        char *program = NULL;
@@ -397,7 +398,9 @@ int main(int argc, char *argv[])
                        if (strcmp(update, "sparc2.2")==0) continue;
                        if (strcmp(update, "super-minor") == 0)
                                continue;
-                       fprintf(stderr, Name ": '--update %s' invalid.  Only 'sparc2.2' or 'super-minor' supported\n",update);
+                       if (strcmp(update, "summaries")==0)
+                               continue;
+                       fprintf(stderr, Name ": '--update %s' invalid.  Only 'sparc2.2', 'super-minor' or 'summaries' supported\n",update);
                        exit(2);
 
                case O(ASSEMBLE,'c'): /* config file */
@@ -517,6 +520,9 @@ int main(int argc, char *argv[])
                        }
                        devmode = opt;
                        continue;
+               case O(MISC,'t'):
+                       test = 1;
+                       continue;
 
                case O(MISC, 22):
                        if (devmode != 'E') {
@@ -683,7 +689,7 @@ int main(int argc, char *argv[])
                                                        continue;
                                                }
                                                if (devmode == 'D')
-                                                       rv |= Detail(name, !verbose);
+                                                       rv |= Detail(name, !verbose, test);
                                                else if (devmode=='S') {
                                                        mdfd = open_mddev(name);
                                                        if (mdfd >= 0)
@@ -699,7 +705,7 @@ int main(int argc, char *argv[])
                        for (dv=devlist ; dv; dv=dv->next) {
                                switch(dv->disposition) {
                                case 'D':
-                                       rv |= Detail(dv->devname, brief); continue;
+                                       rv |= Detail(dv->devname, brief, test); continue;
                                case 'K': /* Zero superblock */
                                        rv |= Kill(dv->devname, force); continue;
                                case 'Q':
diff --git a/mdadm.h b/mdadm.h
index 6ce5fac..a8897da 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -96,6 +96,7 @@ typedef struct mddev_ident_s {
                                 */
        int level;              /* -10 if not set */
        int raid_disks;         /* -1 if not set */
+       int spare_disks;        /* -1 if not set */
        char *spare_group;
        struct mddev_ident_s *next;
 } *mddev_ident_t;
@@ -163,7 +164,7 @@ extern int Create(char *mddev, int mdfd,
                  int subdevs, mddev_dev_t devlist,
                  int runstop, int verbose, int force);
 
-extern int Detail(char *dev, int brief);
+extern int Detail(char *dev, int brief, int test);
 extern int Query(char *dev);
 extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust);
 extern int Monitor(mddev_dev_t devlist,
index f8498ed..7c3d7c1 100644 (file)
@@ -1,6 +1,6 @@
 Summary:     mdadm is used for controlling Linux md devices (aka RAID arrays)
 Name:        mdadm
-Version:     1.3.0
+Version:     1.4.0
 Release:     1
 Source:      http://www.cse.unsw.edu.au/~neilb/source/mdadm/mdadm-%{version}.tgz
 URL:         http://www.cse.unsw.edu.au/~neilb/source/mdadm/