]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdadm-1.6.0 mdadm-1.6.0
authorNeil Brown <neilb@suse.de>
Fri, 4 Jun 2004 12:03:19 +0000 (12:03 +0000)
committerNeil Brown <neilb@suse.de>
Fri, 4 Jun 2004 12:03:19 +0000 (12:03 +0000)
20 files changed:
ANNOUNCE-1.6.0 [new file with mode: 0644]
Build.c
ChangeLog
Create.c
Detail.c
Examine.c
Manage.c
Monitor.c
ReadMe.c
TODO
config.c
mdadm.8
mdadm.c
mdadm.conf.5
mdadm.h
mdadm.spec
mdassemble [new file with mode: 0755]
mdstat.c
t [new file with mode: 0644]
util.c

diff --git a/ANNOUNCE-1.6.0 b/ANNOUNCE-1.6.0
new file mode 100644 (file)
index 0000000..4461fe3
--- /dev/null
@@ -0,0 +1,36 @@
+Subject:  ANNOUNCE: mdadm 1.6.0 - A tool for managing Soft RAID under Linux
+
+
+I am pleased to announce the availability of 
+   mdadm version 1.6.0
+It is available at
+   http://www.cse.unsw.edu.au/~neilb/source/mdadm/
+and
+   http://www.{countrycode}.kernel.org/pub/linux/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.6.0 adds:
+  - --grow which (in 2.6.7-rc1-mm1 and hopefully 2.6.8) allows raid1/4/5/6
+    arrays to change the active size of the underlying devices, and allows
+    raid1 arrays to change the number of active drives.
+  - Allows --build to buld raid1 and multipath arrays.
+  - adds "degraded" and "recovering" as possibilities for the status line
+    in --detail
+  - fixes a bug in 1.5.0 which stopped resync status messages from being
+    generated in --monitor mode
+  - Further support for partitionable arrays included "--auto=" option
+    and "auto=" config file entry which instructs mdadm to create the necessary
+    device files after allocating an unused array number.
+  - assorted minor fixes and improvements.
+
+Development of mdadm is sponsored by CSE@UNSW: 
+  The School of Computer Science and Engineering
+at
+  The University of New South Wales
+
+NeilBrown  4 Jun 2004
diff --git a/Build.c b/Build.c
index 0179807f4bc1908b30cfab5a9b9b29f66be3eba9..3e182f8c8b63d11e15541a442fb974c18e8a53a1 100644 (file)
--- a/Build.c
+++ b/Build.c
@@ -35,7 +35,7 @@
 
 int Build(char *mddev, int mdfd, int chunk, int level,
          int raiddisks,
 
 int Build(char *mddev, int mdfd, int chunk, int level,
          int raiddisks,
-         mddev_dev_t devlist)
+         mddev_dev_t devlist, int assume_clean)
 {
        /* Build a linear or raid0 arrays without superblocks
         * We cannot really do any checks, we just do it.
 {
        /* Build a linear or raid0 arrays without superblocks
         * We cannot really do any checks, we just do it.
@@ -91,6 +91,8 @@ int Build(char *mddev, int mdfd, int chunk, int level,
                        array.md_minor = MINOR(stb.st_rdev);
                array.not_persistent = 1;
                array.state = 0; /* not clean, but no errors */
                        array.md_minor = MINOR(stb.st_rdev);
                array.not_persistent = 1;
                array.state = 0; /* not clean, but no errors */
+               if (assume_clean)
+                       array.state |= 1;
                array.active_disks = raiddisks;
                array.working_disks = raiddisks;
                array.spare_disks = 0;
                array.active_disks = raiddisks;
                array.working_disks = raiddisks;
                array.spare_disks = 0;
index 7c8fe05430ac40fa26e65a11a83ac7f286a04cc9..a505a74fa4b959ea0fa22fd1706042a7bfad4519 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,28 @@
-Changes Prior to this release
+Changes Prior to 1.6.0 release
+    -  Device name given in -Eb is determined by examining /dev rather
+       than assuming /dev/md%d
+    -   Fix bug in --monitor where an array could be held open an so
+       could not be stopped without killing mdadm.
+    -   Add --grow mode.  Currently only --size and --raid-disks can be
+       changed. Both require kernel support which, at the time of
+       writing, is not in a release kernel yet.
+    -   Don't print out "errors" or "no-errors" in -D and -E, as the bit
+       is never set or used.
+    -   Use md event notification in 2.6.??? to make --monitor mode
+        respond instantly to events.
+    -   Add --auto= option and auto= configfile entry to tell mdadm to
+       create device files as needed.  This is particularly useful
+       with partitioned arrays where the major device number can change.
+    -   When generating --brief listing, if the standard name doesn't
+        exist, search /dev for one rather than using a temp name.
+    -   Allow --build to build raid1 and multipath arrays.
+    -   Add "--assume-clean" for Create and Build, particularly for raid1
+       Note: this is dangerous. Only use it if you are certain.
+    -   Fix bug so that Rebuild status monitoring works again.
+    -   Add "degraded" and "recovering" options to the "Status:"
+       entry for --detail
+
+Changes Prior to 1.5.0 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>.
     -   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>.
@@ -323,4 +347,3 @@ Changes Prior to 0.5 release
   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.
   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.
-
index a536a75b2728f1e734c6130e877e7c97e105e2f3..fb9857b551d785f800ab36e38134554d5b98d88c 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -68,7 +68,7 @@ int Create(char *mddev, int mdfd,
        
 
        if (md_get_version(mdfd) < 9000) {
        
 
        if (md_get_version(mdfd) < 9000) {
-               fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
+               fprintf(stderr, Name ": Create requires md driver version 0.90.0 or later\n");
                return 1;
        }
        if (level == UnSet) {
                return 1;
        }
        if (level == UnSet) {
@@ -351,6 +351,7 @@ int Create(char *mddev, int mdfd,
                if (ioctl(mdfd, RUN_ARRAY, &param)) {
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
                                strerror(errno));
                if (ioctl(mdfd, RUN_ARRAY, &param)) {
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
                                strerror(errno));
+                       Manage_runstop(mddev, mdfd, -1);
                        return 1;
                }
                fprintf(stderr, Name ": array %s started.\n", mddev);
                        return 1;
                }
                fprintf(stderr, Name ": array %s started.\n", mddev);
index 419c45cbdc6e1ec161742808e2c994452a9d6509..5028ae29c40346c0991c4e33a3deb1f1d04a1077 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -46,6 +46,7 @@ int Detail(char *dev, int brief, int test)
        char *c;
        char *devices = NULL;
        int spares = 0;
        char *c;
        char *devices = NULL;
        int spares = 0;
+       struct stat stb;
 
        mdp_super_t super;
        int have_super = 0;
 
        mdp_super_t super;
        int have_super = 0;
@@ -79,6 +80,8 @@ int Detail(char *dev, int brief, int test)
                close(fd);
                return rv;
        }
                close(fd);
                return rv;
        }
+       if (fstat(fd, &stb) != 0 && !S_ISBLK(stb.st_mode))
+               stb.st_rdev = 0;
        rv = 0;
        /* Ok, we have some info to print... */
        c = map_num(pers, array.level);
        rv = 0;
        /* Ok, we have some info to print... */
        c = map_num(pers, array.level);
@@ -87,6 +90,15 @@ int Detail(char *dev, int brief, int test)
        else {
                unsigned long array_size;
                unsigned long long larray_size;
        else {
                unsigned long array_size;
                unsigned long long larray_size;
+               struct mdstat_ent *ms = mdstat_read(0);
+               struct mdstat_ent *e;
+               int devnum = array.md_minor;
+               if (MAJOR(stb.st_rdev) != MD_MAJOR)
+                       devnum = -1 - devnum;
+
+               for (e=ms; e; e=e->next)
+                       if (e->devnum == devnum)
+                               break;
 #ifdef BLKGETSIZE64
                if (ioctl(fd, BLKGETSIZE64, &larray_size)==0)
                        ;
 #ifdef BLKGETSIZE64
                if (ioctl(fd, BLKGETSIZE64, &larray_size)==0)
                        ;
@@ -106,7 +118,7 @@ int Detail(char *dev, int brief, int test)
                printf("  Creation Time : %.24s\n", ctime(&atime));
                printf("     Raid Level : %s\n", c?c:"-unknown-");
                if (larray_size)
                printf("  Creation Time : %.24s\n", ctime(&atime));
                printf("     Raid Level : %s\n", c?c:"-unknown-");
                if (larray_size)
-               printf("     Array Size : %llu%s\n", (larray_size>>10), human_size(larray_size));
+                       printf("     Array Size : %llu%s\n", (larray_size>>10), human_size(larray_size));
                if (array.level >= 1)
                        printf("    Device Size : %d%s\n", array.size, human_size((long long)array.size<<10));
                printf("   Raid Devices : %d\n", array.raid_disks);
                if (array.level >= 1)
                        printf("    Device Size : %d%s\n", array.size, human_size((long long)array.size<<10));
                printf("   Raid Devices : %d\n", array.raid_disks);
@@ -117,9 +129,10 @@ int Detail(char *dev, int brief, int test)
                printf("\n");
                atime = array.utime;
                printf("    Update Time : %.24s\n", ctime(&atime));
                printf("\n");
                atime = array.utime;
                printf("    Update Time : %.24s\n", ctime(&atime));
-               printf("          State : %s, %serrors\n",
+               printf("          State : %s%s%s\n",
                       (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
                       (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
-                      (array.state&(1<<MD_SB_ERRORS))?"":"no-");
+                      array.active_disks < array.raid_disks? ", degraded":"",
+                      (e && e->percent >= 0) ? ", recovering": "");
                printf(" Active Devices : %d\n", array.active_disks);
                printf("Working Devices : %d\n", array.working_disks);
                printf(" Failed Devices : %d\n", array.failed_disks);
                printf(" Active Devices : %d\n", array.active_disks);
                printf("Working Devices : %d\n", array.working_disks);
                printf(" Failed Devices : %d\n", array.failed_disks);
@@ -142,17 +155,11 @@ 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);
-               }
+
+               if (e && e->percent >= 0)
+                       printf(" Rebuild Status : %d%% complete\n\n", e->percent);
+               free_mdstat(ms);
+
                printf("    Number   Major   Minor   RaidDevice State\n");
        }
        for (d= 0; d<MD_SB_DISKS; d++) {
                printf("    Number   Major   Minor   RaidDevice State\n");
        }
        for (d= 0; d<MD_SB_DISKS; d++) {
index 2dd76b5ff550693886ff0197b910fc9129364bd9..1f2374586fae5373854fff437a03867b1ddfdf7b 100644 (file)
--- a/Examine.c
+++ b/Examine.c
@@ -152,9 +152,8 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
                        printf("\n");
                        atime = super.utime;
                        printf("    Update Time : %.24s\n", ctime(&atime));
                        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("          State : %s\n",
+                              (super.state&(1<<MD_SB_CLEAN))?"clean":"dirty");
                        printf(" Active Devices : %d\n", super.active_disks);
                        printf("Working Devices : %d\n", super.working_disks);
                        printf(" Failed Devices : %d\n", super.failed_disks);
                        printf(" Active Devices : %d\n", super.active_disks);
                        printf("Working Devices : %d\n", super.working_disks);
                        printf(" Failed Devices : %d\n", super.failed_disks);
@@ -236,8 +235,9 @@ int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust)
                        char sep='=';
                        char *c=map_num(pers, ap->super.level);
                        char *d;
                        char sep='=';
                        char *c=map_num(pers, ap->super.level);
                        char *d;
-                       printf("ARRAY /dev/md%d level=%s num-devices=%d UUID=",
-                              ap->super.md_minor, c?c:"-unknown-", ap->super.raid_disks);
+                       printf("ARRAY %s level=%s num-devices=%d UUID=",
+                              get_md_name(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,
                        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,
index 0d8ad8d24134c0684148ad76e058c1dbcdd458a4..624c775d530d6c0aad6a90810f84af0bf8a6de01 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -114,6 +114,27 @@ int Manage_runstop(char *devname, int fd, int runstop)
        return 0;
 }
 
        return 0;
 }
 
+int Manage_resize(char *devname, int fd, long long size, int raid_disks)
+{
+       mdu_array_info_t info;
+       if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) {
+               fprintf(stderr, Name ": Cannot get array information for %s: %s\n",
+                       devname, strerror(errno));
+               return 1;
+       }
+       if (size >= 0)
+               info.size = size;
+       if (raid_disks > 0)
+               info.raid_disks = raid_disks;
+       if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) {
+               fprintf(stderr, Name ": Cannot set device size/shape for %s: %s\n",
+                       devname, strerror(errno));
+               return 1;
+       }
+       return 0;
+}
+
+
 int Manage_subdevs(char *devname, int fd,
                   mddev_dev_t devlist)
 {
 int Manage_subdevs(char *devname, int fd,
                   mddev_dev_t devlist)
 {
index 2d3693bd8120808be37db429d3a9852e9235ae3d..021a9677aa5f87ee5de8723e9cdd2cac79dae76a 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -185,11 +185,11 @@ int Monitor(mddev_dev_t devlist,
 
                if (mdstat)
                        free_mdstat(mdstat);
 
                if (mdstat)
                        free_mdstat(mdstat);
-               mdstat = mdstat_read();
+               mdstat = mdstat_read(oneshot?0:1);
 
                for (st=statelist; st; st=st->next) {
                        mdu_array_info_t array;
 
                for (st=statelist; st; st=st->next) {
                        mdu_array_info_t array;
-                       struct mdstat_ent *mse;
+                       struct mdstat_ent *mse = NULL, *mse2;
                        char *dev = st->devname;
                        int fd;
                        unsigned int i;
                        char *dev = st->devname;
                        int fd;
                        unsigned int i;
@@ -228,16 +228,18 @@ int Monitor(mddev_dev_t devlist,
                                struct stat stb;
                                if (fstat(fd, &stb) == 0 &&
                                    (S_IFMT&stb.st_mode)==S_IFBLK) {
                                struct stat stb;
                                if (fstat(fd, &stb) == 0 &&
                                    (S_IFMT&stb.st_mode)==S_IFBLK) {
-                                       if (MINOR(stb.st_rdev) == 9)
+                                       if (MAJOR(stb.st_rdev) == MD_MAJOR)
                                                st->devnum = MINOR(stb.st_rdev);
                                        else
                                                st->devnum = -1- (MINOR(stb.st_rdev)>>6);
                                }
                        }
 
                                                st->devnum = MINOR(stb.st_rdev);
                                        else
                                                st->devnum = -1- (MINOR(stb.st_rdev)>>6);
                                }
                        }
 
-                       for (mse = mdstat ; mse ; mse=mse->next)
-                               if (mse->devnum == st->devnum)
-                                       mse->devnum = MAXINT; /* flag it as "used" */
+                       for (mse2 = mdstat ; mse2 ; mse2=mse2->next)
+                               if (mse2->devnum == st->devnum) {
+                                       mse2->devnum = MAXINT; /* flag it as "used" */
+                                       mse = mse2;
+                               }
 
                        if (st->utime == array.utime &&
                            st->failed == array.failed_disks &&
 
                        if (st->utime == array.utime &&
                            st->failed == array.failed_disks &&
@@ -349,6 +351,7 @@ int Monitor(mddev_dev_t devlist,
                                                free(st);
                                                continue;
                                        }
                                                free(st);
                                                continue;
                                        }
+                                       close(fd);
                                        st->utime = 0;
                                        st->next = statelist;
                                        st->err = 1;
                                        st->utime = 0;
                                        st->next = statelist;
                                        st->err = 1;
@@ -414,7 +417,7 @@ int Monitor(mddev_dev_t devlist,
                        if (oneshot)
                                break;
                        else
                        if (oneshot)
                                break;
                        else
-                               sleep(period);
+                               mdstat_wait(period);
                }
                test = 0;
        }
                }
                test = 0;
        }
index 7cd8240093a7d932922c5f56a961dc5037a52b41..6ba33ba15367ddb615e3caf52f158676c9496563 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -29,7 +29,7 @@
 
 #include "mdadm.h"
 
 
 #include "mdadm.h"
 
-char Version[] = Name " - v1.5.0 - 22 Jan 2004\n";
+char Version[] = Name " - v1.6.0 - 4 June 2004\n";
 /*
  * File: ReadMe.c
  *
 /*
  * File: ReadMe.c
  *
@@ -58,7 +58,7 @@ char Version[] = Name " - v1.5.0 - 22 Jan 2004\n";
  */
 
 /*
  */
 
 /*
- * mdadm has 6 major modes of operation:
+ * mdadm has 7 major modes of operation:
  * 1/ Create
  *     This mode is used to create a new array with a superblock
  *     It can progress in several step create-add-add-run
  * 1/ Create
  *     This mode is used to create a new array with a superblock
  *     It can progress in several step create-add-add-run
@@ -84,9 +84,13 @@ char Version[] = Name " - v1.5.0 - 22 Jan 2004\n";
  *     Also query will treat it as either
  * 6/ Monitor
  *     This mode never exits but just monitors arrays and reports changes.
  *     Also query will treat it as either
  * 6/ Monitor
  *     This mode never exits but just monitors arrays and reports changes.
+ * 7/ Grow
+ *     This mode allows for changing of key attributes of a raid array, such
+ *     as size, number of devices, and possibly even layout.
+ *     At the time if writing, there is only minimal support.
  */
 
  */
 
-char short_options[]="-ABCDEFGQhVvbc:l:p:m:n:x:u:c:d:z:U:sarfRSow1t";
+char short_options[]="-ABCDEFGQhVvbc:l:p:m:n:x:u:c:d:z:U:sa::rfRSow1t";
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
     {"misc",      0, 0, '#'},
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
     {"misc",      0, 0, '#'},
@@ -96,7 +100,7 @@ struct option long_options[] = {
     {"detail",    0, 0, 'D'},
     {"examine",   0, 0, 'E'},
     {"follow",    0, 0, 'F'},
     {"detail",    0, 0, 'D'},
     {"examine",   0, 0, 'E'},
     {"follow",    0, 0, 'F'},
-    {"grow",      0, 0, 'G'}, /* not yet implemented */
+    {"grow",      0, 0, 'G'},
     {"zero-superblock", 0, 0, 'K'}, /* deliberately no a short_option */
     {"query",    0, 0, 'Q'},
 
     {"zero-superblock", 0, 0, 'K'}, /* deliberately no a short_option */
     {"query",    0, 0, 'Q'},
 
@@ -119,7 +123,9 @@ struct option long_options[] = {
     {"raid-devices",1, 0, 'n'},
     {"spare-disks",1,0, 'x'},
     {"spare-devices",1,0, 'x'},
     {"raid-devices",1, 0, 'n'},
     {"spare-disks",1,0, 'x'},
     {"spare-devices",1,0, 'x'},
-    {"size"      ,1, 0, 'z'},
+    {"size",     1, 0, 'z'},
+    {"auto",     2, 0, 'a'}, /* also for --assemble */
+    {"assume-clean",0,0, 3 },
 
     /* For assemble */
     {"uuid",      1, 0, 'u'},
 
     /* For assemble */
     {"uuid",      1, 0, 'u'},
@@ -213,6 +219,8 @@ char OptionHelp[] =
 "  --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"
 "                     : insert a missing drive for RAID5.\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"
 "                     : insert a missing drive for RAID5.\n"
+"  --auto(=p)    -a   : Automatically allocate new (partitioned) md array if needed.\n"
+"  --assume-clean     : Assume the array is already in-sync. This is dangerous.\n"
 "\n"
 " For assemble:\n"
 "  --uuid=       -u   : uuid of array to assemble. Devices which don't\n"
 "\n"
 " For assemble:\n"
 "  --uuid=       -u   : uuid of array to assemble. Devices which don't\n"
@@ -223,6 +231,7 @@ char OptionHelp[] =
 "  --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: one of sparc2.2, super-minor or summaries\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: one of sparc2.2, super-minor or summaries\n"
+"  --auto(=p)    -a   : Automatically allocate new (partitioned) md array if needed.\n"
 "\n"
 " For detail or examine:\n"
 "  --brief       -b   : Just print device name and UUID\n"
 "\n"
 " For detail or examine:\n"
 "  --brief       -b   : Just print device name and UUID\n"
@@ -401,7 +410,7 @@ char Help_monitor[] =
 "If no mail address or program are specified, then mdadm reports all\n"
 "state changes to stdout.\n"
 "\n"
 "If no mail address or program are specified, then mdadm reports all\n"
 "state changes to stdout.\n"
 "\n"
-"Options that are valid with the monitor (--F --follow) mode are:\n"
+"Options that are valid with the monitor (-F --follow) mode are:\n"
 "  --mail=       -m   : Address to mail alerts of failure to\n"
 "  --program=    -p   : Program to run when an event is detected\n"
 "  --alert=           : same as --program\n"
 "  --mail=       -m   : Address to mail alerts of failure to\n"
 "  --program=    -p   : Program to run when an event is detected\n"
 "  --alert=           : same as --program\n"
@@ -413,6 +422,22 @@ char Help_monitor[] =
 "  --test        -t   : Generate a TestMessage event against each array at startup\n"
 ;
 
 "  --test        -t   : Generate a TestMessage event against each array at startup\n"
 ;
 
+char Help_grow[] =
+"Usage: mdadm --grow device options\n"
+"\n"
+"This usage causes mdadm to attempt to reconfigure a running array.\n"
+"This is only possibly if the kernel being used supports a particular\n"
+"reconfiguration.  This version only supports changing the number of\n"
+"devices in a RAID1, and changing the active size of all devices in\n"
+"a RAID1/4/5/6.\n"
+"\n"
+"Options that are valid with the grow (-F --grow) mode are:\n"
+"  --size=        -z   : Change the active size of devices in an array.\n"
+"                      : This is useful if all devices have been replaced\n"
+"                      : with larger devices.\n"
+"  --raid-disks=  -n   : Change the number of active devices in a RAID1\n"
+"                      : array.\n"
+;
 
 
 
 
 
 
@@ -494,4 +519,5 @@ mapping_t modes[] = {
        { "manage", MANAGE},
        { "misc", MISC},
        { "monitor", MONITOR},
        { "manage", MANAGE},
        { "misc", MISC},
        { "monitor", MONITOR},
+       { "grow", GROW},
 };
 };
diff --git a/TODO b/TODO
index 4cfa1ebe70fcb47ab5c85271e848e475311c0493..a282744a95f0b37a1076beaccd0e5b4ad439fbc7 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,15 @@
+2004-june-02
+  * Don't print 'errors' flag, it is meaningless. DONE
+  * Handle new superblock format
+  * create device file on demand, particularly partitionable devices. DONE
+      BUT figure a way to create the partition devices.
+              auto=partN
+  * Use Event: interface to listen for events. DONE, untested
+  * Make sure mdadm -As can assemble multi-level RAIDs ok.
+  * --build to build raid1 or multipath arrays 
+       clean or not ???
+  
+----------------------------------------------------------------------------
 * mdadm --monitor to monitor failed multipath paths and re-instate them.
 
 * Maybe make "--help" fit in 80x24 and have a --long-help with more info. DONE
 * mdadm --monitor to monitor failed multipath paths and re-instate them.
 
 * Maybe make "--help" fit in 80x24 and have a --long-help with more info. DONE
index 067beb6cf2ce9666686075d8032cbb7bbdb4e8ce..1671d266ef55bb3a2fb7e078de76fb7aa9cc028c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -32,6 +32,7 @@
 #include       <sys/dir.h>
 #include       <glob.h>
 #include       <fnmatch.h>
 #include       <sys/dir.h>
 #include       <glob.h>
 #include       <fnmatch.h>
+#include       <ctype.h>
 
 /*
  * Read the config file
 
 /*
  * Read the config file
@@ -230,6 +231,7 @@ void load_partitions(void)
                        cdevlist = cd;
                }
        }
                        cdevlist = cd;
                }
        }
+       fclose(f);
 }
 
 
 }
 
 
@@ -272,6 +274,7 @@ void arrayline(char *line)
        mis.devices = NULL;
        mis.devname = NULL;
        mis.spare_group = NULL;
        mis.devices = NULL;
        mis.devname = NULL;
        mis.spare_group = NULL;
+       mis.autof = 0;
 
        for (w=dl_next(line); w!=line; w=dl_next(w)) {
                if (w[0] == '/') {
 
        for (w=dl_next(line); w!=line; w=dl_next(w)) {
                if (w[0] == '/') {
@@ -326,13 +329,41 @@ void arrayline(char *line)
                } else if (strncasecmp(w, "spares=", 7) == 0 ) {
                        /* for warning if not all spares present */
                        mis.spare_disks = atoi(w+7);
                } else if (strncasecmp(w, "spares=", 7) == 0 ) {
                        /* for warning if not all spares present */
                        mis.spare_disks = atoi(w+7);
+               } else if (strncasecmp(w, "auto=", 5) == 0 ) {
+                       /* whether to create device special files as needed */
+                       if (strcasecmp(w+5, "no")==0)
+                               mis.autof = 0;
+                       else if (strcasecmp(w+5,"yes")==0 || strcasecmp(w+5,"md")==0)
+                               mis.autof = -1;
+                       else {
+                               /* There might be digits, and maybe a hypen, at the end */
+                               char *e = w+5 + strlen(w+5);
+                               int num = 4;
+                               int len;
+                               while (e > w+5 && isdigit(e[-1]))
+                                       e--;
+                               if (*e) {
+                                       num = atoi(e);
+                                       if (num <= 0) num = 1;
+                               }
+                               if (e > w+5 && e[-1] == '-')
+                                       e--;
+                               len = e - (w+5);
+                               if ((len == 3 && strncasecmp(w+5,"mdp",3)==0) ||
+                                   (len == 1 && strncasecmp(w+5,"p",1)==0) ||
+                                   (len >= 4 && strncasecmp(w+5,"part",4)==0))
+                                       mis.autof = num;
+                               else 
+                                       fprintf(stderr, Name ": auto type of \"%s\" ignored for %s\n",
+                                               w+5, mis.devname?mis.devname:"unlabeled-array");
+                       }
                } else {
                        fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
                                w);
                }
        }
        if (mis.devname == NULL)
                } else {
                        fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
                                w);
                }
        }
        if (mis.devname == NULL)
-               fprintf(stderr, Name ": ARRAY line with a device\n");
+               fprintf(stderr, Name ": ARRAY line with no device\n");
        else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor < 0)
                fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname);
        else {
        else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor < 0)
                fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname);
        else {
@@ -420,6 +451,7 @@ void load_conffile(char *conffile)
                free_line(line);
        }
     
                free_line(line);
        }
     
+       fclose(f);
 
 /*    printf("got file\n"); */
 }
 
 /*    printf("got file\n"); */
 }
diff --git a/mdadm.8 b/mdadm.8
index 38bcb7377d5d401ec8e005a6642528f8e6f75495..6e20b7ea93b5f49b2876cb89b03e3defa75926d7 100644 (file)
--- a/mdadm.8
+++ b/mdadm.8
@@ -1,5 +1,5 @@
 .\" -*- nroff -*-
 .\" -*- nroff -*-
-.TH MDADM 8 "" v1.5.0
+.TH MDADM 8 "" v1.6.0
 .SH NAME
 mdadm \- manage MD devices
 .I aka
 .SH NAME
 mdadm \- manage MD devices
 .I aka
@@ -76,7 +76,7 @@ configuration file, at all.  It has a different configuration file
 with a different format and an different purpose.
 
 .SH MODES
 with a different format and an different purpose.
 
 .SH MODES
-mdadm has 6 major modes of operation:
+mdadm has 7 major modes of operation:
 .TP
 .B Assemble
 Assemble the parts of a previously created
 .TP
 .B Assemble
 Assemble the parts of a previously created
@@ -114,6 +114,12 @@ only meaningful for raid1, 4, 5, 6 or multipath arrays as
 only these have interesting state.  raid0 or linear never have
 missing, spare, or failed drives, so there is nothing to monitor.
 
 only these have interesting state.  raid0 or linear never have
 missing, spare, or failed drives, so there is nothing to monitor.
 
+.TP
+.B "Grow"
+Grow (or shrink) an array, or otherwise reshape it in some way.
+Currently supported growth options including changing the active size
+of componenet devices in RAID level 1/4/5/6 and changing the number of
+active devices in RAID1.
 
 .SH OPTIONS
 
 
 .SH OPTIONS
 
@@ -152,6 +158,10 @@ Select
 .B Monitor
 mode.
 
 .B Monitor
 mode.
 
+.TP
+.BR -G ", " --grow
+Change the size or shape of an active array.
+
 .TP
 .BR -h ", " --help
 Display help message or, after above option, mode specific help
 .TP
 .BR -h ", " --help
 Display help message or, after above option, mode specific help
@@ -261,13 +271,17 @@ Specify the number of active devices in the array.  This, plus the
 number of spare devices (see below) must equal the number of
 .I component-devices
 (including "\fBmissing\fP" devices)
 number of spare devices (see below) must equal the number of
 .I component-devices
 (including "\fBmissing\fP" devices)
-that are listed on the command line.  Setting a value of 1 is probably
+that are listed on the command line for
+.BR  --create .
+Setting a value of 1 is probably
 a mistake and so requires that
 .B --force
 be specified first.  A value of 1 will then be allowed for linear,
 multipath, raid0 and raid1.  It is never allowed for raid4 or raid5.
 .br
 a mistake and so requires that
 .B --force
 be specified first.  A value of 1 will then be allowed for linear,
 multipath, raid0 and raid1.  It is never allowed for raid4 or raid5.
 .br
-Note that this number cannot be changed once the array has been created.
+This number can only be changed using
+.B --grow
+for RAID1 arrays, and only on kernels which provide necessary support.
 
 .TP
 .BR -x ", " --spare-devices=
 
 .TP
 .BR -x ", " --spare-devices=
@@ -288,6 +302,63 @@ If this is not specified
 size, though if there is a variance among the drives of greater than 1%, a warning is
 issued.
 
 size, though if there is a variance among the drives of greater than 1%, a warning is
 issued.
 
+This value can be set with
+.B --grow
+for RAID level 1/4/5/6. If the array was created with a size smaller
+than the currently active drives, the extra space can be accessed
+using
+.BR --grow .
+
+.TP
+.BR --assume-clean
+Tell
+.I mdadm
+that the array pre-existed and is known to be clean.  This is only
+really useful for Building RAID1 array.  Only use this if you really
+know what you are doing.  This is currently only supported for --build.
+
+.TP
+.BR -R ", " --run
+Insist that
+.I mdadm
+run the array, even if some of the components
+appear to be active in another array or filesystem.  Normally
+.I mdadm
+will ask for confirmation before including such components in an
+array.  This option causes that question to be suppressed.
+
+.TP
+.BR -f ", " --force
+Insist that
+.I mdadm
+accept the geometry and layout specified without question.  Normally
+.I mdadm
+will not allow creation of an array with only one device, and will try
+to create a raid5 array with one missing drive (as this makes the
+initial resync work faster).  With
+.BR --force ,
+.I mdadm
+will not try to be so clever.
+
+.TP
+.BR -a ", " "--auto{=no,yes,md,mdp,part,p}{NN}"
+Instruct mdadm to create the device file if needed, and to allocate
+an unused minor number.  "yes" or "md" causes a non-partitionable array
+to be used.  "mdp", "part" or "p" causes a partitionable array (2.6 and
+later) to be used.  The argumentment can also come immediately after
+"-a".  e.g. "-ap".
+
+For partitionable arrays,
+.I mdadm
+will create the device file for the whole array and for the first 4
+partitions.  A different number of partitions can be specified at the
+end of this option (e.g.
+.BR --auto=p7 ).
+If the device name ends with a digit, the partition names add an
+underscore, a 'p', and a number, e.g. "/dev/home1_p3".  If there is no
+trailing digit, then the partition names just have a number added,
+e.g. "/dev/scratch3".
+
 .SH For assemble:
 
 .TP
 .SH For assemble:
 
 .TP
@@ -326,6 +397,10 @@ With
 .B --run
 an attempt will be made to start it anyway.
 
 .B --run
 an attempt will be made to start it anyway.
 
+.TP
+.BR -a ", " "--auto{=no,yes,md,mdp,part}"
+See this option under Create and Build options.
+
 .TP
 .BR -U ", " --update=
 Update the superblock on each device while assembling the array.  The
 .TP
 .BR -U ", " --update=
 Update the superblock on each device while assembling the array.  The
@@ -504,7 +579,7 @@ listed in the configuration file are assembled.
 
 If precisely one device is listed, but
 .B --scan
 
 If precisely one device is listed, but
 .B --scan
-is not given, that
+is not given, then
 .I mdadm
 acts as though
 .B --scan
 .I mdadm
 acts as though
 .B --scan
@@ -545,6 +620,46 @@ may work for RAID1, 4, 5 or 6), give the
 .B --run
 flag.
 
 .B --run
 flag.
 
+If an
+.B auto
+option is given, either on the command line (--auto) or in the
+configuration file (e.g. auto=part), then
+.I mdadm
+will create the md device if necessary or will re-create it if it
+doesn't look usable as it is.
+
+This can be useful for handling partitioned devices (which don't have
+a stable device number - it can change after a reboot) and when using
+"udev" to manage your
+.B /dev
+tree (udev cannot handle md devices because of the unusual device
+initialisation conventions).
+
+If the option to "auto" is "mdp" or "part" or (on the command line
+only) "p", then mdadm will create a partitionable array, using the
+first free one that is not inuse, and does not already have an entry
+in /dev (apart from numeric /dev/md* entries).
+
+If the option to "auto" is "yes" or "md" or (on the command line)
+nothing, then mdadm will create a traditional, non-partitionable md
+array.
+
+It is expected that the "auto" functionality will be used to create
+device entries with meaningful names such as "/dev/md/home" or
+"/dev/md/root", rather than names based on the numerical array number.
+
+When using this option to create a partitionable array, the device
+files for the first 4 partitions are also created. If a different
+number is required it can be simply appended to the auto option.
+e.g. "auto=part8".  Partition names are created by appending a digit
+string to the device name, with an intervening "_p" if the device name
+ends with a digit.
+
+The
+.B --auto
+option is also available in Build and Create modes.  As those modes do
+not use a config file, the "auto=" config option does not apply to
+these modes.
 
 .SH BUILD MODE
 
 
 .SH BUILD MODE
 
@@ -584,6 +699,12 @@ Usage:
 This usage will initialise a new md array, associate some devices with
 it, and activate the array.
 
 This usage will initialise a new md array, associate some devices with
 it, and activate the array.
 
+This the
+.B --auto
+option is given (as described in more detail in the section on
+Assemble mode), then the md device will be created with a suitable
+device number if necessary.
+
 As devices are added, they are checked to see if they contain raid
 superblocks or filesystems. They are also checked to see if the variance in
 device size exceeds 1%.
 As devices are added, they are checked to see if they contain raid
 superblocks or filesystems. They are also checked to see if the variance in
 device size exceeds 1%.
@@ -625,7 +746,7 @@ option.
 The General Management options that are valid with --create are:
 .TP
 .B --run
 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
+insist on running the array even if some devices look like they might
 be in use.
 
 .TP
 be in use.
 
 .TP
@@ -921,6 +1042,43 @@ first.
 If the removal succeeds but the adding fails, then it is added back to
 the original array.
 
 If the removal succeeds but the adding fails, then it is added back to
 the original array.
 
+.SH GROW MODE
+The GROW mode is used for changing the size or shape of an active
+array.
+For this to work, the kernel must support the necessary change.
+Various types of growth may be added during 2.6 development, possibly
+including restructuring a raid5 array to have more active devices.
+
+Currently the only support available is to change the "size" attribute
+for arrays with redundancy, and the raid-disks attribute of RAID1
+arrays.
+
+Normally when an array is build the "size" it taken from the smallest
+of the drives.  If all the small drives in an arrays are, one at a
+time, removed and replaced with larger drives, then you could have an
+array of large drives with only a small amount used.  In this
+situation, changing the "size" with "GROW" mode will allow the extra
+space to start being used.  If the size is increased in this way, a
+"resync" process will start to make sure the new parts of the array
+are synchronised.
+
+Note that when an array changes size, any filesystem that may be
+stored in the array will not automatically grow to use the space.  The
+filesystem will need to be explicitly told to use the extra space.
+
+A RAID1 array can work with any number of devices from 1 upwards
+(though 1 is not very useful).  There may be times which you want to
+increase or decrease the number of active devices.  Note that this is
+different to hot-add or hot-remove which changes the number of
+inactive devices.
+
+When reducing the number of devices in a RAID1 array, the slots which
+are to be removed from the array must already be vacant.  That is, the
+devices that which were in those slots must be failed and removed.
+
+When the number of devices is increased, any hot spares that are
+present may be activated immediately.
+
 .SH EXAMPLES
 
 .B "  mdadm --query /dev/name-of-device"
 .SH EXAMPLES
 
 .B "  mdadm --query /dev/name-of-device"
diff --git a/mdadm.c b/mdadm.c
index d17e0b1701126103996b6c1b55480291c91c2567..827f334d9da146437f3c4c07c8dc9080ba687f91 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
 
 #include "mdadm.h"
 #include "md_p.h"
 
 #include "mdadm.h"
 #include "md_p.h"
+#include <ctype.h>
 
 
-int open_mddev(char *dev)
+
+void make_parts(char *dev, int cnt)
 {
 {
-       int mdfd = open(dev, O_RDWR, 0);
+       /* make 'cnt' partition devices for 'dev'
+        * We use the major/minor from dev and add 1..cnt
+        * If dev ends with a digit, we add "_p%d" else "%d"
+        * If the name exists, we use it's owner/mode,
+        * else that of dev
+        */
+       struct stat stb;
+       int major, minor;
+       int i;
+       char *name = malloc(strlen(dev) + 20);
+       int dig = isdigit(dev[strlen(dev)-1]);
+
+       if (stat(dev, &stb)!= 0)
+               return;
+       if (!S_ISBLK(stb.st_mode))
+               return;
+       major = MAJOR(stb.st_rdev);
+       minor = MINOR(stb.st_rdev);
+       for (i=1; i <= cnt ; i++) {
+               struct stat stb2;
+               sprintf(name, "%s%s%d", dev, dig?"_p":"", i);
+               if (stat(name, &stb2)==0) {
+                       if (!S_ISBLK(stb2.st_mode))
+                               continue;
+                       if (stb2.st_rdev == MKDEV(major, minor+i))
+                               continue;
+                       unlink(name);
+               } else {
+                       stb2 = stb;
+               }
+               mknod(name, S_IFBLK | 0600, MKDEV(major, minor+i));
+               chown(name, stb2.st_uid, stb2.st_gid);
+               chmod(name, stb2.st_mode & 07777);
+       }
+}
+
+/*
+ * Open a given md device, and check that it really is one.
+ * If 'autof' is given, then we need to create, or recreate, the md device.
+ * If the name already exists, and is not a block device, we fail.
+ * If it exists and is not an md device, is not the right type (partitioned or not),
+ * or is currently in-use, we remove the device, but remember the owner and mode.
+ * If it now doesn't exist, we find a few md array and create the device.
+ * Default ownership is user=0, group=0 perm=0600
+ */
+int open_mddev(char *dev, int autof)
+{
+       int mdfd;
+       struct stat stb;
+       int major = MD_MAJOR;
+       int minor;
+       int must_remove = 0;
+       struct mdstat_ent *mdlist;
+       int num;
+
+       if (autof) {
+               /* autof is set, so we need to check that the name is ok,
+                * and possibly create one if not
+                */
+               stb.st_mode = 0;
+               if (lstat(dev, &stb)==0 && ! S_ISBLK(stb.st_mode)) {
+                       fprintf(stderr, Name ": %s is not a block device.\n",
+                               dev);
+                       return -1;
+               }
+               /* check major number is correct */
+               if (autof>0)
+                       major = get_mdp_major();
+               if (stb.st_mode && MAJOR(stb.st_rdev) != major)
+                       must_remove = 1;
+               if (stb.st_mode && !must_remove) {
+                       mdu_array_info_t array;
+                       /* looks ok, see if it is available */
+                       mdfd = open(dev, O_RDWR, 0);
+                       if (mdfd < 0) {
+                               fprintf(stderr, Name ": error opening %s: %s\n",
+                                       dev, strerror(errno));
+                               return -1;
+                       } else if (md_get_version(mdfd) <= 0) {
+                               fprintf(stderr, Name ": %s does not appear to be an md device\n",
+                                       dev);
+                               close(mdfd);
+                               return -1;
+                       }
+                       if (ioctl(mdfd, GET_ARRAY_INFO, &array)==0) {
+                               /* already active */
+                               must_remove = 1;
+                               close(mdfd);
+                       } else {
+                               if (autof > 0)
+                                       make_parts(dev, autof);
+                               return mdfd;
+                       }
+               }
+               /* Ok, need to find a minor that is not in use.
+                * Easiest to read /proc/mdstat, and hunt through for
+                * an unused number 
+                */
+               mdlist = mdstat_read(0);
+               for (num= (autof>0)?-1:0 ; ; num+= (autof>2)?-1:1) {
+                       struct mdstat_ent *me;
+                       for (me=mdlist; me; me=me->next)
+                               if (me->devnum == num)
+                                       break;
+                       if (!me) {
+                               /* doesn't exist if mdstat.
+                                * make sure it is new to /dev too
+                                */
+                               char *dn;
+                               if (autof > 0) 
+                                       minor = (-1-num) << MdpMinorShift;
+                               else
+                                       minor = num;
+                               dn = map_dev(major,minor);
+                               if (dn==NULL || is_standard(dn)) {
+                                       /* this number only used by a 'standard' name,
+                                        * so it is safe to use
+                                        */
+                                       break;
+                               }
+                       }
+               }
+               /* 'num' is the number to use, >=0 for md, <0 for mdp */
+               if (must_remove) {
+                       /* never remove a device name that ends /mdNN or /dNN,
+                        * that would be confusing 
+                        */
+                       if (is_standard(dev)) {
+                               fprintf(stderr, Name ": --auto refusing to remove %s as it looks like a standard name.\n",
+                                       dev);
+                               return -1;
+                       }
+                       unlink(dev);
+               }
+
+               if (mknod(dev, S_IFBLK|0600, MKDEV(major, minor))!= 0) {
+                       fprintf(stderr, Name ": failed to create %s\n", dev);
+                       return -1;
+               }
+               if (must_remove) {
+                       chown(dev, stb.st_uid, stb.st_gid);
+                       chmod(dev, stb.st_mode & 07777);
+               }
+               make_parts(dev,autof);
+       }
+       mdfd = open(dev, O_RDWR, 0);
        if (mdfd < 0)
                fprintf(stderr, Name ": error opening %s: %s\n",
                        dev, strerror(errno));
        if (mdfd < 0)
                fprintf(stderr, Name ": error opening %s: %s\n",
                        dev, strerror(errno));
@@ -57,7 +204,7 @@ int main(int argc, char *argv[])
        int rv;
 
        int chunk = 0;
        int rv;
 
        int chunk = 0;
-       int size = 0;
+       int size = -1;
        int level = UnSet;
        int layout = UnSet;
        int raiddisks = 0;
        int level = UnSet;
        int layout = UnSet;
        int raiddisks = 0;
@@ -79,6 +226,8 @@ int main(int argc, char *argv[])
        int brief = 0;
        int force = 0;
        int test = 0;
        int brief = 0;
        int force = 0;
        int test = 0;
+       int assume_clean = 0;
+       int autof = 0; /* -1 for non-partitions, 1 or more to create partitions */
 
        char *mailaddr = NULL;
        char *program = NULL;
 
        char *mailaddr = NULL;
        char *program = NULL;
@@ -114,6 +263,7 @@ int main(int argc, char *argv[])
                                case MANAGE   : help_text = Help_manage; break;
                                case MISC     : help_text = Help_misc; break;
                                case MONITOR  : help_text = Help_monitor; break;
                                case MANAGE   : help_text = Help_manage; break;
                                case MISC     : help_text = Help_misc; break;
                                case MONITOR  : help_text = Help_monitor; break;
+                               case GROW     : help_text = Help_grow; break;
                                }
                        fputs(help_text,stderr);
                        exit(0);
                                }
                        fputs(help_text,stderr);
                        exit(0);
@@ -150,6 +300,7 @@ int main(int argc, char *argv[])
                case 'B': newmode = BUILD; break;
                case 'C': newmode = CREATE; break;
                case 'F': newmode = MONITOR;break;
                case 'B': newmode = BUILD; break;
                case 'C': newmode = CREATE; break;
                case 'F': newmode = MONITOR;break;
+               case 'G': newmode = GROW; break;
 
                case '#':
                case 'D':
 
                case '#':
                case 'D':
@@ -200,13 +351,14 @@ int main(int argc, char *argv[])
                case 'B':
                case 'C':
                case 'F':
                case 'B':
                case 'C':
                case 'F':
+               case 'G':
                        continue;
                }
                if (opt == 1) {
                        /* an undecorated option - must be a device name.
                         */
                        if (devs_found > 0 && mode == '@' && !devmode) {
                        continue;
                }
                if (opt == 1) {
                        /* an undecorated option - must be a device name.
                         */
                        if (devs_found > 0 && mode == '@' && !devmode) {
-                               fprintf(stderr, Name ": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg);
+                               fprintf(stderr, Name ": Must give one of -a/-r/-f for subsequent devices at %s\n", optarg);
                                exit(2);
                        }
                        dv = malloc(sizeof(*dv));
                                exit(2);
                        }
                        dv = malloc(sizeof(*dv));
@@ -243,17 +395,22 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
                        }
                        continue;
 
+               case O(GROW,'z'):
                case O(CREATE,'z'): /* size */
                case O(CREATE,'z'): /* size */
-                       if (size) {
+                       if (size >= 0) {
                                fprintf(stderr, Name ": size may only be specified once. "
                                        "Second value is %s.\n", optarg);
                                exit(2);
                        }
                                fprintf(stderr, Name ": size may only be specified once. "
                                        "Second value is %s.\n", optarg);
                                exit(2);
                        }
-                       size = strtol(optarg, &c, 10);
-                       if (!optarg[0] || *c || size < 4) {
-                               fprintf(stderr, Name ": invalid size: %s\n",
-                                       optarg);
-                               exit(2);
+                       if (strcmp(optarg, "max")==0)
+                               size = 0;
+                       else {
+                               size = strtol(optarg, &c, 10);
+                               if (!optarg[0] || *c || size < 4) {
+                                       fprintf(stderr, Name ": invalid size: %s\n",
+                                               optarg);
+                                       exit(2);
+                               }
                        }
                        continue;
 
                        }
                        continue;
 
@@ -270,7 +427,7 @@ int main(int argc, char *argv[])
                                        optarg);
                                exit(2);
                        }
                                        optarg);
                                exit(2);
                        }
-                       if (level != 0 && level != -1 && mode == BUILD) {
+                       if (level != 0 && level != -1 && level != 1 && level != -4 && mode == BUILD) {
                                fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
                                        optarg);
                                exit(2);
                                fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
                                        optarg);
                                exit(2);
@@ -310,6 +467,12 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
                        }
                        continue;
 
+               case O(CREATE,3):
+               case O(BUILD,3): /* assume clean */
+                       assume_clean = 1;
+                       continue;
+
+               case O(GROW,'n'):
                case O(CREATE,'n'):
                case O(BUILD,'n'): /* number of raid disks */
                        if (raiddisks) {
                case O(CREATE,'n'):
                case O(BUILD,'n'): /* number of raid disks */
                        if (raiddisks) {
@@ -350,6 +513,43 @@ int main(int argc, char *argv[])
                                exit(2);
                        }
                        continue;
                                exit(2);
                        }
                        continue;
+
+               case O(CREATE,'a'):
+               case O(BUILD,'a'):
+               case O(ASSEMBLE,'a'): /* auto-creation of device node */
+                       if (optarg == NULL)
+                               autof = -1;
+                       else if (strcasecmp(optarg,"no")==0)
+                               autof = 0;
+                       else if (strcasecmp(optarg,"yes")==0 || strcasecmp(optarg,"md")==0)
+                               autof = -1;
+                       else {
+                               /* There might be digits, and maybe a hypen, at the end */
+                               char *e = optarg + strlen(optarg);
+                               int num = 4;
+                               int len;
+                               while (e > optarg && isdigit(e[-1]))
+                                       e--;
+                               if (*e) {
+                                       num = atoi(e);
+                                       if (num <= 0) num = 1;
+                               }
+                               if (e > optarg && e[-1] == '-')
+                                       e--;
+                               len = e - optarg;
+                               if ((len == 3 && strncasecmp(optarg,"mdp",3)==0) ||
+                                   (len == 1 && strncasecmp(optarg,"p",1)==0) ||
+                                   (len >= 4 && strncasecmp(optarg,"part",4)==0))
+                                       autof = num;
+                               else {
+                                       fprintf(stderr, Name ": --auto flag arg of \"%s\" unrecognised: use no,yes,md,mdp,part\n"
+                                               "        optionally followed by a number.\n",
+                                               optarg);
+                                       exit(2);
+                               }
+                       }
+                       continue;
+
                case O(BUILD,'f'): /* force honouring '-n 1' */
                case O(CREATE,'f'): /* force honouring of device list */
                case O(ASSEMBLE,'f'): /* force assembly */
                case O(BUILD,'f'): /* force honouring '-n 1' */
                case O(CREATE,'f'): /* force honouring of device list */
                case O(ASSEMBLE,'f'): /* force assembly */
@@ -463,10 +663,7 @@ int main(int argc, char *argv[])
                        /* now the general management options.  Some are applicable
                         * to other modes. None have arguments.
                         */
                        /* now the general management options.  Some are applicable
                         * to other modes. None have arguments.
                         */
-               case O(MANAGE,'a'):
-               case O(CREATE,'a'):
-               case O(BUILD,'a'):
-               case O(ASSEMBLE,'a'): /* add a drive */
+               case O(MANAGE,'a'): /* add a drive */
                        devmode = 'a';
                        continue;
                case O(MANAGE,'r'): /* remove a drive */
                        devmode = 'a';
                        continue;
                case O(MANAGE,'r'): /* remove a drive */
@@ -559,12 +756,17 @@ int main(int argc, char *argv[])
         * we check that here and open it.
         */
 
         * we check that here and open it.
         */
 
-       if (mode==MANAGE || mode == BUILD || mode == CREATE || (mode == ASSEMBLE && ! scan)) {
+       if (mode==MANAGE || mode == BUILD || mode == CREATE || mode == GROW ||
+           (mode == ASSEMBLE && ! scan)) {
                if (devs_found < 1) {
                        fprintf(stderr, Name ": an md device must be given in this mode\n");
                        exit(2);
                }
                if (devs_found < 1) {
                        fprintf(stderr, Name ": an md device must be given in this mode\n");
                        exit(2);
                }
-               mdfd = open_mddev(devlist->devname);
+               if ((int)ident.super_minor == -2 && autof) {
+                       fprintf(stderr, Name ": --super-minor=dev is incompatible with --auto\n");      
+                       exit(2);
+               }
+               mdfd = open_mddev(devlist->devname, autof);
                if (mdfd < 0)
                        exit(1);
                if ((int)ident.super_minor == -2) {
                if (mdfd < 0)
                        exit(1);
                if ((int)ident.super_minor == -2) {
@@ -593,7 +795,7 @@ int main(int argc, char *argv[])
                    ident.super_minor == UnSet && !scan ) {
                        /* Only a device has been given, so get details from config file */
                        mddev_ident_t array_ident = conf_get_ident(configfile, devlist->devname);
                    ident.super_minor == UnSet && !scan ) {
                        /* Only a device has been given, so get details from config file */
                        mddev_ident_t array_ident = conf_get_ident(configfile, devlist->devname);
-                       mdfd = open_mddev(devlist->devname);
+                       mdfd = open_mddev(devlist->devname, array_ident->autof);
                        if (mdfd < 0)
                                rv |= 1;
                        else {
                        if (mdfd < 0)
                                rv |= 1;
                        else {
@@ -618,7 +820,7 @@ int main(int argc, char *argv[])
                        }
                        for (dv = devlist ; dv ; dv=dv->next) {
                                mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
                        }
                        for (dv = devlist ; dv ; dv=dv->next) {
                                mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
-                               mdfd = open_mddev(dv->devname);
+                               mdfd = open_mddev(dv->devname, array_ident->autof);
                                if (mdfd < 0) {
                                        rv |= 1;
                                        continue;
                                if (mdfd < 0) {
                                        rv |= 1;
                                        continue;
@@ -641,7 +843,7 @@ int main(int argc, char *argv[])
                        } else
                                for (; array_list; array_list = array_list->next) {
                                        mdu_array_info_t array;
                        } else
                                for (; array_list; array_list = array_list->next) {
                                        mdu_array_info_t array;
-                                       mdfd = open_mddev(array_list->devname);
+                                       mdfd = open_mddev(array_list->devname, array_list->autof);
                                        if (mdfd < 0) {
                                                rv |= 1;
                                                continue;
                                        if (mdfd < 0) {
                                                rv |= 1;
                                                continue;
@@ -657,10 +859,10 @@ int main(int argc, char *argv[])
                }
                break;
        case BUILD:
                }
                break;
        case BUILD:
-               rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next);
+               rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next, assume_clean);
                break;
        case CREATE:
                break;
        case CREATE:
-               rv = Create(devlist->devname, mdfd, chunk, level, layout, size,
+               rv = Create(devlist->devname, mdfd, chunk, level, layout, size<0 ? 0 : size,
                            raiddisks, sparedisks,
                            devs_found-1, devlist->next, runstop, verbose, force);
                break;
                            raiddisks, sparedisks,
                            devs_found-1, devlist->next, runstop, verbose, force);
                break;
@@ -682,7 +884,7 @@ int main(int argc, char *argv[])
                        if (devlist == NULL) {
                                if ((devmode == 'S' ||devmode=='D') && scan) {
                                        /* apply to all devices in /proc/mdstat */
                        if (devlist == NULL) {
                                if ((devmode == 'S' ||devmode=='D') && scan) {
                                        /* apply to all devices in /proc/mdstat */
-                                       struct mdstat_ent *ms = mdstat_read();
+                                       struct mdstat_ent *ms = mdstat_read(0);
                                        struct mdstat_ent *e;
                                        for (e=ms ; e ; e=e->next) {
                                                char *name = get_md_name(e->devnum);
                                        struct mdstat_ent *e;
                                        for (e=ms ; e ; e=e->next) {
                                                char *name = get_md_name(e->devnum);
@@ -695,7 +897,7 @@ int main(int argc, char *argv[])
                                                if (devmode == 'D')
                                                        rv |= Detail(name, !verbose, test);
                                                else if (devmode=='S') {
                                                if (devmode == 'D')
                                                        rv |= Detail(name, !verbose, test);
                                                else if (devmode=='S') {
-                                                       mdfd = open_mddev(name);
+                                                       mdfd = open_mddev(name, 0);
                                                        if (mdfd >= 0)
                                                                rv |= Manage_runstop(name, mdfd, -1);
                                                }
                                                        if (mdfd >= 0)
                                                                rv |= Manage_runstop(name, mdfd, -1);
                                                }
@@ -715,7 +917,7 @@ int main(int argc, char *argv[])
                                case 'Q':
                                        rv |= Query(dv->devname); continue;
                                }
                                case 'Q':
                                        rv |= Query(dv->devname); continue;
                                }
-                               mdfd = open_mddev(dv->devname);
+                               mdfd = open_mddev(dv->devname, 0);
                                if (mdfd>=0)
                                        switch(dv->disposition) {
                                        case 'R':
                                if (mdfd>=0)
                                        switch(dv->disposition) {
                                        case 'R':
@@ -739,6 +941,20 @@ int main(int argc, char *argv[])
                rv= Monitor(devlist, mailaddr, program,
                            delay?delay:60, daemonise, scan, oneshot, configfile, test);
                break;
                rv= Monitor(devlist, mailaddr, program,
                            delay?delay:60, daemonise, scan, oneshot, configfile, test);
                break;
+
+       case GROW:
+               if (devs_found > 1) {
+                       fprintf(stderr, Name ": Only one device may be given for --grow\n");
+                       rv = 1;
+                       break;
+               }
+               if (size >= 0 && raiddisks) {
+                       fprintf(stderr, Name ": can only grow size OR raiddisks, not both\n");
+                       rv = 1;
+                       break;
+               }
+               rv = Manage_resize(devlist->devname, mdfd, size, raiddisks);
+               break;
        }
        exit(rv);
 }
        }
        exit(rv);
 }
index 7b455223b224e6eabcc32134b35d43cdfc621409..97390102ec28b1b4c6a9c7ee85f1cc5fe65033bf 100644 (file)
@@ -128,6 +128,22 @@ a group of arrays is that
 will, when monitoring the arrays, move a spare drive from one array in
 a group to another array in that group if the first array had a failed
 or missing drive but no spare.
 will, when monitoring the arrays, move a spare drive from one array in
 a group to another array in that group if the first array had a failed
 or missing drive but no spare.
+
+.TP
+.B auto=
+This option declares to
+.B mdadm
+that it should try to create the device file of the array if it
+doesn't already exist, or exists but with the wrong device number.
+
+The value of this option can be "yes" or "md" to indicate that a
+traditional, non-partitionable md array should be created, or "mdp",
+"part" or "partition" to indicate that a partitionable md array (only
+available in linux 2.6 and later) should be used.  This later set can
+also have a number appended to indicate how many partitions to create
+device files for, e.g.
+.BR auto=mdp5 .
+The default is 4.
 .RE
 
 .TP
 .RE
 
 .TP
@@ -191,6 +207,14 @@ ARRAY /dev/md4 uuid=b23f3c6d:aec43a9f:fd65db85:369432df
 ARRAY /dev/md5 uuid=19464854:03f71b1b:e0df2edd:246cc977
 .br
            spare-group=group1
 ARRAY /dev/md5 uuid=19464854:03f71b1b:e0df2edd:246cc977
 .br
            spare-group=group1
+.br
+# /dev/md/home is created if need to be a partitionable md array
+.br
+# any spare device number is allocated.
+.br
+ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b
+.br
+           auto=part
 
 MAILADDR root@mydomain.tld
 .br
 
 MAILADDR root@mydomain.tld
 .br
diff --git a/mdadm.h b/mdadm.h
index 6c6cc7fe450890a2dc716d0243cbffc9baf78e2b..90d3a094712d8d27f68423c4a84f2c998309d940 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -55,6 +55,7 @@ char *strncpy(char *dest, const char *src, size_t n) __THROW;
 #include       <asm/types.h>
 #include       <sys/ioctl.h>
 #define        MD_MAJOR 9
 #include       <asm/types.h>
 #include       <sys/ioctl.h>
 #define        MD_MAJOR 9
+#define MdpMinorShift 6
 
 #ifndef BLKGETSIZE64
 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
 
 #ifndef BLKGETSIZE64
 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
@@ -73,12 +74,13 @@ enum mode {
        MANAGE,
        MISC,
        MONITOR,
        MANAGE,
        MISC,
        MONITOR,
+       GROW,
 };
 
 extern char short_options[];
 extern struct option long_options[];
 extern char Version[], Usage[], Help[], OptionHelp[],
 };
 
 extern char short_options[];
 extern struct option long_options[];
 extern char Version[], Usage[], Help[], OptionHelp[],
-       Help_create[], Help_build[], Help_assemble[],
+       Help_create[], Help_build[], Help_assemble[], Help_grow[],
        Help_manage[], Help_misc[], Help_monitor[], Help_config[];
 
 /* structures read from config file */
        Help_manage[], Help_misc[], Help_monitor[], Help_config[];
 
 /* structures read from config file */
@@ -93,20 +95,22 @@ extern char Version[], Usage[], Help[], OptionHelp[],
  */
 #define UnSet (0xfffe)
 typedef struct mddev_ident_s {
  */
 #define UnSet (0xfffe)
 typedef struct mddev_ident_s {
-       char *devname;
+       char    *devname;
        
        
-       int uuid_set;
-       __u32 uuid[4];
+       int     uuid_set;
+       __u32   uuid[4];
 
        unsigned int super_minor;
 
 
        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;
+       int     level;
        unsigned int raid_disks;
        unsigned int spare_disks;
        unsigned int raid_disks;
        unsigned int spare_disks;
-       char *spare_group;
+       int     autof;          /* 1 for normal, 2 for partitioned */
+       char    *spare_group;
+
        struct mddev_ident_s *next;
 } *mddev_ident_t;
 
        struct mddev_ident_s *next;
 } *mddev_ident_t;
 
@@ -135,8 +139,9 @@ struct mdstat_ent {
        struct mdstat_ent *next;
 };
 
        struct mdstat_ent *next;
 };
 
-extern struct mdstat_ent *mdstat_read(void);
+extern struct mdstat_ent *mdstat_read(int);
 extern void free_mdstat(struct mdstat_ent *ms);
 extern void free_mdstat(struct mdstat_ent *ms);
+extern void mdstat_wait(int seconds);
 
 #ifndef Sendmail
 #define Sendmail "/usr/lib/sendmail -t"
 
 #ifndef Sendmail
 #define Sendmail "/usr/lib/sendmail -t"
@@ -151,6 +156,7 @@ 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_ro(char *devname, int fd, int readonly);
 extern int Manage_runstop(char *devname, int fd, int runstop);
+extern int Manage_resize(char *devname, int fd, long long size, int raid_disks);
 extern int Manage_subdevs(char *devname, int fd,
                          mddev_dev_t devlist);
 
 extern int Manage_subdevs(char *devname, int fd,
                          mddev_dev_t devlist);
 
@@ -165,7 +171,7 @@ extern int Assemble(char *mddev, int mdfd,
 
 extern int Build(char *mddev, int mdfd, int chunk, int level,
                 int raiddisks,
 
 extern int Build(char *mddev, int mdfd, int chunk, int level,
                 int raiddisks,
-                mddev_dev_t devlist);
+                mddev_dev_t devlist, int assume_clean);
 
 
 extern int Create(char *mddev, int mdfd,
 
 
 extern int Create(char *mddev, int mdfd,
@@ -190,6 +196,10 @@ extern int check_ext2(int fd, char *name);
 extern int check_reiser(int fd, char *name);
 extern int check_raid(int fd, char *name);
 
 extern int check_reiser(int fd, char *name);
 extern int check_raid(int fd, char *name);
 
+extern int get_mdp_major(void);
+extern int is_standard(char *dev);
+
+
 extern mddev_ident_t conf_get_ident(char *conffile, char *dev);
 extern mddev_dev_t conf_get_devs(char *conffile);
 extern char *conf_get_mailaddr(char *conffile);
 extern mddev_ident_t conf_get_ident(char *conffile, char *dev);
 extern mddev_dev_t conf_get_devs(char *conffile);
 extern char *conf_get_mailaddr(char *conffile);
index 815ccd94d0f55854d15a67311d9876db24ff56c6..7465b3406c7a7489a62b0197a3ba878900e0f1d7 100644 (file)
@@ -1,6 +1,6 @@
 Summary:     mdadm is used for controlling Linux md devices (aka RAID arrays)
 Name:        mdadm
 Summary:     mdadm is used for controlling Linux md devices (aka RAID arrays)
 Name:        mdadm
-Version:     1.5.0
+Version:     1.6.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/
 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/
diff --git a/mdassemble b/mdassemble
new file mode 100755 (executable)
index 0000000..cd8f042
Binary files /dev/null and b/mdassemble differ
index 9711e54afe46d93703b7b26ed2b63abaabb8ee7f..3204d2e468f08d30e4f5753ef2e10115d365f121 100644 (file)
--- a/mdstat.c
+++ b/mdstat.c
@@ -85,6 +85,7 @@
 
 #include       "mdadm.h"
 #include       "dlink.h"
 
 #include       "mdadm.h"
 #include       "dlink.h"
+#include       <sys/select.h>
 
 void free_mdstat(struct mdstat_ent *ms)
 {
 
 void free_mdstat(struct mdstat_ent *ms)
 {
@@ -99,13 +100,18 @@ void free_mdstat(struct mdstat_ent *ms)
        }
 }
 
        }
 }
 
-struct mdstat_ent *mdstat_read()
+static int mdstat_fd = -1;
+struct mdstat_ent *mdstat_read(int hold)
 {
        FILE *f;
        struct mdstat_ent *all, **end;
        char *line;
 
 {
        FILE *f;
        struct mdstat_ent *all, **end;
        char *line;
 
-       f = fopen("/proc/mdstat", "r");
+       if (hold && mdstat_fd != -1) {
+               lseek(mdstat_fd, 0L, 0);
+               f = fdopen(dup(mdstat_fd), "r");
+       } else
+               f = fopen("/proc/mdstat", "r");
        if (f == NULL)
                return NULL;
 
        if (f == NULL)
                return NULL;
 
@@ -141,8 +147,7 @@ struct mdstat_ent *mdstat_read()
                if (!ent) {
                        fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
                        free_line(line);
                if (!ent) {
                        fprintf(stderr, Name ": malloc failed reading /proc/mdstat.\n");
                        free_line(line);
-                       fclose(f);
-                       return all;
+                       break;
                }
                ent->dev = ent->level = ent->pattern= NULL;
                ent->next = NULL;
                }
                ent->dev = ent->level = ent->pattern= NULL;
                ent->next = NULL;
@@ -184,6 +189,20 @@ struct mdstat_ent *mdstat_read()
                *end = ent;
                end = &ent->next;
        }
                *end = ent;
                end = &ent->next;
        }
+       if (hold && mdstat_fd == -1)
+               mdstat_fd = dup(fileno(f));
        fclose(f);
        return all;
 }
        fclose(f);
        return all;
 }
+
+void mdstat_wait(int seconds)
+{
+       fd_set fds;
+       struct timeval tm;
+       FD_ZERO(&fds);
+       if (mdstat_fd >= 0)
+               FD_SET(mdstat_fd, &fds);
+       tm.tv_sec = seconds;
+       tm.tv_usec = 0;
+       select(mdstat_fd >2 ? mdstat_fd+1:3, NULL, NULL, &fds, &tm);
+}
diff --git a/t b/t
new file mode 100644 (file)
index 0000000..baf4ab5
--- /dev/null
+++ b/t
@@ -0,0 +1 @@
+ARRAY /dev/fred auto=parti /dev/fred
diff --git a/util.c b/util.c
index bdafe66cc1afe11db6d598d62f51d6bb1350fe65..2f4ad9638e71fd2c9ed757d0bd1cdc1d227ded81 100644 (file)
--- a/util.c
+++ b/util.c
@@ -421,23 +421,57 @@ int add_dev(const char *name, const struct stat *stb, int flag)
     return 0;
 }
 
     return 0;
 }
 
+int is_standard(char *dev)
+{
+       /* tests if dev is a "standard" md dev name.
+        * i.e if the last component is "/dNN" or "/mdNN",
+        * where NN is a string of digits 
+        */
+       dev = strrchr(dev, '/');
+       if (!dev)
+               return 0;
+       if (strncmp(dev, "/d",2)==0)
+               dev += 2;
+       else if (strncmp(dev, "/md", 3)==0)
+               dev += 3;
+       else
+               return 0;
+       if (!*dev)
+               return 0;
+       while (isdigit(*dev))
+               dev++;
+       if (*dev)
+               return 0;
+       return 1;
+}
+
+
+/*
+ * Find a block device with the right major/minor number.
+ * Avoid /dev/mdNN and /dev/md/dNN is possible
+ */
 char *map_dev(int major, int minor)
 {
 char *map_dev(int major, int minor)
 {
-    struct devmap *p;
-    if (!devlist_ready) {
+       struct devmap *p;
+       char *std = NULL;
+       if (!devlist_ready) {
 #ifndef __dietlibc__
 #ifndef __dietlibc__
-       nftw("/dev", add_dev, 10, FTW_PHYS);
+               nftw("/dev", add_dev, 10, FTW_PHYS);
 #else
 #else
-       ftw("/dev", add_dev, 10);
+               ftw("/dev", add_dev, 10);
 #endif
 #endif
-       devlist_ready=1;
-    }
+               devlist_ready=1;
+       }
 
 
-    for (p=devlist; p; p=p->next)
-       if (p->major == major &&
-           p->minor == minor)
-           return p->name;
-    return NULL;
+       for (p=devlist; p; p=p->next)
+               if (p->major == major &&
+                   p->minor == minor) {
+                       if (is_standard(p->name))
+                               std = p->name;
+                       else
+                               return p->name;
+               }
+       return std;
 }
 
 #endif
 }
 
 #endif
@@ -504,16 +538,20 @@ char *human_size_brief(long long bytes)
        return buf;
 }
 
        return buf;
 }
 
-static int mdp_major = -1;
-void get_mdp_major(void)
+int get_mdp_major(void)
 {
 {
-       FILE *fl = fopen("/proc/devices", "r");
+static int mdp_major = -1;
+       FILE *fl;
        char *w;
        int have_block = 0;
        int have_devices = 0;
        int last_num = -1;
        char *w;
        int have_block = 0;
        int have_devices = 0;
        int last_num = -1;
+
+       if (mdp_major != -1)
+               return mdp_major;
+       fl = fopen("/proc/devices", "r");
        if (!fl)
        if (!fl)
-               return;
+               return -1;
        while ((w = conf_word(fl, 1))) {
                if (have_block && strcmp(w, "devices:")==0)
                        have_devices = 1;
        while ((w = conf_word(fl, 1))) {
                if (have_block && strcmp(w, "devices:")==0)
                        have_devices = 1;
@@ -525,6 +563,7 @@ void get_mdp_major(void)
                free(w);
        }
        fclose(fl);
                free(w);
        }
        fclose(fl);
+       return mdp_major;
 }
 
 
 }
 
 
@@ -536,12 +575,12 @@ char *get_md_name(int dev)
        static char devname[50];
        struct stat stb;
        dev_t rdev;
        static char devname[50];
        struct stat stb;
        dev_t rdev;
+       char *dn;
 
        if (dev < 0) {
 
        if (dev < 0) {
-
-               if (mdp_major < 0) get_mdp_major();
-               if (mdp_major < 0) return NULL;
-               rdev = MKDEV(mdp_major, (-1-dev)<<6);
+               int mdp =  get_mdp_major();
+               if (mdp < 0) return NULL;
+               rdev = MKDEV(mdp, (-1-dev)<<6);
                sprintf(devname, "/dev/md/d%d", -1-dev);
                if (stat(devname, &stb) == 0
                    && (S_IFMT&stb.st_mode) == S_IFBLK
                sprintf(devname, "/dev/md/d%d", -1-dev);
                if (stat(devname, &stb) == 0
                    && (S_IFMT&stb.st_mode) == S_IFBLK
@@ -561,9 +600,13 @@ char *get_md_name(int dev)
                    && (stb.st_rdev == rdev))
                        return devname;
        }
                    && (stb.st_rdev == rdev))
                        return devname;
        }
+       dn = map_dev(MAJOR(rdev), MINOR(rdev));
+       if (dn)
+               return dn;
        sprintf(devname, "/dev/.tmp.md%d", dev);
        if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
        sprintf(devname, "/dev/.tmp.md%d", dev);
        if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
-               return NULL;
+               if (errno != EEXIST)
+                       return NULL;
 
        if (stat(devname, &stb) == 0
            && (S_IFMT&stb.st_mode) == S_IFBLK
 
        if (stat(devname, &stb) == 0
            && (S_IFMT&stb.st_mode) == S_IFBLK