]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdctl-0.6 mdctl-0.6
authorNeil Brown <neilb@suse.de>
Wed, 6 Mar 2002 23:17:40 +0000 (23:17 +0000)
committerNeil Brown <neilb@suse.de>
Wed, 6 Mar 2002 23:17:40 +0000 (23:17 +0000)
19 files changed:
Assemble.c
Build.c
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Create.c
Detail.c
Examine.c
Makefile
Manage.c
Monitor.c
ReadMe.c
TODO
config.c
makedist
mdctl.8
mdctl.c
mdctl.h
mdctl.man [new file with mode: 0644]
util.c

index 272602e908fea3602d1756d17b986ad81ced20ca..1a4cb7ed6ee22a956fbe03c4e9303d0a79a330d6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
 
 int Assemble(char *mddev, int mdfd,
             mddev_ident_t ident, char *conffile,
 
 int Assemble(char *mddev, int mdfd,
             mddev_ident_t ident, char *conffile,
-            int subdevs, char **subdev,
+            mddev_dev_t devlist,
             int readonly, int runstop,
             int verbose, int force)
 {
             int readonly, int runstop,
             int verbose, int force)
 {
@@ -67,7 +67,7 @@ int Assemble(char *mddev, int mdfd,
         *
         * If !uuidset and scan, look in conf-file for uuid
         *       If not found, give up
         *
         * If !uuidset and scan, look in conf-file for uuid
         *       If not found, give up
-        * If !subdevs and scan and uuidset, get list of devs from conf-file 
+        * If !devlist and scan and uuidset, get list of devs from conf-file 
         *
         * For each device:
         *   Check superblock - discard if bad
         *
         * For each device:
         *   Check superblock - discard if bad
@@ -94,7 +94,6 @@ int Assemble(char *mddev, int mdfd,
        int old_linux = 0;
        int vers;
        mdu_array_info_t array;
        int old_linux = 0;
        int vers;
        mdu_array_info_t array;
-       mddev_dev_t devlist = NULL;
        mdp_super_t first_super, super;
        struct {
                char *devname;
        mdp_super_t first_super, super;
        struct {
                char *devname;
@@ -108,8 +107,10 @@ int Assemble(char *mddev, int mdfd,
        int devcnt = 0, okcnt, sparecnt;
        int i;
        int most_recent = 0;
        int devcnt = 0, okcnt, sparecnt;
        int i;
        int most_recent = 0;
-       int chosen_drive = -1;
+       int chosen_drive;
        int change = 0;
        int change = 0;
+       int inargv = 0;
+       int start_partial_ok = force || devlist==NULL;
        
        vers = md_get_version(mdfd);
        if (vers <= 0) {
        
        vers = md_get_version(mdfd);
        if (vers <= 0) {
@@ -139,7 +140,7 @@ int Assemble(char *mddev, int mdfd,
         * there must be something in the identity
         */
 
         * there must be something in the identity
         */
 
-       if (subdevs == 0 &&
+       if (!devlist &&
            ident->uuid_set == 0 &&
            ident->super_minor < 0 &&
            ident->devices == NULL) {
            ident->uuid_set == 0 &&
            ident->super_minor < 0 &&
            ident->devices == NULL) {
@@ -147,8 +148,9 @@ int Assemble(char *mddev, int mdfd,
                        mddev);
                return 1;
        }
                        mddev);
                return 1;
        }
-       if (subdevs==0)
+       if (devlist == NULL)
                devlist = conf_get_devs(conffile);
                devlist = conf_get_devs(conffile);
+       else inargv = 1;
 
        first_super.md_magic = 0;
        for (i=0; i<MD_SB_DISKS; i++)
 
        first_super.md_magic = 0;
        for (i=0; i<MD_SB_DISKS; i++)
@@ -158,23 +160,15 @@ int Assemble(char *mddev, int mdfd,
            fprintf(stderr, Name ": looking for devices for %s\n",
                    mddev);
 
            fprintf(stderr, Name ": looking for devices for %s\n",
                    mddev);
 
-       while (subdevs || devlist) {
+       while ( devlist) {
                char *devname;
                int this_uuid[4];
                int dfd;
                struct stat stb;
                char *devname;
                int this_uuid[4];
                int dfd;
                struct stat stb;
-               int inargv;
                int havesuper=0;
 
                int havesuper=0;
 
-               if (subdevs) {
-                       devname = *subdev++;
-                       subdevs--;
-                       inargv=1;
-               } else {
-                       devname = devlist->devname;
-                       devlist = devlist->next;
-                       inargv=0;
-               }
+               devname = devlist->devname;
+               devlist = devlist->next;
 
                if (ident->devices &&
                    !match_oneof(ident->devices, devname))
 
                if (ident->devices &&
                    !match_oneof(ident->devices, devname))
@@ -190,11 +184,11 @@ int Assemble(char *mddev, int mdfd,
                        fprintf(stderr, Name ": fstat failed for %s: %s\n",
                                devname, strerror(errno));
                        close(dfd);
                        fprintf(stderr, Name ": fstat failed for %s: %s\n",
                                devname, strerror(errno));
                        close(dfd);
-               } if ((stb.st_mode & S_IFMT) != S_IFBLK) {
-                       fprintf(stderr, Name ": %d is not a block device.\n",
+               } else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
+                       fprintf(stderr, Name ": %s is not a block device.\n",
                                devname);
                        close(dfd);
                                devname);
                        close(dfd);
-               } if (load_super(dfd, &super)) {
+               } else if (load_super(dfd, &super)) {
                        if (inargv || verbose)
                                fprintf( stderr, Name ": no RAID superblock on %s\n",
                                         devname);
                        if (inargv || verbose)
                                fprintf( stderr, Name ": no RAID superblock on %s\n",
                                         devname);
@@ -219,14 +213,25 @@ int Assemble(char *mddev, int mdfd,
                                        devname);
                        continue;
                }
                                        devname);
                        continue;
                }
+               if (ident->level != -10 &&
+                   (!havesuper|| ident->level != super.level)) {
+                       if (inargv || verbose)
+                               fprintf(stderr, Name ": %s has wrong raid level.\n",
+                                       devname);
+                       continue;
+               }
+               if (ident->raid_disks != -1 &&
+                   (!havesuper || ident->raid_disks!= super.raid_disks)) {
+                       if (inargv || verbose)
+                               fprintf(stderr, Name ": %s requires wrong number of drives.\n",
+                                       devname);
+                       continue;
+               }
 
                /* If we are this far, then we are commited to this device.
                 * If the super_block doesn't exist, or doesn't match others,
                 * then we cannot continue
                 */
 
                /* If we are this far, then we are commited to this device.
                 * If the super_block doesn't exist, or doesn't match others,
                 * then we cannot continue
                 */
-               if (verbose)
-                       fprintf(stderr, Name ": %s is identified as a member of %s.\n",
-                               devname, mddev);
 
                if (!havesuper) {
                        fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
 
                if (!havesuper) {
                        fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
@@ -244,6 +249,9 @@ int Assemble(char *mddev, int mdfd,
                            devname);
                    continue;
                }
                            devname);
                    continue;
                }
+               if (verbose)
+                       fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n",
+                               devname, mddev, super.this_disk.raid_disk);
                devices[devcnt].devname = devname;
                devices[devcnt].major = MAJOR(stb.st_rdev);
                devices[devcnt].minor = MINOR(stb.st_rdev);
                devices[devcnt].devname = devname;
                devices[devcnt].major = MAJOR(stb.st_rdev);
                devices[devcnt].minor = MINOR(stb.st_rdev);
@@ -277,8 +285,9 @@ int Assemble(char *mddev, int mdfd,
        sparecnt=0;
        for (i=0; i< MD_SB_DISKS;i++) {
                int j = best[i];
        sparecnt=0;
        for (i=0; i< MD_SB_DISKS;i++) {
                int j = best[i];
+               int event_margin = !force;
                if (j < 0) continue;
                if (j < 0) continue;
-               if (devices[j].events+1 >=
+               if (devices[j].events+event_margin >=
                    devices[most_recent].events) {
                        devices[j].uptodate = 1;
                        if (i < first_super.raid_disks)
                    devices[most_recent].events) {
                        devices[j].uptodate = 1;
                        if (i < first_super.raid_disks)
@@ -293,6 +302,7 @@ int Assemble(char *mddev, int mdfd,
                 * and add it.
                 */
                int fd;
                 * and add it.
                 */
                int fd;
+               chosen_drive = -1;
                for (i=0; i<first_super.raid_disks; i++) {
                        int j = best[i];
                        if (j>=0 &&
                for (i=0; i<first_super.raid_disks; i++) {
                        int j = best[i];
                        if (j>=0 &&
@@ -344,6 +354,7 @@ int Assemble(char *mddev, int mdfd,
         * If there are differences and --force is given, then update this chosen
         * superblock.
         */
         * If there are differences and --force is given, then update this chosen
         * superblock.
         */
+       chosen_drive = -1;
        for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) {
                int j = best[i];
                int fd;
        for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) {
                int j = best[i];
                int fd;
@@ -368,6 +379,7 @@ int Assemble(char *mddev, int mdfd,
 
        for (i=0; i<MD_SB_DISKS; i++) {
                int j = best[i];
 
        for (i=0; i<MD_SB_DISKS; i++) {
                int j = best[i];
+               int active_sync = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
                if (j<0)
                        continue;
                if (!devices[j].uptodate)
                if (j<0)
                        continue;
                if (!devices[j].uptodate)
@@ -379,12 +391,12 @@ int Assemble(char *mddev, int mdfd,
                        super.disks[j].minor = devices[j].minor;
                }
                if (devices[j].uptodate &&
                        super.disks[j].minor = devices[j].minor;
                }
                if (devices[j].uptodate &&
-                   (super.disks[i].state & (1 << MD_DISK_FAULTY))) {
+                   (super.disks[i].state != active_sync)) {
                        if (force) {
                                fprintf(stderr, Name ": "
                        if (force) {
                                fprintf(stderr, Name ": "
-                                       "clearing FAULT flag for device %d in %s for %s\n",
+                                       "clearing FAULTY flag for device %d in %s for %s\n",
                                        j, mddev, devices[j].devname);
                                        j, mddev, devices[j].devname);
-                               super.disks[i].state &= ~(1<<MD_DISK_FAULTY);
+                               super.disks[i].state = active_sync;
                                change |= 2;
                        } else {
                                fprintf(stderr, Name ": "
                                change |= 2;
                        } else {
                                fprintf(stderr, Name ": "
@@ -460,7 +472,9 @@ int Assemble(char *mddev, int mdfd,
                
                if (runstop == 1 ||
                    (runstop == 0 && 
                
                if (runstop == 1 ||
                    (runstop == 0 && 
-                    enough(first_super.level, first_super.raid_disks, okcnt))) {
+                    ( first_super.raid_disks == okcnt
+                      || start_partial_ok && enough(first_super.level, first_super.raid_disks, okcnt))
+                           )) {
                        if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
                                fprintf(stderr, Name ": %s has been started with %d drive%s",
                                        mddev, okcnt, okcnt==1?"":"s");
                        if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
                                fprintf(stderr, Name ": %s has been started with %d drive%s",
                                        mddev, okcnt, okcnt==1?"":"s");
@@ -478,7 +492,7 @@ int Assemble(char *mddev, int mdfd,
                                mddev, okcnt, okcnt==1?"":"s");
                        return 0;
                }
                                mddev, okcnt, okcnt==1?"":"s");
                        return 0;
                }
-               fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it.\n",
+               fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it (use --run to insist).\n",
                        mddev, okcnt, okcnt==1?"":"s");
                return 1;
        } else {
                        mddev, okcnt, okcnt==1?"":"s");
                return 1;
        } else {
@@ -486,7 +500,7 @@ int Assemble(char *mddev, int mdfd,
                 * been updated to point to the current locations of devices.
                 * so we can just start the array
                 */
                 * been updated to point to the current locations of devices.
                 * so we can just start the array
                 */
-               int dev;
+               unsigned long dev;
                dev = MKDEV(devices[chosen_drive].major,
                            devices[chosen_drive].minor);
                if (ioctl(mdfd, START_ARRAY, dev)) {
                dev = MKDEV(devices[chosen_drive].major,
                            devices[chosen_drive].minor);
                if (ioctl(mdfd, START_ARRAY, dev)) {
diff --git a/Build.c b/Build.c
index 40b631f168f4787827020072f6256610263d31aa..51f2df07c3744389be1bde877ac061d63d2ba003 100644 (file)
--- a/Build.c
+++ b/Build.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
 
 int Build(char *mddev, int mdfd, int chunk, int level,
          int raiddisks,
 
 int Build(char *mddev, int mdfd, int chunk, int level,
          int raiddisks,
-         int subdevs, char *subdev[])
+         mddev_dev_t devlist)
 {
        /* Build a linear or raid0 arrays without superblocks
         * We cannot really do any checks, we just do it.
 {
        /* Build a linear or raid0 arrays without superblocks
         * We cannot really do any checks, we just do it.
@@ -53,30 +53,34 @@ int Build(char *mddev, int mdfd, int chunk, int level,
        int i;
        int vers;
        struct stat stb;
        int i;
        int vers;
        struct stat stb;
-       if (raiddisks != subdevs) {
-               fprintf(stderr, Name ": requested %d devices in array but listed %d\n",
-                       raiddisks, subdevs);
-               return 1;
-       }
+       int subdevs = 0;
+       mddev_dev_t dv;
 
        /* scan all devices, make sure they really are block devices */
 
        /* scan all devices, make sure they really are block devices */
-       for (i=0; i<subdevs; i++) {
-               if (stat(subdev[i], &stb)) {
+       for (dv = devlist; dv; dv=dv->next) {
+               if (stat(dv->devname, &stb)) {
                        fprintf(stderr, Name ": Cannot find %s: %s\n",
                        fprintf(stderr, Name ": Cannot find %s: %s\n",
-                               subdev[i], strerror(errno));
+                               dv->devname, strerror(errno));
                        return 1;
                }
                if ((stb.st_mode & S_IFMT) != S_IFBLK) {
                        fprintf(stderr, Name ": %s is not a block device.\n",
                        return 1;
                }
                if ((stb.st_mode & S_IFMT) != S_IFBLK) {
                        fprintf(stderr, Name ": %s is not a block device.\n",
-                               subdev[i]);
+                               dv->devname);
                        return 1;
                }
                        return 1;
                }
+               subdevs++;
+       }
+
+       if (raiddisks != subdevs) {
+               fprintf(stderr, Name ": requested %d devices in array but listed %d\n",
+                       raiddisks, subdevs);
+               return 1;
        }
 
        vers = md_get_version(mdfd);
        
        /* looks Ok, go for it */
        }
 
        vers = md_get_version(mdfd);
        
        /* looks Ok, go for it */
-       if (vers >= 90000) {
+       if (vers >= 9000) {
                mdu_array_info_t array;
                array.level = level;
                array.size = 0;
                mdu_array_info_t array;
                array.level = level;
                array.size = 0;
@@ -85,12 +89,14 @@ int Build(char *mddev, int mdfd, int chunk, int level,
                array.md_minor = 0;
                if (fstat(mdfd, &stb)==0)
                        array.md_minor = MINOR(stb.st_rdev);
                array.md_minor = 0;
                if (fstat(mdfd, &stb)==0)
                        array.md_minor = MINOR(stb.st_rdev);
-               array.not_persistent = 0;
+               array.not_persistent = 1;
                array.state = 0; /* not clean, but no errors */
                array.active_disks = raiddisks;
                array.working_disks = raiddisks;
                array.spare_disks = 0;
                array.failed_disks = 0;
                array.state = 0; /* not clean, but no errors */
                array.active_disks = raiddisks;
                array.working_disks = raiddisks;
                array.spare_disks = 0;
                array.failed_disks = 0;
+               if (chunk == 0)  
+                       chunk = 64;
                array.chunk_size = chunk*1024;
                if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
                        fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
                array.chunk_size = chunk*1024;
                if (ioctl(mdfd, SET_ARRAY_INFO, &array)) {
                        fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
@@ -99,18 +105,18 @@ int Build(char *mddev, int mdfd, int chunk, int level,
                }
        }
        /* now add the devices */
                }
        }
        /* now add the devices */
-       for (i=0; i<subdevs; i++) {
-               if (stat(subdev[i], &stb)) {
+       for ((i=0), (dv = devlist) ; dv ; i++, dv=dv->next) {
+               if (stat(dv->devname, &stb)) {
                        fprintf(stderr, Name ": Wierd: %s has disappeared.\n",
                        fprintf(stderr, Name ": Wierd: %s has disappeared.\n",
-                               subdev[i]);
+                               dv->devname);
                        goto abort;
                }
                        goto abort;
                }
-               if ((stb.st_rdev & S_IFMT)!= S_IFBLK) {
+               if ((stb.st_mode & S_IFMT)!= S_IFBLK) {
                        fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n",
                        fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n",
-                               subdev[i]);
+                               dv->devname);
                        goto abort;
                }
                        goto abort;
                }
-               if (vers> 90000) {
+               if (vers>= 9000) {
                        mdu_disk_info_t disk;
                        disk.number = i;
                        disk.raid_disk = i;
                        mdu_disk_info_t disk;
                        disk.number = i;
                        disk.raid_disk = i;
@@ -119,27 +125,27 @@ int Build(char *mddev, int mdfd, int chunk, int level,
                        disk.minor = MINOR(stb.st_rdev);
                        if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
                                fprintf(stderr, Name ": ADD_NEW_DISK failed for %s: %s\n",
                        disk.minor = MINOR(stb.st_rdev);
                        if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
                                fprintf(stderr, Name ": ADD_NEW_DISK failed for %s: %s\n",
-                                       subdev[i], strerror(errno));
+                                       dv->devname, strerror(errno));
                                goto abort;
                        }
                } else {
                        if (ioctl(mdfd, REGISTER_DEV, &stb.st_rdev)) {
                                fprintf(stderr, Name ": REGISTER_DEV failed for %s.\n",
                                goto abort;
                        }
                } else {
                        if (ioctl(mdfd, REGISTER_DEV, &stb.st_rdev)) {
                                fprintf(stderr, Name ": REGISTER_DEV failed for %s.\n",
-                                       subdev[i], strerror(errno));
+                                       dv->devname, strerror(errno));
                                goto abort;
                        }
                }
        }
        /* now to start it */
                                goto abort;
                        }
                }
        }
        /* now to start it */
-       if (vers > 90000) {
+       if (vers >= 9000) {
                mdu_param_t param; /* not used by syscall */
                mdu_param_t param; /* not used by syscall */
-               if (ioctl(mdfd, RUN_ARRAY, param)) {
+               if (ioctl(mdfd, RUN_ARRAY, &param)) {
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
                                strerror(errno));
                        goto abort;
                }
        } else {
                        fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
                                strerror(errno));
                        goto abort;
                }
        } else {
-               int arg;
+               unsigned long arg;
                arg=0;
                while (chunk > 4096) {
                        arg++;
                arg=0;
                while (chunk > 4096) {
                        arg++;
@@ -159,7 +165,7 @@ int Build(char *mddev, int mdfd, int chunk, int level,
        return 0;
 
  abort:
        return 0;
 
  abort:
-       if (vers > 900000)
+       if (vers >= 9000)
            ioctl(mdfd, STOP_ARRAY, 0);
        else
            ioctl(mdfd, STOP_MD, 0);
            ioctl(mdfd, STOP_ARRAY, 0);
        else
            ioctl(mdfd, STOP_MD, 0);
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..b27e2d5
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,148 @@
+
+Changes Prior to 0.6 release
+
+       -   Remove the limit on the number of device names that can be
+       given on the command line.
+    -   Fix bug in --assemble --force where it would only update a 
+       single superblock.
+    -   Fix bogus printing of big numbers not being block devices
+       when given names of devices that don't exist.
+    -   When --assemble --force, consider superblocks with an event
+       count that is 1 behind as out-of-date.  Normally they are
+       considered up-to-date (as the kernel assumes this too).
+    -   When marking drives as not-failed in the superblock, 
+       we also mark them as ACTIVE and SYNC.
+    -   Don't start arrays for which not all drives are available unless:
+        --scan   which implies that all drives were found automatically
+        --run    which means the user knows what they want
+        --force  which means that we are fixing something broken
+    -   Make sure all device numbers passed as 3rd arg of ioctl
+       are passed as unsigned lock, so that it works on SPARC
+    -   If HOT_ADD_DISK failes for -a, then only try ADD_NEW_DISK
+       if we cannot read from the array, i.e. if the array is
+       not started yet.
+    -   man page update
+    -   Taught Examine to handle --scan. It examines all devices listed
+       on DEVICE lines in the config file.  
+    -   Added --brief (-b) flag for Examine and Detail to print out
+       and mdctl.conf compatible description with uuid=, level=,
+       disks= and  - for Examine - devices=
+       --examine --brief collects all devices the make the one array and 
+       list them as one entry.
+    -   Added level= and disks= options to ARRAY lines in config files
+       so --brief output could be used as-is.
+    -   Make parity style ({left,right}-{,a}symmetric) consistantly use -,
+       never _.
+    -   Add "Array Size" to --detail output
+    -   Change "Size" to "Device Size" and exclude from Detail of arrays
+       that do not have a consistent device size.
+    -   Add Human readable MiB or GiB value on size lines of Detail and Examine
+    -   --assemble --scan  doesn't complain about active drives
+    -   require number of spares given in -x to be listed.
+    -   Made --build actually work.
+Changes Prior to 0.5 release
+
+  --assemble:
+     spare drives are handled properly.
+
+     --force can be used to recover from 2-drive failures on RAID5
+     If you belive that /dev/hda1 /dev/hdb1 /dev/hdc1 /dev/hdd1 should
+     make a raid5 array, but it has experienced multiple failures and
+     wont start, then
+
+       mdctl --assemble --force /dev/md0 /dev/hd[abcd]1
+
+     Should update the superblock on the newest failed drive and
+     restart the array in degraded mode.  You should then remove the
+     remaining failed drive and re-add it (if you are happy that it
+     might work).
+
+     Ofcourse whenever you have a 2-drive failure, you have a risk
+     of corruption in data that hasn't be changed for a long time.  So
+     this doesn't give you your array back all nice and happy, but it
+     does allow you to recover data that might not be corrupt.
+
+     More flexibility in identifying a RAID array in the mdctl.conf
+     e.g.
+         array /dev/md4  super-minor=4
+
+      assembles /dev/md4 from all devices found that have a raid
+      superblock that says the minor number of the array is 4.
+      If the blocks with the right minor number do not all have the
+      same UUID, an error is flags and no assembly happens.
+        array /dev/md3  devices=/dev/hd[abc]2
+
+      Assembles /dev/md3 drom /dev/hda2 /dev/hdb2 and/dev/hdc2.  All
+      devices must exist and have raid superblock with the same uuid.
+
+      If two identity specifiers are used, only devices that match all
+      of them are considered, so
+
+        array /dev/md2 devices=/dev/hd?2 super-minor=2
+
+      will assemble /dev/md2 using all /dev/hd?2 devices which have a 
+      raid superblock with minor number 2.
+  --create:
+      When listing devices for --create, the word "missing" can be
+      used to indicate that the respective slot does not have a
+      working drive currently.  This is similar to the "failed-disk"
+      directive in mkraid/raidtab.
+      e.g.
+         mdctl --create --level=5 -raid-disks=4 --spare-disks=2
+                 /dev/md0 /dev/sda /dev/sdb missing /dev/sdc /dev/sdd  /dev/sde
+
+      will create a raid5 array with the third slot empty, and two
+      spares.
+
+      By default, raid5 arrays are created with the last slot empty
+      and drive listed for the last slot added as a spare.  If a
+      "missing" slot is given, or if --force is given, then --create
+      does exactly what you ask and doesn't try to be clever.
+   
+
+   --follow / --monitor:
+
+      This is a new mode.  I couldn't stop my self from picking a name
+      starting with F (as current modes start A,B,C,D,E) but I
+      relented and provided an alternate name that is somewhat more
+      meaningful. 
+      In this mode, mdctl does not exit, but runs continuously and
+      periodically polls all the md devices to see if they have had
+      any interested state change.
+      The changes that it currently notices are:
+           Fail      -  an active disc fails
+           FailSpare -  a spare, that was presumably being build, fails
+           ActiveSpare - a spare becomes active, presumably after a rebuild.
+
+      Options:
+         --mail mailaddress  - send Email on any Fail* event
+         --program program   - run the program on any event.  
+                  Args are: eventname mddevice subdevice(if-known)
+         --delay  seconds    - change from the default 60second pause
+                              between polls.
+
+      I plan to add functionality to this mode to allow sharing of
+      spare drives. If an array is marks "spare-group=fred", and it
+      has a failed drive and no spares, and if some other array is
+      also "spare-group=fred" and it has no failed drives, but does
+      have a spare drive that is big enough, the spare will be moved
+      to the first array.
+
+  I also have the idea of adding a --grow mode which will re-organise
+  the data on an N disk raid0/4/5 array to be on an N+M disk array.
+  I have no concrete plans for this though.
+
+  I got rid of the "v" in the archive file name, and include the
+  version number in the directory created by the archive.
+
+  There is now a man page and mdctl.spec (for rpm) thanks to
+  Danilo Godec <danci@agenda.si>.
+  
+  Ofcourse, the man page is now out of date and despite being based on
+  the --help output, is not wholy correct.  After I get --follow
+  working properly, I plan to revise the various documentation and/or
+  the code to make sure the two match.
+
index c7d35979a443c22f625069869d68ab9cddba1266..55a9eca7408a84e16bddb7be5ec409b057601c78 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
 
 int Create(char *mddev, int mdfd,
           int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
 
 int Create(char *mddev, int mdfd,
           int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
-          int subdevs, char *subdev[],
+          int subdevs, mddev_dev_t devlist,
           int runstop, int verbose, int force)
 {
        /*
           int runstop, int verbose, int force)
 {
        /*
@@ -53,8 +53,10 @@ int Create(char *mddev, int mdfd,
         * RUN_ARRAY
         */
        int minsize, maxsize;
         * RUN_ARRAY
         */
        int minsize, maxsize;
-       int maxdisc= -1, mindisc = -1;
+       char *mindisc = NULL;
+       char *maxdisc = NULL;
        int i;
        int i;
+       mddev_dev_t dv;
        int fail=0, warn=0;
        struct stat stb;
        int first_missing = MD_SB_DISKS*2;
        int fail=0, warn=0;
        struct stat stb;
        int first_missing = MD_SB_DISKS*2;
@@ -93,7 +95,7 @@ int Create(char *mddev, int mdfd,
                fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
                return 1;
        }
                fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
                return 1;
        }
-       if (subdevs < raiddisks) {
+       if (subdevs < raiddisks+sparedisks) {
                fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
                return 1;
        }
                fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
                return 1;
        }
@@ -121,11 +123,11 @@ int Create(char *mddev, int mdfd,
        /* now look at the subdevs */
        array.active_disks = 0;
        array.working_disks = 0;
        /* now look at the subdevs */
        array.active_disks = 0;
        array.working_disks = 0;
-       for (i=0; i<subdevs; i++) {
-               char *dname = subdev[i];
+       for (dv=devlist; dv; dv=dv->next) {
+               char *dname = dv->devname;
                int dsize, freesize;
                int fd;
                int dsize, freesize;
                int fd;
-               if (strcasecmp(subdev[i], "missing")==0) {
+               if (strcasecmp(dname, "missing")==0) {
                        if (first_missing > i)
                                first_missing = i;
                        missing_disks ++;
                        if (first_missing > i)
                                first_missing = i;
                        missing_disks ++;
@@ -165,12 +167,12 @@ int Create(char *mddev, int mdfd,
                        close(fd);
                        continue;
                }
                        close(fd);
                        continue;
                }
-               if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) {
-                       maxdisc = i;
+               if (maxdisc == NULL || (maxdisc && freesize > maxsize)) {
+                       maxdisc = dname;
                        maxsize = freesize;
                }
                        maxsize = freesize;
                }
-               if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) {
-                       mindisc = i;
+               if (mindisc ==NULL || (mindisc && freesize < minsize)) {
+                       mindisc = dname;
                        minsize = freesize;
                }
                warn |= check_ext2(fd, dname);
                        minsize = freesize;
                }
                warn |= check_ext2(fd, dname);
@@ -183,7 +185,7 @@ int Create(char *mddev, int mdfd,
                return 1;
        }
        if (size == 0) {
                return 1;
        }
        if (size == 0) {
-               if (mindisc == -1) {
+               if (mindisc == NULL) {
                        fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
                        return 1;
                }
                        fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
                        return 1;
                }
@@ -193,7 +195,7 @@ int Create(char *mddev, int mdfd,
        }
        if ((maxsize-size)*100 > maxsize) {
                fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
        }
        if ((maxsize-size)*100 > maxsize) {
                fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
-                       subdev[maxdisc], size);
+                       maxdisc, size);
                warn = 1;
        }
 
                warn = 1;
        }
 
@@ -267,7 +269,7 @@ int Create(char *mddev, int mdfd,
                return 1;
        }
        
                return 1;
        }
        
-       for (i=0; i<subdevs; i++) {
+       for (i=0, dv = devlist ; dv ; dv=dv->next, i++) {
                int fd;
                struct stat stb;
                mdu_disk_info_t disk;
                int fd;
                struct stat stb;
                mdu_disk_info_t disk;
@@ -280,15 +282,15 @@ int Create(char *mddev, int mdfd,
                        disk.state = 6; /* active and in sync */
                else
                        disk.state = 0;
                        disk.state = 6; /* active and in sync */
                else
                        disk.state = 0;
-               if (strcasecmp(subdev[i], "missing")==0) {
+               if (strcasecmp(dv->devname, "missing")==0) {
                        disk.major = 0;
                        disk.minor = 0;
                        disk.state = 1; /* faulty */
                } else {
                        disk.major = 0;
                        disk.minor = 0;
                        disk.state = 1; /* faulty */
                } else {
-                       fd = open(subdev[i], O_RDONLY, 0);
+                       fd = open(dv->devname, O_RDONLY, 0);
                        if (fd < 0) {
                                fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
                        if (fd < 0) {
                                fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
-                                       subdev[i]);
+                                       dv->devname);
                                return 1;
                        }
                        fstat(fd, &stb);
                                return 1;
                        }
                        fstat(fd, &stb);
@@ -298,7 +300,7 @@ int Create(char *mddev, int mdfd,
                }
                if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
                        fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
                }
                if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
                        fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
-                               subdev[i], strerror(errno));
+                               dv->devname, strerror(errno));
                        return 1;
                }
        }
                        return 1;
                }
        }
index 026c3b3de91cd8893da28872d5176f68d10e2da0..7c2860d62c957d35e842118a0fd4dbee0dc9c331 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
 #include       "md_p.h"
 #include       "md_u.h"
 
 #include       "md_p.h"
 #include       "md_u.h"
 
-int Detail(char *dev)
+int Detail(char *dev, int brief)
 {
        /*
         * Print out details for an md array by using
 {
        /*
         * Print out details for an md array by using
@@ -77,48 +77,59 @@ int Detail(char *dev)
                return 1;
        }
        /* Ok, we have some info to print... */
                return 1;
        }
        /* Ok, we have some info to print... */
-       printf("%s:\n", dev);
-       printf("        Version : %02d.%02d.%02d\n",
-              array.major_version, array.minor_version, array.patch_version);
-       atime = array.ctime;
-       printf("  Creation Time : %.24s\n", ctime(&atime));
        c = map_num(pers, array.level);
        c = map_num(pers, array.level);
-       printf("     Raid Level : %s\n", c?c:"-unknown-");
-       printf("           Size : %d\n", array.size);
-       printf("     Raid Disks : %d\n", array.raid_disks);
-       printf("    Total Disks : %d\n", array.nr_disks);
-       printf("Preferred Minor : %d\n", array.md_minor);
-       printf("    Persistance : Superblock is %spersistant\n",
-              array.not_persistent?"not ":"");
-       printf("\n");
-       atime = array.utime;
-       printf("    Update Time : %.24s\n", ctime(&atime));
-       printf("          State : %s, %serrors\n",
-              (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
-              (array.state&(1<<MD_SB_ERRORS))?"":"no-");
-       printf("  Active Drives : %d\n", array.active_disks);
-       printf(" Working Drives : %d\n", array.working_disks);
-       printf("  Failed Drives : %d\n", array.failed_disks);
-       printf("   Spare Drives : %d\n", array.spare_disks);
-       printf("\n");
-       if (array.level == 5) {
-               c = map_num(r5layout, array.layout);
-               printf("         Layout : %s\n", c?c:"-unknown-");
-       }
-       switch (array.level) {
-       case 0:
-       case 4:
-       case 5:
-               printf("     Chunk Size : %dK\n", array.chunk_size/1024);
-               break;
-       case -1:
-               printf("       Rounding : %dK\n", array.chunk_size/1024);
-               break;
-       default: break;
-       }
+       if (brief) 
+               printf("ARRAY %s level=%s disks=%d", dev, c?c:"-unknown-",array.raid_disks );
+       else {
+               int array_size;
+               if (ioctl(fd, BLKGETSIZE, &array_size))
+                       array_size = 0;
+               else array_size>>= 1;
+               printf("%s:\n", dev);
+               printf("        Version : %02d.%02d.%02d\n",
+                      array.major_version, array.minor_version, array.patch_version);
+               atime = array.ctime;
+               printf("  Creation Time : %.24s\n", ctime(&atime));
+               printf("     Raid Level : %s\n", c?c:"-unknown-");
+               if (array_size)
+               printf("     Array Size : %d%s\n", array_size, human_size(array_size));
+               if (array.level >= 1)
+                       printf("    Device Size : %d%s\n", array.size, human_size(array.size));
+               printf("     Raid Disks : %d\n", array.raid_disks);
+               printf("    Total Disks : %d\n", array.nr_disks);
+               printf("Preferred Minor : %d\n", array.md_minor);
+               printf("    Persistance : Superblock is %spersistant\n",
+                      array.not_persistent?"not ":"");
+               printf("\n");
+               atime = array.utime;
+               printf("    Update Time : %.24s\n", ctime(&atime));
+               printf("          State : %s, %serrors\n",
+                      (array.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
+                      (array.state&(1<<MD_SB_ERRORS))?"":"no-");
+               printf("  Active Drives : %d\n", array.active_disks);
+               printf(" Working Drives : %d\n", array.working_disks);
+               printf("  Failed Drives : %d\n", array.failed_disks);
+               printf("   Spare Drives : %d\n", array.spare_disks);
+               printf("\n");
+               if (array.level == 5) {
+                       c = map_num(r5layout, array.layout);
+                       printf("         Layout : %s\n", c?c:"-unknown-");
+               }
+               switch (array.level) {
+               case 0:
+               case 4:
+               case 5:
+                       printf("     Chunk Size : %dK\n", array.chunk_size/1024);
+                       break;
+               case -1:
+                       printf("       Rounding : %dK\n", array.chunk_size/1024);
+                       break;
+               default: break;
+               }
        
        
-       printf("\n");
-       printf("    Number   Major   Minor   RaidDisk   State\n");
+               printf("\n");
+               printf("    Number   Major   Minor   RaidDisk   State\n");
+       }
        for (d= 0; d<array.raid_disks+array.spare_disks; d++) {
                mdu_disk_info_t disk;
                char *dv;
        for (d= 0; d<array.raid_disks+array.spare_disks; d++) {
                mdu_disk_info_t disk;
                char *dv;
@@ -128,34 +139,40 @@ int Detail(char *dev)
                                d, strerror(errno));
                        continue;
                }
                                d, strerror(errno));
                        continue;
                }
-               printf("   %5d   %5d    %5d    %5d     ", 
-                      disk.number, disk.major, disk.minor, disk.raid_disk);
-               if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty");
-               if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active");
-               if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync");
-               if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed");
+               if (!brief) {
+                       printf("   %5d   %5d    %5d    %5d     ", 
+                              disk.number, disk.major, disk.minor, disk.raid_disk);
+                       if (disk.state & (1<<MD_DISK_FAULTY)) printf(" faulty");
+                       if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active");
+                       if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync");
+                       if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed");
+               }
                if ((dv=map_dev(disk.major, disk.minor))) {
                if ((dv=map_dev(disk.major, disk.minor))) {
-                   printf("   %s", dv);
-                   if (!have_super) {
-                       /* try to read the superblock from this device
-                        * to get more info
-                        */
-                       int fd = open(dv, O_RDONLY);
-                       if (fd >=0 &&
-                           load_super(fd, &super) ==0 &&
-                           super.ctime == array.ctime &&
-                           super.level == array.level)
-                           have_super = 1;
-                   }
+                       if (!brief) printf("   %s", dv);
+                       if (!have_super) {
+                               /* try to read the superblock from this device
+                                * to get more info
+                                */
+                               int fd = open(dv, O_RDONLY);
+                               if (fd >=0 &&
+                                   load_super(fd, &super) ==0 &&
+                                   super.ctime == array.ctime &&
+                                   super.level == array.level)
+                                       have_super = 1;
+                       }
                }
                }
-               printf("\n");
+               if (!brief) printf("\n");
        }
        if (have_super) {
        }
        if (have_super) {
+               if (brief) printf(" UUID=");
+               else printf("           UUID : ");
                if (super.minor_version >= 90)
                if (super.minor_version >= 90)
-               printf("           UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1,
-                      super.set_uuid2, super.set_uuid3);
-       else
-               printf("           UUID : %08x\n", super.set_uuid0);
+                       printf("%08x:%08x:%08x:%08x", super.set_uuid0, super.set_uuid1,
+                              super.set_uuid2, super.set_uuid3);
+               else
+                       printf("%08x", super.set_uuid0);
+               if (!brief) printf("\n");
        }
        }
+       if (brief) printf("\n");
        return 0;
 }
        return 0;
 }
index bb4290dc318f60333a507e15f392d7d2a36a13c9..c8fbfbbb07d299bafbd73dfea2826e37a3ea367d 100644 (file)
--- a/Examine.c
+++ b/Examine.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  */
 
 #include       "mdctl.h"
  */
 
 #include       "mdctl.h"
+#include       "dlink.h"
 
 #if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
 #error no endian defined
 #endif
 #include       "md_u.h"
 #include       "md_p.h"
 
 #if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
 #error no endian defined
 #endif
 #include       "md_u.h"
 #include       "md_p.h"
-int Examine(char *dev)
+int Examine(mddev_dev_t devlist, int brief, char *conffile)
 {
 
        /* Read the raid superblock from a device and
 {
 
        /* Read the raid superblock from a device and
@@ -49,120 +50,186 @@ int Examine(char *dev)
         *
         *   utime, state etc
         *
         *
         *   utime, state etc
         *
+        * If (brief) gather devices for same array and just print a mdctl.conf line including devices=
+        * if devlist==NULL, use conf_get_devs(
         */
         */
-       int fd = open(dev, O_RDONLY);
+       int fd
        time_t atime;
        mdp_super_t super;
        int d;
        char *c;
        time_t atime;
        mdp_super_t super;
        int d;
        char *c;
-       int rv;
+       int rv = 0;
+       int err;
+       int scan= 0;
 
 
-       if (fd < 0) {
-               fprintf(stderr,Name ": cannot open %s: %s\n",
-                       dev, strerror(errno));
+       struct array {
+               mdp_super_t super;
+               void *devs;
+               struct array *next;
+       } *arrays = NULL;
+
+       if (devlist == NULL) {
+               devlist = conf_get_devs(conffile);
+               scan=1;
+       }
+       if (devlist == NULL) {
+               fprintf(stderr, Name ": No devices listed in %s\n", conffile);
                return 1;
        }
 
                return 1;
        }
 
-       rv = load_super(fd, &super);
-       close(fd);
-       switch(rv) {
-       case 1:
-               fprintf(stderr, Name ": cannot find device size for %s: %s\n",
-                       dev, strerror(errno));
-               return 1;
-       case 2:
+       for (; devlist ; devlist=devlist->next) {
+               fd = open(devlist->devname, O_RDONLY);
+               if (fd < 0) {
+                       if (!scan)
+                               fprintf(stderr,Name ": cannot open %s: %s\n",
+                                       devlist->devname, strerror(errno));
+                       err = 1;
+               }
+               else {
+                       err = load_super(fd, &super);
+                       close(fd);
+               }
+               if (err && (brief||scan))
+                       continue;
+               if (err) rv =1;
+               switch(err) {
+               case 1:
+                       fprintf(stderr, Name ": cannot find device size for %s: %s\n",
+                               devlist->devname, strerror(errno));
+                       continue;
+               case 2:
 /*             fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n",
 /*             fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n",
-                       dev, size);
+               devlist->devname, size);
 */
 */
-               fprintf(stderr, Name ": %s is too small for md\n",
-                       dev);
-               return 1;
-       case 3:
-               fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
-                       dev, strerror(errno));
-               return 1;
-       case 4:
-               fprintf(stderr, Name ": Cannot read superblock on %s\n",
-                       dev);
-               return 1;
-       case 5:
-               fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
-                       dev, MD_SB_MAGIC, super.md_magic);
-               return 1;
-       case 6:
-               fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
-                       dev, super.major_version);
-               return 1;
-       }
+                       fprintf(stderr, Name ": %s is too small for md\n",
+                               devlist->devname);
+                       continue;
+               case 3:
+                       fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
+                               devlist->devname, strerror(errno));
+                       continue;
+               case 4:
+                       fprintf(stderr, Name ": Cannot read superblock on %s\n",
+                               devlist->devname);
+                       continue;
+               case 5:
+                       fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
+                               devlist->devname, MD_SB_MAGIC, super.md_magic);
+                       continue;
+               case 6:
+                       fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
+                               devlist->devname, super.major_version);
+                       continue;
+               }
     
     
-       /* Ok, its good enough to try, though the checksum could be wrong */
-       printf("%s:\n",dev);
-       printf("          Magic : %08x\n", super.md_magic);
-       printf("        Version : %02d.%02d.%02d\n", super.major_version, super.minor_version,
-              super.patch_version);
-       if (super.minor_version >= 90)
-               printf("           UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1,
-                      super.set_uuid2, super.set_uuid3);
-       else
-               printf("           UUID : %08x\n", super.set_uuid0);
+               /* Ok, its good enough to try, though the checksum could be wrong */
+               if (brief) {
+                       struct array *ap;
+                       char *d;
+                       for (ap=arrays; ap; ap=ap->next) {
+                               if (compare_super(&ap->super, &super)==0)
+                                       break;
+                       }
+                       if (!ap) {
+                               ap = malloc(sizeof(*ap));
+                               ap->super = super;
+                               ap->devs = dl_head();
+                               ap->next = arrays;
+                               arrays = ap;
+                       }
+                       d = dl_strdup(devlist->devname);
+                       dl_add(ap->devs, d);
+               } else {
+                       printf("%s:\n",devlist->devname);
+                       printf("          Magic : %08x\n", super.md_magic);
+                       printf("        Version : %02d.%02d.%02d\n", super.major_version, super.minor_version,
+                              super.patch_version);
+                       if (super.minor_version >= 90)
+                               printf("           UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1,
+                                      super.set_uuid2, super.set_uuid3);
+                       else
+                               printf("           UUID : %08x\n", super.set_uuid0);
 
 
-       atime = super.ctime;
-       printf("  Creation Time : %.24s\n", ctime(&atime));
-       c=map_num(pers, super.level);
-       printf("     Raid Level : %s\n", c?c:"-unknown-");
-       printf("           Size : %d\n", super.size);
-       printf("     Raid Disks : %d\n", super.raid_disks);
-       printf("    Total Disks : %d\n", super.nr_disks);
-       printf("Preferred Minor : %d\n", super.md_minor);
-       printf("\n");
-       atime = super.utime;
-       printf("    Update Time : %.24s\n", ctime(&atime));
-       printf("          State : %s, %serrors\n",
-              (super.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
-              (super.state&(1<<MD_SB_ERRORS))?"":"no-");
-       printf("  Active Drives : %d\n", super.active_disks);
-       printf(" Working Drives : %d\n", super.working_disks);
-       printf("  Failed Drives : %d\n", super.failed_disks);
-       printf("   Spare Drives : %d\n", super.spare_disks);
-       if (calc_sb_csum(&super) == super.sb_csum)
-           printf("       Checksum : %x - correct\n", super.sb_csum);
-       else
-           printf("       Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super));
-       printf("         Events : %d.%d\n", super.events_hi, super.events_lo);
-       printf("\n");
-       if (super.level == 5) {
-               c = map_num(r5layout, super.layout);
-               printf("         Layout : %s\n", c?c:"-unknown-");
-       }
-       switch(super.level) {
-       case 0:
-       case 4:
-       case 5:
-               printf("     Chunk Size : %dK\n", super.chunk_size/1024);
-               break;
-       case -1:
-               printf("       Rounding : %dK\n", super.chunk_size/1024);
-               break;
-       default: break;         
+                       atime = super.ctime;
+                       printf("  Creation Time : %.24s\n", ctime(&atime));
+                       c=map_num(pers, super.level);
+                       printf("     Raid Level : %s\n", c?c:"-unknown-");
+                       printf("    Device Size : %d%s\n", super.size, human_size(super.size));
+                       printf("     Raid Disks : %d\n", super.raid_disks);
+                       printf("    Total Disks : %d\n", super.nr_disks);
+                       printf("Preferred Minor : %d\n", super.md_minor);
+                       printf("\n");
+                       atime = super.utime;
+                       printf("    Update Time : %.24s\n", ctime(&atime));
+                       printf("          State : %s, %serrors\n",
+                              (super.state&(1<<MD_SB_CLEAN))?"clean":"dirty",
+                              (super.state&(1<<MD_SB_ERRORS))?"":"no-");
+                       printf("  Active Drives : %d\n", super.active_disks);
+                       printf(" Working Drives : %d\n", super.working_disks);
+                       printf("  Failed Drives : %d\n", super.failed_disks);
+                       printf("   Spare Drives : %d\n", super.spare_disks);
+                       if (calc_sb_csum(&super) == super.sb_csum)
+                               printf("       Checksum : %x - correct\n", super.sb_csum);
+                       else
+                               printf("       Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super));
+                       printf("         Events : %d.%d\n", super.events_hi, super.events_lo);
+                       printf("\n");
+                       if (super.level == 5) {
+                               c = map_num(r5layout, super.layout);
+                               printf("         Layout : %s\n", c?c:"-unknown-");
+                       }
+                       switch(super.level) {
+                       case 0:
+                       case 4:
+                       case 5:
+                               printf("     Chunk Size : %dK\n", super.chunk_size/1024);
+                               break;
+                       case -1:
+                               printf("       Rounding : %dK\n", super.chunk_size/1024);
+                               break;
+                       default: break;         
+                       }
+                       printf("\n");
+                       printf("      Number   Major   Minor   RaidDisk   State\n");
+                       for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) {
+                               mdp_disk_t *dp;
+                               char *dv;
+                               char nb[5];
+                               if (d>=0) dp = &super.disks[d];
+                               else dp = &super.this_disk;
+                               sprintf(nb, "%4d", d);
+                               printf("%4s %5d   %5d    %5d    %5d     ", d < 0 ? "this" :  nb,
+                                      dp->number, dp->major, dp->minor, dp->raid_disk);
+                               if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty");
+                               if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
+                               if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
+                               if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
+                               if ((dv=map_dev(dp->major, dp->minor)))
+                                       printf("   %s", dv);
+                               printf("\n");
+                       }
+               }
        }
        }
-       printf("\n");
-       printf("      Number   Major   Minor   RaidDisk   State\n");
-       for (d= -1; d<(signed int)(super.raid_disks+super.spare_disks); d++) {
-               mdp_disk_t *dp;
-               char *dv;
-               char nb[5];
-               if (d>=0) dp = &super.disks[d];
-               else dp = &super.this_disk;
-               sprintf(nb, "%4d", d);
-               printf("%4s %5d   %5d    %5d    %5d     ", d < 0 ? "this" :  nb,
-                      dp->number, dp->major, dp->minor, dp->raid_disk);
-               if (dp->state & (1<<MD_DISK_FAULTY)) printf(" faulty");
-               if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active");
-               if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync");
-               if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed");
-               if ((dv=map_dev(dp->major, dp->minor)))
-                   printf("   %s", dv);
-               printf("\n");
+       if (brief) {
+               struct array *ap;
+               for (ap=arrays; ap; ap=ap->next) {
+                       char sep='=';
+                       char *c=map_num(pers, ap->super.level);
+                       char *d;
+                       printf("ARRAY /dev/md%d level=%s disks=%d UUID=",
+                              ap->super.md_minor, c?c:"-unknown-", ap->super.raid_disks);
+                       if (ap->super.minor_version >= 90)
+                               printf("%08x:%08x:%08x:%08x", ap->super.set_uuid0, ap->super.set_uuid1,
+                                      ap->super.set_uuid2, ap->super.set_uuid3);
+                       else
+                               printf("%08x", ap->super.set_uuid0);
+                       printf("\n   devices");
+                       for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) {
+                               printf("%c%s", sep, d);
+                               sep=',';
+                       }
+                       printf("\n");
+               }
        }
        }
-       return 0;
+       return rv;
 }
 }
index 5d0b1428aba0ee71eef75006fc9b706cdc70dc19..551345162d55a22a8152c00be71d03a3f65cd3d2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 #
 # mdctl - manage Linux "md" devices aka RAID arrays.
 #
 #
 # mdctl - manage Linux "md" devices aka RAID arrays.
 #
-# Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+# Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
 #
 #
 #    This program is free software; you can redistribute it and/or modify
 #
 #
 #    This program is free software; you can redistribute it and/or modify
 #           Australia
 #
 
 #           Australia
 #
 
+CC = gcc
 CFLAGS = -Wall,error,strict-prototypes -ggdb
 
 CFLAGS = -Wall,error,strict-prototypes -ggdb
 
+INSTALL = /usr/bin/install
+DESTDIR = /sbin
+
 OBJS =  mdctl.o config.o  ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Monitor.o dlink.o
 OBJS =  mdctl.o config.o  ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o Monitor.o dlink.o
-all : mdctl
+
+all : mdctl mdctl.man
 
 mdctl : $(OBJS)
        $(CC) -o mdctl $^
 
 
 mdctl : $(OBJS)
        $(CC) -o mdctl $^
 
+mdctl.man : mdctl.8
+       nroff -man mdctl.8 > mdctl.man
+
 $(OBJS) : mdctl.h
 
 $(OBJS) : mdctl.h
 
+install : mdctl
+       $(INSTALL) -m 755 mdctl $(DESTDIR)/sbin
+
 clean : 
 clean : 
-       rm -f mdctl $(OBJS) core
+       rm -f mdctl $(OBJS) core mdctl.man
 
 dist : clean
        ./makedist
 
 dist : clean
        ./makedist
index d8cc1362dc5c1aecfdc41a924270a763c6d9539f..cab49bcc04b2ed43a61e1fca8ea658197f6d1ee2 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -116,8 +116,8 @@ int Manage_runstop(char *devname, int fd, int runstop)
 }
 
 int Manage_subdevs(char *devname, int fd,
 }
 
 int Manage_subdevs(char *devname, int fd,
-                  int devcnt, char *devnames[], int devmodes[])
- {
+                  mddev_dev_t devlist)
+{
        /* do something to each dev.
         * devmode can be
         *  'a' - add the device
        /* do something to each dev.
         * devmode can be
         *  'a' - add the device
@@ -128,37 +128,49 @@ int Manage_subdevs(char *devname, int fd,
         */
        mdu_array_info_t array;
        mdu_disk_info_t disc;
         */
        mdu_array_info_t array;
        mdu_disk_info_t disc;
+       mddev_dev_t dv;
        struct stat stb;
        int i,j;
        struct stat stb;
        int i,j;
+       int save_errno;
+       static buf[4096];
 
        if (ioctl(fd, GET_ARRAY_INFO, &array)) {
                fprintf(stderr, Name ": cannot get array info for %s\n",
                        devname);
                return 1;
        }
 
        if (ioctl(fd, GET_ARRAY_INFO, &array)) {
                fprintf(stderr, Name ": cannot get array info for %s\n",
                        devname);
                return 1;
        }
-       for (i=0 ; i<devcnt; i++) {
-               if (stat(devnames[i], &stb)) {
+       for (dv = devlist ; dv; dv=dv->next) {
+               if (stat(dv->devname, &stb)) {
                        fprintf(stderr, Name ": cannot find %s: %s\n",
                        fprintf(stderr, Name ": cannot find %s: %s\n",
-                               devnames[i], strerror(errno));
+                               dv->devname, strerror(errno));
                        return 1;
                }
                if ((stb.st_mode & S_IFMT) != S_IFBLK) {
                        fprintf(stderr, Name ": %s is not a block device.\n",
                        return 1;
                }
                if ((stb.st_mode & S_IFMT) != S_IFBLK) {
                        fprintf(stderr, Name ": %s is not a block device.\n",
-                               devnames[i]);
+                               dv->devname);
                        return 1;
                }
                        return 1;
                }
-               switch(devmodes[i]){
+               switch(dv->disposition){
                default:
                        fprintf(stderr, Name ": internal error - devmode[%d]=%d\n",
                default:
                        fprintf(stderr, Name ": internal error - devmode[%d]=%d\n",
-                               i, devmodes[i]);
+                               i, dv->disposition);
                        return 1;
                case 'a':
                        /* add the device - hot or cold */
                        return 1;
                case 'a':
                        /* add the device - hot or cold */
-                       if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) {
+                       if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) {
                                fprintf(stderr, Name ": hot added %s\n",
                                fprintf(stderr, Name ": hot added %s\n",
-                                       devnames[i]);
+                                       dv->devname);
                                continue;
                        }
                                continue;
                        }
+                       save_errno = errno;
+                       if (read(fd, buf, sizeof(buf)) > 0) {
+                               /* array is active, so don't try to add.
+                                * i.e. something is wrong 
+                                */
+                               fprintf(stderr, Name ": hot add failed for %s: %s\n",
+                                       dv->devname, strerror(save_errno));
+                               return 1;
+                       }
                        /* try ADD_NEW_DISK.
                         * we might be creating, we might be assembling,
                         * it is hard to tell.
                        /* try ADD_NEW_DISK.
                         * we might be creating, we might be assembling,
                         * it is hard to tell.
@@ -180,32 +192,32 @@ int Manage_subdevs(char *devname, int fd,
                        disc.minor = MINOR(stb.st_rdev);
                        if (ioctl(fd,ADD_NEW_DISK, &disc)) {
                                fprintf(stderr, Name ": add new disk failed for %s: %s\n",
                        disc.minor = MINOR(stb.st_rdev);
                        if (ioctl(fd,ADD_NEW_DISK, &disc)) {
                                fprintf(stderr, Name ": add new disk failed for %s: %s\n",
-                                       devnames[i], strerror(errno));
+                                       dv->devname, strerror(errno));
                                return 1;
                        }
                                return 1;
                        }
-                       fprintf(stderr, Name ": added %s\n", devnames[i]);
+                       fprintf(stderr, Name ": added %s\n", dv->devname);
                        break;
 
                case 'r':
                        /* hot remove */
                        /* FIXME check that it is a current member */
                        break;
 
                case 'r':
                        /* hot remove */
                        /* FIXME check that it is a current member */
-                       if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) {
+                       if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) {
                                fprintf(stderr, Name ": hot remove failed for %s: %s\n",
                                fprintf(stderr, Name ": hot remove failed for %s: %s\n",
-                                       devnames[i], strerror(errno));
+                                       dv->devname, strerror(errno));
                                return 1;
                        }
                                return 1;
                        }
-                       fprintf(stderr, Name ": hot removed %s\n", devnames[i]);
+                       fprintf(stderr, Name ": hot removed %s\n", dv->devname);
                        break;
 
                case 'f': /* set faulty */
                        /* FIXME check current member */
                        break;
 
                case 'f': /* set faulty */
                        /* FIXME check current member */
-                       if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) {
+                       if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
                                fprintf(stderr, Name ": set disk faulty failed for %s:  %s\n",
                                fprintf(stderr, Name ": set disk faulty failed for %s:  %s\n",
-                                       devnames[i], strerror(errno));
+                                       dv->devname, strerror(errno));
                                return 1;
                        }
                        fprintf(stderr, Name ": set %s faulty in %s\n",
                                return 1;
                        }
                        fprintf(stderr, Name ": set %s faulty in %s\n",
-                               devnames[i], devname);
+                               dv->devname, devname);
                        break;
                }
        }
                        break;
                }
        }
index 968e4b3e4a4fe844feba4941ccd85520d1461c19..4f4aa0ec9debec2ea8142fc82328e3ca9ed6b3b8 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
 
 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
 
 
 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd);
 
-int Monitor(int num_devs, char *devlist[],
+int Monitor(mddev_dev_t devlist,
            char *mailaddr, char *alert_cmd,
            int period,
            char *config)
            char *mailaddr, char *alert_cmd,
            int period,
            char *config)
@@ -75,10 +75,12 @@ int Monitor(int num_devs, char *devlist[],
        int finished = 0;
        while (! finished) {
                mddev_ident_t mdlist = NULL;
        int finished = 0;
        while (! finished) {
                mddev_ident_t mdlist = NULL;
+               mddev_dev_t dv;
                int dnum=0;
                int dnum=0;
-               if (num_devs == 0)
+               if (devlist== NULL)
                        mdlist = conf_get_ident(config, NULL);
                        mdlist = conf_get_ident(config, NULL);
-               while (dnum < num_devs || mdlist) {
+               dv = devlist;
+               while (dv || mdlist) {
                        mddev_ident_t mdident;
                        struct state *st;
                        mdu_array_info_t array;
                        mddev_ident_t mdident;
                        struct state *st;
                        mdu_array_info_t array;
@@ -87,9 +89,10 @@ int Monitor(int num_devs, char *devlist[],
                        char *event = NULL;
                        int i;
                        char *event_disc = NULL;
                        char *event = NULL;
                        int i;
                        char *event_disc = NULL;
-                       if (num_devs) {
-                               dev = devlist[dnum++];
+                       if (dv) {
+                               dev = dv->devname;
                                mdident = conf_get_ident(config, dev);
                                mdident = conf_get_ident(config, dev);
+                               dv = dv->next;
                        } else {
                                mdident = mdlist;
                                dev = mdident->devname;
                        } else {
                                mdident = mdlist;
                                dev = mdident->devname;
@@ -171,6 +174,11 @@ int Monitor(int num_devs, char *devlist[],
 
 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd)
 {
 
 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *cmd)
 {
+       if (!cmd && !mailaddr) {
+               time_t now = time(0);
+              
+               printf("%0.15s: %s on %s %s\n", ctime(&now)+4, event, dev, disc?disc:"unknown device");
+       }
        if (cmd) {
                int pid = fork();
                switch(pid) {
        if (cmd) {
                int pid = fork();
                switch(pid) {
index 49830cdc2b40c5451a690fd206af54b3a68e5321..5128cbfcd1933747479be9d91a12977f304b057d 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 
 #include "mdctl.h"
 
 
 #include "mdctl.h"
 
-char Version[] = Name " - v0.5 - 23 August 2001\n";
+char Version[] = Name " - v0.6 -  7 March 2002\n";
 /*
  * File: ReadMe.c
  *
 /*
  * File: ReadMe.c
  *
@@ -78,7 +78,7 @@ char Version[] = Name " - v0.5 - 23 August 2001\n";
  *     command, subsequent Manage commands can finish the job.
  */
 
  *     command, subsequent Manage commands can finish the job.
  */
 
-char short_options[]="-ABCDEFhVvc:l:p:m:n:x:u:c:d:z:sarfRSow";
+char short_options[]="-ABCDEFhVvbc:l:p:m:n:x:u:c:d:z:sarfRSow";
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
     {"assemble",  0, 0, 'A'},
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
     {"assemble",  0, 0, 'A'},
@@ -122,6 +122,9 @@ struct option long_options[] = {
     {"readonly",  0, 0, 'o'},
     {"readwrite", 0, 0, 'w'},
 
     {"readonly",  0, 0, 'o'},
     {"readwrite", 0, 0, 'w'},
 
+    /* For Detail/Examine */
+    {"brief",    0, 0, 'b'},
+
     /* For Follow/monitor */
     {"mail",      1, 0, 'm'},
     {"program",   1, 0, 'p'},
     /* For Follow/monitor */
     {"mail",      1, 0, 'm'},
     {"program",   1, 0, 'p'},
@@ -174,7 +177,7 @@ char Help[] =
 "  --paritiy=    -p   : raid5 parity algorith: {left,right}-{,a}symmetric\n"
 "  --layout=          : same as --parity\n"
 "  --raid-disks= -n   : number of active devices in array\n"
 "  --paritiy=    -p   : raid5 parity algorith: {left,right}-{,a}symmetric\n"
 "  --layout=          : same as --parity\n"
 "  --raid-disks= -n   : number of active devices in array\n"
-"  --spare-disks= -x  : number of spares (eXtras) to allow space for\n"
+"  --spare-disks= -x  : number of spares (eXtras) devices in initial array\n"
 "  --size=       -z   : Size (in K) of each drive in RAID1/4/5 - optional\n"
 "  --force       -f   : Honour devices as listed on command line.  Don't\n"
 "                     : insert a missing drive for RAID5.\n"
 "  --size=       -z   : Size (in K) of each drive in RAID1/4/5 - optional\n"
 "  --force       -f   : Honour devices as listed on command line.  Don't\n"
 "                     : insert a missing drive for RAID5.\n"
@@ -188,6 +191,9 @@ char Help[] =
 "  --scan        -s   : scan config file for missing information\n"
 "  --force       -f   : Assemble the array even if some superblocks appear out-of-date\n"
 "\n"
 "  --scan        -s   : scan config file for missing information\n"
 "  --force       -f   : Assemble the array even if some superblocks appear out-of-date\n"
 "\n"
+" For detail or examine:\n"
+"  --brief       -b   : Just print device name and UUID\n"
+"\n"
 " For follow/monitor:\n"
 "  --mail=       -m   : Address to mail alerts of failure to\n"
 "  --program=    -p   : Program to run when an event is detected\n"
 " For follow/monitor:\n"
 "  --mail=       -m   : Address to mail alerts of failure to\n"
 "  --program=    -p   : Program to run when an event is detected\n"
@@ -306,10 +312,10 @@ char Help_assemble[] =
 /* name/number mappings */
 
 mapping_t r5layout[] = {
 /* name/number mappings */
 
 mapping_t r5layout[] = {
-       { "left_asymmetric", 0},
-       { "right_asymmetric", 1},
-       { "left_symmetric", 2},
-       { "right_symmetric", 3},
+       { "left-asymmetric", 0},
+       { "right-asymmetric", 1},
+       { "left-symmetric", 2},
+       { "right-symmetric", 3},
 
        { "default", 2},
        { "la", 0},
 
        { "default", 2},
        { "la", 0},
diff --git a/TODO b/TODO
index 9bcf70f32aa12adb28356bb65207a6eca6361d8e..a23e0fe8851c59c0c354e242f559fa0fc3174572 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,21 +1,47 @@
 
 
+
+?? Allow -S /dev/md? - current complains subsequent not a/d/r
+
+* write proc.c to parse /proc/mdstat file, and maybe /proc/partitions too.
+   Build list of arrays:  name, rebuild-percent
+
+* --detail --scan to read mdctl.conf, and then iterate over these,
+    but assume --brief.  --verbose can override
+    check each subdevice to see if it is in conf_get_devs.
+    Warn if not.
+
+* Support multipath ... maybe...
+
+* --follow to syslog 
+
+* --follow to move spares around
+
+* --follow to notice other events:
+     rebuild started
+     spare activated
+     spare removed
+     spare added
+
+------------------------------------
+- --examine --scan scans all drives and build an mdctl.conf file DONE
+
 - check superblock checksum in examine DONE
 - report "chunk" or "rounding" depending on raid level DONE
 - report "linear" instead of "-1" for raid level DONE
 - decode ayout depending on raid level DONE
 - check superblock checksum in examine DONE
 - report "chunk" or "rounding" depending on raid level DONE
 - report "linear" instead of "-1" for raid level DONE
 - decode ayout depending on raid level DONE
-- --verbose and --force flags.
+- --verbose and --force flags. DONE
 
 - set md_minor, *_disks for Create  - DONE
 - for create raid5, how to choose between 
    all working, but not insync
 
 - set md_minor, *_disks for Create  - DONE
 - for create raid5, how to choose between 
    all working, but not insync
-   one missing, one spare, insync
-- and for raid1 - some failed drives...
+   one missing, one spare, insync  DONE (--force)
+- and for raid1 - some failed drives...  (missing)
 
 - when RUN_ARRAY, make sure *_disks counts are right
 
 - get --detail to extract extra stuff from superblock,
    like uuid  DONE
 
 - when RUN_ARRAY, make sure *_disks counts are right
 
 - get --detail to extract extra stuff from superblock,
    like uuid  DONE
-- --detail --brief to give a config file line
+- --detail --brief to give a config file line DONE
 - parse config file. DONE
 - test...
 
 - parse config file. DONE
 - test...
 
@@ -23,7 +49,7 @@
   then try to assemble that device first.
 
 
   then try to assemble that device first.
 
 
-- mdctl -S /dev/md0 /dev/md1 gives internal error
+- mdctl -S /dev/md0 /dev/md1 gives internal error FIXED
 
 - mdctl --detail --scan print summary of what it can find?
 
 
 - mdctl --detail --scan print summary of what it can find?
 
@@ -74,4 +100,4 @@ New mode: --Monitor (or --Follow)
      rebuild started
      spare activated
      spare removed
      rebuild started
      spare activated
      spare removed
-     spare added
\ No newline at end of file
+     spare added
index 39ef56ba1db928c40b9fda4818e9d5184d5dc321..4fc381c046c109f5b50e5f3d3f0fa5e2fa322764 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -229,6 +229,8 @@ void arrayline(char *line)
 
        mis.uuid_set = 0;
        mis.super_minor = -1;
 
        mis.uuid_set = 0;
        mis.super_minor = -1;
+       mis.level = -10;
+       mis.raid_disks = -1;
        mis.devices = NULL;
        mis.devname = NULL;
 
        mis.devices = NULL;
        mis.devname = NULL;
 
@@ -273,6 +275,12 @@ void arrayline(char *line)
                                        w);
                        else
                                mis.spare_group = strdup(w+12);
                                        w);
                        else
                                mis.spare_group = strdup(w+12);
+               } else if (strncasecmp(w, "level=", 6) == 0 ) {
+                       /* this is mainly for compatability with --brief output */
+                       mis.level = map_name(pers, w+6);
+               } else if (strncasecmp(w, "disks=", 6) == 0 ) {
+                       /* again, for compat */
+                       mis.raid_disks = atoi(w+6);                        
                } else {
                        fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
                                w);
                } else {
                        fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
                                w);
index 773e7f09d1284b4c282be75920281971a351282a..dae9949b3be87bfd6df1980b7c35bd11c4e54535 100755 (executable)
--- a/makedist
+++ b/makedist
@@ -16,6 +16,6 @@ then
   exit 1
 fi
 trap "rm $target/$base; exit" 1 2 3
   exit 1
 fi
 trap "rm $target/$base; exit" 1 2 3
-( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude=RCS mdctl-$version ; rm mdctl-$version )  > $target/$base
+( cd .. ; ln -s mdctl mdctl-$version ; tar czhvf - --exclude='*,v' --exclude='*.o' --exclude mdctl --exclude=RCS mdctl-$version ; rm mdctl-$version )  > $target/$base
 chmod a+r $target/$base
 ls -l $target/$base
 chmod a+r $target/$base
 ls -l $target/$base
diff --git a/mdctl.8 b/mdctl.8
index fe9c65645e6f39ced60be048d47b760a0a97134c..153d7b5d793692b2ea0aa1b9f4d8a6a7d2fac304 100644 (file)
--- a/mdctl.8
+++ b/mdctl.8
 .\" -*- nroff -*-
 .TH mdctl 8
 .SH NAME
 .\" -*- nroff -*-
 .TH mdctl 8
 .SH NAME
-mdctl \- a single program that can be used to control Linux md devices
+mdctl \- manage MD devices
+.I aka
+Linux Software Raid.
+
 .SH SYNOPSIS
 
 .SH SYNOPSIS
 
-.BI mdctl 
-[mode] <raiddevice> [options]
+.BI mdctl " [mode] <raiddevice> [options] <subdevices>"
 
 .SH DESCRIPTION 
 RAID devices are virtual devices created from two or more
 
 .SH DESCRIPTION 
 RAID devices are virtual devices created from two or more
-real block devices. This allows multiple disks to be combined into a single
-filesystem, possibly with integrated redundancy to survive drive failure.. Linux RAID devices
-are implemented through the md device driver.
-
-If you're using the 
-.B /proc 
-filesystem,
-.B /proc/mdstat
-gives you informations about md devices status.
-
-Currently, Linux supports linear md devices, RAID0 (striping), RAID1
-(mirrroring), RAID4 and RAID5. For information on the various levels of
-RAID, check out:
-
-  http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
-
-for new releases of the RAID driver check out:
-
-  ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
-
-.B mdctl 
-is a single program that can be used to control Linux md devices. It
-is intended to provide all the functionality (and more) of the mdtools
-and raidtools but with a very different interface.
-
-mdctl can perform all functions without a configuration file. There is the
-option of using a configuration file, but not in the same way that raidtools
-uses one. raidtools uses a configuration file to describe how to create a
-RAID array, and also uses this file partially to start a previously created
-RAID array. Further, raidtools requires the configuration file for such
-things as stopping a raid array which needs to know nothing about the array.
-
-The configuration file that can be used by mdctl lists two different things:
-
-.IP "\fB\-\fP"
-a list of md devices and information about how to identify each.  The
-identity can consist of a UUID, and minor-number as recorded on the
-superblock, or a list of devices.
+real block devices. This allows multiple devices (typically disk
+drives or partitions there-of) to be combined into a single device to
+hold (for example) a single filesystem.
+Some RAID levels included redundancy and so can survive some degree of
+device failure.
+
+Linux Software RAID devices are implemented through the md (Multiple Devices) device driver.
+
+Currently, Linux supports
+.B LINEAR
+md devices,
+.B RAID0
+(striping),
+.B RAID1
+(mirroring),
+.B RAID4
+and
+.B RAID5.
+
+Recent kernels (2002) also support a mode known as
+.BR MULTIPATH .
+.B mdctl
+does not support MULTIPATH as yet.
 
 
-.IP "\fB\-\fP"
-a list of devices that should be scanned for md sub-devices.
+.B mdctl
+is a program that can be used to create and manage MD devices.  As
+such it provides a similar set of functionality to the
+.B raidtools
+packages.
+The key differences between
+.B mdctl
+and
+.B raidtools
+are:
+.IP \(bu 4
+.B mdctl
+is a single program and not a collection of programs.
+.IP \(bu 4
+.B mdctl
+can perform (almost) all of its functions without having a
+configuration file.  Also mdctl helps with management of the configuration
+file.
+.IP \(bu 4
+.B mdctl
+can provide information about your arrays (through Detail and Examine)
+that
+.B  raidtools
+cannot.
+.IP \(bu 4
+.B raidtools
+can manage MULTIPATH devices which
+.B mdctl
+cannot yet manage.
 
 .SH MODES
 
 .SH MODES
-mdctl has 4 major modes of operation:
-.IP "\fBCreate\fP"
-This mode is used to create a new array with a superblock. It can progress
-in several step create-add-add-run or it can all happen with one command.
-
-.IP "\fBAssemble\fP"
-This mode is used to assemble the parts of a previously created
+mdctl has 7 major modes of operation:
+.TP
+.B Assemble
+Assemble the parts of a previously created
 array into an active array. Components can be explicitly given
 or can be searched for. 
 .B mdctl
 array into an active array. Components can be explicitly given
 or can be searched for. 
 .B mdctl
-(optionally) checks that the components
-do form a bonafide array, and can, on request, fiddle superblock
-version numbers so as to assemble a faulty array.
-
-.IP "\fBBuild\fP"
-This is for building legacy arrays without superblocks.
-
-.IP "\fBManage\fP"
+checks that the components
+do form a bona fide array, and can, on request, fiddle superblock
+information so as to assemble a faulty array.
+
+.TP
+.B Build
+Build a legacy array without per-device superblocks.
+
+.TP
+.B Create
+Create a new array with per-device superblocks.
+'''It can progress
+'''in several step create-add-add-run or it can all happen with one command.
+
+.TP
+.B Detail
+Display the details of a given md device.  Details include the RAID
+level, the number of devices, which ones are faulty (if any), and the
+array UUID.
+
+.TP
+.B Examine
+Examine a device to see if it is part of an md array, and print out
+the details of that array.
+This mode can also be used to examine a large number of devices and to
+print out a summary of the arrays found in a format suitable for the
+.B mdctl.conf
+configuration file.
+
+.TP
+.B "Follow or Monitor"
+Monitor one or more md devices and act on any state changes.
+
+.TP
+.B Manage
 This is for odd bits an pieces like hotadd, hotremove, setfaulty, stop,
 This is for odd bits an pieces like hotadd, hotremove, setfaulty, stop,
-readonly,readwrite If an array is only partially setup by the
-Create/Assemble/Build command, subsequent Manage commands can finish the
-job.
+readonly, readwrite.
+'''If an array is only partially setup by the
+'''Create or Assemble commands, subsequent Manage commands can finish the
+'''job.
 
 .SH OPTIONS
 
 Available options are:
 
 
 .SH OPTIONS
 
 Available options are:
 
-.IP "\fB\-C\fP, \fB\-\-create\fP"
-Create a new array
+.TP
+.BR -A ", " --assemble
+Assemble an existing array.
 
 
-.IP "\fB-A\fP, \fB\-\-assemble\fP"
-Assemble an existing array
+.TP
+.BR -B ", " --build
+Build a legacy array without superblocks.
 
 
-.IP "\fB\-B\fP, \fB\-\-build\fP"
-Build a legacy array without superblock
+.TP
+.BR -C ", " --create
+Create a new array.
 
 
-.IP "\fB\-D\fP, \fB\-\-detail\fP"
-Print detail of a given md array
+.TP
+.BR -D ", " --detail
+Print detail of one or more md devices.
 
 
-.IP "\fB\-E\fP, \fB\-\-examine\fP"
-Print content of md superblock on device
+.TP
+.BR -E ", " --examine
+Print content of md superblock on device(s).
 
 
-.IP "\fB\-h\fP, \fB\-\-help\fP"
-This help message or, after above option, mode specific help message
+.TP
+.BR -F ", " --follow ", " --monitor
+Select
+.B Monitor
+mode.
 
 
-.IP "\fB\-V\fP, \fB\-\-version\fP"
-Print version information for mdctl
+.TP
+.BR -h ", " --help
+Display help message or, after above option, mode specific help message.
 
 
-.IP "\fB\-v\fP, \fB\-\-verbose\fP"
-Be more verbose about what is happening
+.TP
+.BR -V ", " --version
+Print version information for mdctl.
 
 
-.SH For create or build:
+.TP
+.BR -v ", " --verbose
+Be more verbose about what is happening.
 
 
-.IP "\fB\-c\fP, \fB\-\-chunk=\fP"
-chunk size of kibibytes
+.TP
+.BR -b ", " --brief
+Be less verbose.  This is used with
+.B --detail
+and
+.BR --examine .
 
 
-.IP "\fB\-\-rounding=\fP"
-rounding factor for linear array (==chunk size)
+.SH For create or build:
 
 
-.IP "\fB\-l\fP, \fB\-\-level=\fP"
-raid level: 0,1,4,5,linear. 0 or linear for build
+.TP
+.BR -c ", " --chunk=
+Specify chunk size of kibibytes.  The default is 64.
 
 
-.IP "\fB\-p\fP, \fB\-\-parity=\fP"
-raid5 parity algorithm: {left,right}-{,a}symmetric
+.TP
+.BR --rounding=
+Specify rounding factor for linear array (==chunk size)
 
 
-.IP "\fB\-\-layout=\fP"
-same as --parity
+.TP
+.BR -l ", " --level=
+Set raid level.  Options are: linear, raid0, 0, stripe, raid1, 1, mirror, raid5, 4,
+raid5, 5.  Obviously some of these are synonymous.
+Only the first 4 are valid when Building.
 
 
-.IP "\fB\-n\fP, \fB\-\-raid-disks=\fP"
-number of active devices in array
+.TP
+.BR -p ", " --parity=
+Set raid5 parity algorithm. Options are:
+{left,right}-{,a}symmetric, la, ra, ls, rs.  The default is left-symmetric.
 
 
-.IP "\fB\-x\fP, \fB\-\-spare-disks=\fP"
-number of spares (eXtras) to allow space for
+.TP
+.BR --layout=
+same as --parity
 
 
-.IP "\fB\-z\fP, \fB\-\-size=\fP"
-Size (in K) of each drive in RAID1/4/5 - optional
+.TP
+.BR -n ", " --raid-disks=
+number of active devices in array.
+
+.TP
+.BR -x ", " --spare-disks=
+number of spare (eXtra) disks in initial array.  Spares can be added
+and removed later.
+
+.TP
+.BR -z ", " --size=
+Amount (in Kibibytes) of space to use from each drive in RAID1/4/5.
+This must be a multiple of the chunk size, and must leave about 128Kb
+of space at the end of the drive for the RAID superblock.
+If this is not specified
+(as it normally is not) the smallest drive (or partition) sets the
+size, though if there is a variance among the drives of greater than 1%, a warning is
+issued.
 
 .SH For assemble:
 
 
 .SH For assemble:
 
-.IP "\fB\-u\fP, \fB\-\-uuid=\fP"
-uuid of array to assemble. Devices which don't have this uuid are excluded
-
-.IP "\fB\-c\fP, \fB\-\-config=\fP"
-config file
-
-.IP "\fB\-s\fP, \fB\-\-scan\fP"
+.TP
+.BR -u ", " --uuid=
+uuid of array to assemble. Devices which don't have this uuid are
+excluded
+
+.TP
+.BR -m ", " --super-minor=
+Minor number of device that array was created for.  Devices which
+don't have this minor number are excluded.  If you create an array as
+/dev/md1, then all superblock will contain the minor number 1, even if
+the array is later assembled as /dev/md2.
+
+.TP
+.BR -c ", " --config=
+config file.  Default is
+.BR /etc/mdctl.conf .
+
+.TP
+.BR -s ", " --scan
 scan config file for missing information
 
 scan config file for missing information
 
-.IP "\fB\-f\fP, \fB\-\-force\fP"
+.TP
+.BR -f ", " --force
 Assemble the array even if some superblocks appear out-of-date
 
 Assemble the array even if some superblocks appear out-of-date
 
-.SH General management
-
-.IP "\fB\-a\fP, \fB\-\-add\fP"
-add, or hotadd subsequent devices
-
-.IP "\fB\-r\fP, \fB\-\-remove\fP"
-remove subsequent devices
-
-.IP "\fB\-f\fP, \fB\-\-fail\fP"
-mark subsequent devices a faulty
-
-.IP "\fB\-\-set-faulty\fP"
-same as --fail
-
-.IP "\fB\-R\fP, \fB\-\-run\fP"
-start a partially built array
+.TP
+.BR -R ", " --run
+Attempt to start the array even if fewer drives were given than are
+needed for a full array. Normally if not all drives are found and
+.B --scan
+is not used, then the array will be assembled but not started.
+With
+.B --run
+an attempt will be made to start it anyway.
 
 
-.IP "\fB\-S\fP, \fB\-\-stop\fP"
-deactivate array, releasing all resources
+.SH General management
 
 
-.IP "\fB\-o\fP, \fB\-\-readonly\fP"
-mark array as readonly
+.TP
+.BR -a ", " --add
+'''add, or
+hotadd listed devices.
 
 
-.IP "\fB\-w\fP, \fB\-\-readwrite\fP"
-mark array as readwrite
+.TP
+.BR -r ", " --remove
+remove listed devices.  The must not be active.  i.e. they should
+be failed or spare devices.
 
 
-.SH CREATE MODE
+.TP
+.BR -f ", " --fail
+mark listed devices as faulty.
 
 
-Usage:
+.TP
+.BR --set-faulty
+same as --fail.
 
 
-.B mdctl
---create device --chunk=X --level=Y --raid-disks=Z devices
+.TP
+.BR -R ", " --run
+start a partially built array.
 
 
-This usage will initialise a new md array and possibly associate some
-devices with it. If enough devices are given to complete the array, the
-array will be activated. Otherwise it will be left inactive to be completed
-and activated by subsequent management commands.
+.TP
+.BR -S ", " --stop
+deactivate array, releasing all resources.
 
 
-As devices are added, they are checked to see if they contain raid
-superblocks or filesystems. They are also check to see if the variance in
-device size exceeds 1%.
+.TP
+.BR -o ", " --readonly
+mark array as readonly.
 
 
-If any discrepancy is found, the array will not automatically be run, though
-the presence of a 
-.B --run
-can override this caution.
+.TP
+.BR -w ", " --readwrite
+mark array as readwrite.
 
 
-If the 
-.B --size
-option is given, it is not necessary to list any subdevices in this command.
-They can be added later, before a
-.B --run. 
-If no 
-.B --size
-is given, the apparent size of the smallest drive given is used.
-
-The General management options that are valid with --create are:
-.IP "\fB\-\-run\fP"
-insist of running the array even if not all devices are present or some look
-odd.
-
-.IP "\fB\-\-readonly\fP"
-start the array readonly - not supported yet.
 
 .SH ASSEMBLY MODE
 
 
 .SH ASSEMBLY MODE
 
-Usage: 
-
-.B mdctl
---assemble device options...
-
-.B mdctl
---assemble --scan options...
+.HP 12
+Usage:
+.B mdctl --assemble
+.I device options...
+.HP 12
+Usage:
+.B mdctl --assemble --scan
+.I  options...
 
 
+.PP
 This usage assembles one or more raid arrays from pre-existing components.
 This usage assembles one or more raid arrays from pre-existing components.
-For each array, mdctl needs to know the md device, the uuid, and a number of
-sub devices. These can be found in a number of ways.
+For each array, mdctl needs to know the md device, the identity of the
+array, and a number of sub devices. These can be found in a number of ways.
 
 The md device is either given before 
 .B --scan
 or is found from the config file. In the latter case, multiple md devices
 can be started with a single mdctl command.
 
 
 The md device is either given before 
 .B --scan
 or is found from the config file. In the latter case, multiple md devices
 can be started with a single mdctl command.
 
-The uuid can be given with the 
+The identity can be given with the 
 .B --uuid
 .B --uuid
-option, or can be found in in the config file, or will be taken from the
-super block on the first subdevice listed on the command line or in a
-subsequent
-.B --add
-command.
+option, with the
+.B --super-minor
+option, can be found in in the config file, or will be taken from the
+super block on the first subdevice listed on the command line.
 
 Devices can be given on the 
 .B --assemble
 
 Devices can be given on the 
 .B --assemble
-command line, on subsequent
-.B 'mdctl --add'
-command lines, or from the config file. Only devices which have an md
-superblock which contains the right uuid will be considered for any device.
+command line or from the config file. Only devices which have an md
+superblock which contains the right identity will be considered for any device.
 
 The config file is only used if explicitly named with 
 .B --config
 or requested with 
 .B --scan. 
 In the later case,
 
 The config file is only used if explicitly named with 
 .B --config
 or requested with 
 .B --scan. 
 In the later case,
-.B /etc/md.conf
+.B /etc/mdctl.conf
 is used.
 
 If 
 .B --scan
 is used.
 
 If 
 .B --scan
-is not given, then the config file will only be used to find uuids for md
-arrays.
-
-The format of the config file is:
-   not yet documented
+is not given, then the config file will only be used to find the
+identity of md arrays.
 
 
-.SH BUILD MDOE
+Normally the array will be started after it is assembled.  However is
+.B --scan
+is not given and insufficient drives were lists to start a complete
+(non-degraded) array, then the array is not started (to guard against
+usage errors).  To insist that the array be started in this case (as
+may work for RAID1 or RAID5), give the
+.B --run
+flag.
 
 
-Usage:
 
 
-.B mdctl 
---build device -chunk=X --level=Y --raid-disks=Z devices
+.SH BUILD MODE
 
 
+.HP 12
+Usage:
+.B mdctl --build
+.I device
+.BI --chunk= X
+.BI --level= Y
+.BI --raid-disks= Z
+.I devices
+
+.PP
 This usage is similar to 
 This usage is similar to 
-.B --create. 
+.BR --create .
 The difference is that it creates a legacy array without a superblock. With
 The difference is that it creates a legacy array without a superblock. With
-these arrays there is no different between initially creating the array and
+these arrays there is no difference between initially creating the array and
 subsequently assembling the array, except that hopefully there is useful
 data there in the second case.
 
 subsequently assembling the array, except that hopefully there is useful
 data there in the second case.
 
-The level may only be 0 or linear. All devices must be listed and the array
-will be started once complete.
+The level may only be 0, raid0, or linear. All devices must be listed
+and the array will be started once complete.
+
+.SH CREATE MODE
+
+.HP 12
+Usage:
+.B mdctl --create
+.I device
+.BI --chunk= X
+.BI --level= Y
+.br
+.BI --raid-disks= Z
+.I  devices
+
+.PP
+This usage will initialise a new md array, associate some devices with
+it, and activate the array.
+
+As devices are added, they are checked to see if they contain raid
+superblocks or filesystems. They are also check to see if the variance in
+device size exceeds 1%.
+
+If any discrepancy is found, the array will not automatically be run, though
+the presence of a 
+.B --run
+can override this caution.
+
+'''If the 
+'''.B --size
+'''option is given, it is not necessary to list any subdevices in this command.
+'''They can be added later, before a
+'''.B --run. 
+'''If no 
+'''.B --size
+'''is given, the apparent size of the smallest drive given is used.
+
+The General Management options that are valid with --create are:
+.TP
+.B --run
+insist of running the array even if some devices look like they might
+be in use.
+
+.TP
+.B --readonly
+start the array readonly - not supported yet.
 
 
-.SH BUGS
-no known bugs.
+.SH DETAIL MODE
+.HP 12
+Usage:
+.B mdctl --detail
+.RB [ --brief ]
+.I device ...
+.PP
+
+This usage sill print out the details of the given array including a
+list of component devices.  To determine names for the devices,
+.B mdctl
+searches
+.B /dev
+for device files with the right major and minor numbers.
+
+With
+.B --brief
+.B mdctl
+prints a single line that identifies the level, number of disks, and
+UUID of the array.  This line is suitable for inclusion in
+.BR /etc/mdctl.conf .
+
+.SH EXAMINE MODE
+.HP 12
+Usage:
+.B mdctl --examine
+.RB [ --scan ]
+.RB [ --brief ]
+.I device ...
+.PP
+This usage will examine some block devices to see if that have a valid
+RAID superblock on them.  The information in each valid raid
+superblock will be printed.
+
+If
+.B --scan
+is used, the no devices should be listed, and the complete set of
+devices identified in the configuration file are checked.
+.B --scan
+implies
+.B --brief
+but this implication can be countered by specifying
+.BR --verbose .
+
+With
+.B --brief
+.B mdctl
+will output an config file entry of each distinct array that was
+found.  This entry will list the UUID, the raid level, and a list of
+the individual devices on which a superblock for that array was found.
+This output will by syntactically suitable for inclusion in the
+configuration file, but should
+.B NOT
+be used blindly.  Often the array description that you want in the
+configuration file is much less specific than that given by
+.BR "mdctl -Bs" .
+For example, you normally do not want to list the devices,
+particularly if they are SCSI devices.
+
+'''.SH BUGS
+'''no known bugs.
+
+.SH FILES
+
+.SS /proc/mdstat
+
+If you're using the 
+.B /proc 
+filesystem,
+.B /proc/mdstat
+gives you informations about md devices status.
+This file is not currently used by
+.BR mdctl .
+
+.SS /etc/mdctl.conf
+
+The config file is line oriented with, as usual, blank lines and lines
+beginning with a hash (or pound sign or sharp or number sign,
+whichever you like to call it) ignored.
+Lines that start with a blank are treated as continuations of the
+previous line (I don't like trailing slashes).
+
+Each line contains a sequence of space-separated words, the first of
+which identified the type of line. Keywords are case-insensitive, and
+the first work on a line can be abbreviated to 3 letters.
+
+There are two types of lines. ARRAY and DEVICE.
+
+The DEVICE lines usually come first. All remaining words on the line
+are treated as names of devices, possibly containing wild cards (see
+.IR glob (7)).
+These list all the devices that
+.B mdctl
+is allowed to scan
+when looking for devices with RAID superblocks.
+Each line can contain multiple device names, and there can be multiple
+DEVICE lines.  For example:
+.IP
+DEVICE /dev/hda* /dev/hdc*
+.br
+DEV    /dev/sd*
+.br
+DEVICE /dev/discs/disc*/disc
+.PP
+The ARRAY lines identify actual arrays.  The second word on the line
+should be the name of the device where the array is normally
+assembled, such as /dev/md1.
+Subsequent words identify the array. If multiple identities are given,
+then the array much match ALL identities to be considered a match.
+Each identity word has a tag, and equals sign, and some value.
+The options are:
+
+.TP
+.B uuid=
+The value should be a 128 bit uuid in hexadecimal, with punctuation
+interspersed if desired.  This must match the uuid stored in the
+superblock.
+.TP
+.B super-minor=
+The value is an integer which indicates the minor number that was
+stored in the superblock when the array was created. When an array is
+created as /dev/mdX, then the minor number X is stored.
+.TP
+.B devices=
+The value is a comma separated list of device names. Precisely these
+devices will be used to assemble the array.  Note that the devices
+listed there must also be listed on a DEVICE line.
+.TP
+.B level=
+The value is a raid level.  This is normally used to identify an
+array, but is supported so that the output of
+.B "mdctl --examine --scan"
+can be use directly in the configuration file.
+.TP
+.B disks=
+The value is the number of disks in a complete active array.  As with
+.B level=
+this is mainly for compatibility with the output of
+.BR "mdctl --examine --scan" .
 
 .SH TODO
 
 
 .SH TODO
 
+Finish and document Follow mode.
 
 .SH SEE ALSO
 
 .SH SEE ALSO
+For information on the various levels of
+RAID, check out:
+
+.IP
+.UR   http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
+http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
+.UE
+.PP
+for new releases of the RAID driver check out:
+
+.IP
+.UR  ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
+ftp://ftp.kernel.org/pub/linux/kernel/people/mingo/raid-patches
+.UE
+.PP
+or
+.IP
+.UR http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/
+http://www.cse.unsw.edu.au/~neilb/patches/linux-stable/
+.URk
+.PP
 .IR raidtab (5),
 .IR raid0run (8),
 .IR raidstop (8),
 .IR raidtab (5),
 .IR raid0run (8),
 .IR raidstop (8),
diff --git a/mdctl.c b/mdctl.c
index 63871104c4f31c3ba12e8578d77b933362d51f32..054fbc4d253ef9c86d9af9ab947816181f0a41df 100644 (file)
--- a/mdctl.c
+++ b/mdctl.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -64,14 +64,17 @@ int main(int argc, char *argv[])
        int sparedisks = 0;
        struct mddev_ident_s ident;
        char *configfile = NULL;
        int sparedisks = 0;
        struct mddev_ident_s ident;
        char *configfile = NULL;
+       char *cp;
        int scan = 0;
        char devmode = 0;
        int runstop = 0;
        int readonly = 0;
        int scan = 0;
        char devmode = 0;
        int runstop = 0;
        int readonly = 0;
-       char *devs[MD_SB_DISKS+1];
-       int devmodes[MD_SB_DISKS+1];
+       mddev_dev_t devlist = NULL;
+       mddev_dev_t *devlistend = & devlist;
+       mddev_dev_t dv;
        int devs_found = 0;
        int verbose = 0;
        int devs_found = 0;
        int verbose = 0;
+       int brief = 0;
        int force = 0;
 
        char *mailaddr = NULL;
        int force = 0;
 
        char *mailaddr = NULL;
@@ -81,6 +84,8 @@ int main(int argc, char *argv[])
        int mdfd = -1;
 
        ident.uuid_set=0;
        int mdfd = -1;
 
        ident.uuid_set=0;
+       ident.level = -10;
+       ident.raid_disks = -1;
        ident.super_minor= -1;
        ident.devices=0;
 
        ident.super_minor= -1;
        ident.devices=0;
 
@@ -124,19 +129,36 @@ int main(int argc, char *argv[])
                case 'v': verbose = 1;
                        continue;
 
                case 'v': verbose = 1;
                        continue;
 
+               case 'b': brief = 1;
+                       continue;
+
                case 1: /* an undecorated option - must be a device name.
                         * Depending on mode, it could be that:
                case 1: /* an undecorated option - must be a device name.
                         * Depending on mode, it could be that:
-                        * All devices listed are "md" devices : --Detail, -As
-                        * No devices are "md" devices : --Examine
-                        * First device is "md", others are component: -A,-B,-C
+                        *    All devices listed are "md" devices : --Detail, -As
+                        *    No devices are "md" devices : --Examine
+                        *    First device is "md", others are component: -A,-B,-C
+                        * Only accept on device before mode is determined.
+                        *  If mode is @, then require devmode for other devices.
                         */
                         */
-                       if (devs_found >= MD_SB_DISKS+1) {
-                               fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n",
-                                       optarg, MD_SB_DISKS+1);
+                       if (devs_found > 0 && !mode ) {
+                               fprintf(stderr, Name ": Must give mode flag before second device name at %s\n", optarg);
+                               exit(2);
+                       }
+                       if (devs_found > 0 && mode == '@' && !devmode) {
+                               fprintf(stderr, Name ": Must give on of -a/-r/-f for subsequent devices at %s\n", optarg);
                                exit(2);
                        }
                                exit(2);
                        }
-                       devs[devs_found] = optarg;
-                       devmodes[devs_found] = devmode;
+                       dv = malloc(sizeof(*dv));
+                       if (dv == NULL) {
+                               fprintf(stderr, Name ": malloc failed\n");
+                               exit(3);
+                       }
+                       dv->devname = optarg;
+                       dv->disposition = devmode;
+                       dv->next = NULL;
+                       *devlistend = dv;
+                       devlistend = &dv->next;
+                       
                        devs_found++;
                        continue;
 
                        devs_found++;
                        continue;
 
@@ -205,6 +227,7 @@ int main(int argc, char *argv[])
                                        optarg);
                                exit(2);
                        }
                                        optarg);
                                exit(2);
                        }
+                       ident.level = level;
                        continue;
 
                case O('C','p'): /* raid5 layout */
                        continue;
 
                case O('C','p'): /* raid5 layout */
@@ -246,6 +269,7 @@ int main(int argc, char *argv[])
                                        optarg);
                                exit(2);
                        }
                                        optarg);
                                exit(2);
                        }
+                       ident.raid_disks = raiddisks;
                        continue;
 
                case O('C','x'): /* number of spare (eXtra) discs */
                        continue;
 
                case O('C','x'): /* number of spare (eXtra) discs */
@@ -276,7 +300,7 @@ int main(int argc, char *argv[])
                        continue;
                case O('A','u'): /* uuid of array */
                        if (ident.uuid_set) {
                        continue;
                case O('A','u'): /* uuid of array */
                        if (ident.uuid_set) {
-                               fprintf(stderr, Name ": uuid cannot bet set twice.  "
+                               fprintf(stderr, Name ": uuid cannot be set twice.  "
                                        "Second value %s.\n", optarg);
                                exit(2);
                        }
                                        "Second value %s.\n", optarg);
                                exit(2);
                        }
@@ -288,6 +312,19 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
                        }
                        continue;
 
+               case O('A','m'): /* super-minor for array */
+                       if (ident.super_minor >= 0) {
+                               fprintf(stderr, Name ": super-minor cannot be set twice.  "
+                                       "Second value: %s.\n", optarg);
+                               exit(2);
+                       }
+                       ident.super_minor = strtoul(optarg, &cp, 10);
+                       if (!optarg[0] || *cp) {
+                               fprintf(stderr, Name ": Bad super-minor number: %s.\n", optarg);
+                               exit(2);
+                       }
+                       continue;
+
                case O('A','c'): /* config file */
                case O('F','c'):
                        if (configfile) {
                case O('A','c'): /* config file */
                case O('F','c'):
                        if (configfile) {
@@ -299,6 +336,7 @@ int main(int argc, char *argv[])
                        /* FIXME possibly check that config file exists.  Even parse it */
                        continue;
                case O('A','s'): /* scan */
                        /* FIXME possibly check that config file exists.  Even parse it */
                        continue;
                case O('A','s'): /* scan */
+               case O('E','s'):
                        scan = 1;
                        continue;
 
                        scan = 1;
                        continue;
 
@@ -409,7 +447,7 @@ int main(int argc, char *argv[])
                        fprintf(stderr, Name ": an md device must be given in this mode\n");
                        exit(2);
                }
                        fprintf(stderr, Name ": an md device must be given in this mode\n");
                        exit(2);
                }
-               mdfd = open_mddev(devs[0]);
+               mdfd = open_mddev(devlist->devname);
                if (mdfd < 0)
                        exit(1);
        }
                if (mdfd < 0)
                        exit(1);
        }
@@ -420,36 +458,36 @@ int main(int argc, char *argv[])
        case '@':/* Management */
                /* readonly, add/remove, readwrite, runstop */
                if (readonly>0)
        case '@':/* Management */
                /* readonly, add/remove, readwrite, runstop */
                if (readonly>0)
-                       rv = Manage_ro(devs[0], mdfd, readonly);
+                       rv = Manage_ro(devlist->devname, mdfd, readonly);
                if (!rv && devs_found>1)
                if (!rv && devs_found>1)
-                       rv = Manage_subdevs(devs[0], mdfd,
-                                           devs_found-1, devs+1, devmodes+1);
+                       rv = Manage_subdevs(devlist->devname, mdfd,
+                                           devlist->next);
                if (!rv && readonly < 0)
                if (!rv && readonly < 0)
-                       rv = Manage_ro(devs[0], mdfd, readonly);
+                       rv = Manage_ro(devlist->devname, mdfd, readonly);
                if (!rv && runstop)
                if (!rv && runstop)
-                       rv = Manage_runstop(devs[0], mdfd, runstop);
+                       rv = Manage_runstop(devlist->devname, mdfd, runstop);
                break;
        case 'A': /* Assemble */
                if (!scan)
                break;
        case 'A': /* Assemble */
                if (!scan)
-                       rv = Assemble(devs[0], mdfd, &ident, configfile,
-                                     devs_found-1, devs+1,
+                       rv = Assemble(devlist->devname, mdfd, &ident, configfile,
+                                     devlist->next,
                                      readonly, runstop, verbose, force);
                else if (devs_found>0)
                                      readonly, runstop, verbose, force);
                else if (devs_found>0)
-                       for (i=0; i<devs_found; i++) {
-                               mddev_ident_t array_ident = conf_get_ident(configfile, devs[i]);
-                               mdfd = open_mddev(devs[i]);
+                       for (dv = devlist ; dv ; dv=dv->next) {
+                               mddev_ident_t array_ident = conf_get_ident(configfile, dv->devname);
+                               mdfd = open_mddev(dv->devname);
                                if (mdfd < 0) {
                                        rv |= 1;
                                        continue;
                                }
                                if (array_ident == NULL) {
                                        fprintf(stderr, Name ": %s not identified in config file.\n",
                                if (mdfd < 0) {
                                        rv |= 1;
                                        continue;
                                }
                                if (array_ident == NULL) {
                                        fprintf(stderr, Name ": %s not identified in config file.\n",
-                                               devs[i]);
+                                               dv->devname);
                                        rv |= 1;
                                        continue;
                                }
                                        rv |= 1;
                                        continue;
                                }
-                               rv |= Assemble(devs[i], mdfd, array_ident, configfile,
-                                              0, NULL,
+                               rv |= Assemble(dv->devname, mdfd, array_ident, configfile,
+                                              NULL,
                                               readonly, runstop, verbose, force);
                        }
                else {
                                               readonly, runstop, verbose, force);
                        }
                else {
@@ -459,36 +497,43 @@ int main(int argc, char *argv[])
                                rv = 1;
                        } else
                                for (; array_list; array_list = array_list->next) {
                                rv = 1;
                        } else
                                for (; array_list; array_list = array_list->next) {
+                                       mdu_array_info_t array;
                                        mdfd = open_mddev(array_list->devname);
                                        if (mdfd < 0) {
                                                rv |= 1;
                                                continue;
                                        }
                                        mdfd = open_mddev(array_list->devname);
                                        if (mdfd < 0) {
                                                rv |= 1;
                                                continue;
                                        }
+                                       if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0)
+                                               /* already assembled, skip */
+                                               continue;
                                        rv |= Assemble(array_list->devname, mdfd,
                                                       array_list, configfile,
                                        rv |= Assemble(array_list->devname, mdfd,
                                                       array_list, configfile,
-                                                      0, NULL,
+                                                      NULL,
                                                       readonly, runstop, verbose, force);
                                }
                }
                break;
        case 'B': /* Build */
                                                       readonly, runstop, verbose, force);
                                }
                }
                break;
        case 'B': /* Build */
-               rv = Build(devs[0], mdfd, chunk, level, raiddisks, devs_found-1,devs+1);
+               rv = Build(devlist->devname, mdfd, chunk, level, raiddisks, devlist->next);
                break;
        case 'C': /* Create */
                break;
        case 'C': /* Create */
-               rv = Create(devs[0], mdfd, chunk, level, layout, size,
+               rv = Create(devlist->devname, mdfd, chunk, level, layout, size,
                            raiddisks, sparedisks,
                            raiddisks, sparedisks,
-                           devs_found-1,devs+1, runstop, verbose, force);
+                           devs_found-1, devlist->next, runstop, verbose, force);
                break;
        case 'D': /* Detail */
                break;
        case 'D': /* Detail */
-               for (i=0; i<devs_found; i++)
-                       rv |= Detail(devs[i]);
+               for (dv=devlist ; dv; dv=dv->next)
+                       rv |= Detail(dv->devname, brief);
                break;
        case 'E': /* Examine */
                break;
        case 'E': /* Examine */
-               for (i=0; i<devs_found; i++)
-                       rv |= Examine(devs[i]);
+               if (devlist == NULL && scan==0) {
+                       fprintf(stderr, Name ": No devices to examine\n");
+                       exit(2);
+               }
+               rv = Examine(devlist, devlist?brief:!verbose, configfile);
                break;
        case 'F': /* Follow */
                break;
        case 'F': /* Follow */
-               rv= Monitor(devs_found, devs, mailaddr, program,
+               rv= Monitor(devlist, mailaddr, program,
                            delay?delay:60, configfile);
        }
        exit(rv);
                            delay?delay:60, configfile);
        }
        exit(rv);
diff --git a/mdctl.h b/mdctl.h
index 43087161fbd6cfbe8497a08952a8d0b460bacf3b..5aa61ce1cd80a72bfe205e1b14f3dacabbafb203 100644 (file)
--- a/mdctl.h
+++ b/mdctl.h
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -76,7 +76,8 @@ typedef struct mddev_ident_s {
        char *devices;          /* comma separated list of device
                                 * names with wild cards
                                 */
        char *devices;          /* comma separated list of device
                                 * names with wild cards
                                 */
-
+       int level;              /* -10 if not set */
+       int raid_disks;         /* -1 if not set */
        char *spare_group;
        struct mddev_ident_s *next;
 } *mddev_ident_t;
        char *spare_group;
        struct mddev_ident_s *next;
 } *mddev_ident_t;
@@ -84,6 +85,9 @@ typedef struct mddev_ident_s {
 /* List of device names - wildcards expanded */
 typedef struct mddev_dev_s {
        char *devname;
 /* List of device names - wildcards expanded */
 typedef struct mddev_dev_s {
        char *devname;
+       char disposition;       /* 'a' for add, 'r' for remove, 'f' for fail.
+                                * Not set for names read from .config
+                                */
        struct mddev_dev_s *next;
 } *mddev_dev_t;
 
        struct mddev_dev_s *next;
 } *mddev_dev_t;
 
@@ -106,29 +110,29 @@ extern char *map_dev(int major, int minor);
 extern int Manage_ro(char *devname, int fd, int readonly);
 extern int Manage_runstop(char *devname, int fd, int runstop);
 extern int Manage_subdevs(char *devname, int fd,
 extern int Manage_ro(char *devname, int fd, int readonly);
 extern int Manage_runstop(char *devname, int fd, int runstop);
 extern int Manage_subdevs(char *devname, int fd,
-                         int devcnt, char *devnames[], int devmodes[]);
+                         mddev_dev_t devlist);
 
 
 extern int Assemble(char *mddev, int mdfd,
                    mddev_ident_t ident,
                    char *conffile,
 
 
 extern int Assemble(char *mddev, int mdfd,
                    mddev_ident_t ident,
                    char *conffile,
-                   int subdevs, char *subdev[],
+                   mddev_dev_t devlist,
                    int readonly, int runstop,
                    int verbose, int force);
 
 extern int Build(char *mddev, int mdfd, int chunk, int level,
                 int raiddisks,
                    int readonly, int runstop,
                    int verbose, int force);
 
 extern int Build(char *mddev, int mdfd, int chunk, int level,
                 int raiddisks,
-                int subdevs, char *subdev[]);
+                mddev_dev_t devlist);
 
 
 extern int Create(char *mddev, int mdfd,
                  int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
 
 
 extern int Create(char *mddev, int mdfd,
                  int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
-                 int subdevs, char *subdev[],
+                 int subdevs, mddev_dev_t devlist,
                  int runstop, int verbose, int force);
 
                  int runstop, int verbose, int force);
 
-extern int Detail(char *dev);
-extern int Examine(char *dev);
-extern int Monitor(int num_devs, char *devlist[],
+extern int Detail(char *dev, int brief);
+extern int Examine(mddev_dev_t devlist, int brief, char *conffile);
+extern int Monitor(mddev_dev_t devlist,
                  char *mailaddr, char *alert_cmd,
                  int period,
                  char *config);
                  char *mailaddr, char *alert_cmd,
                  int period,
                  char *config);
@@ -142,3 +146,5 @@ extern int check_raid(int fd, char *name);
 
 extern mddev_ident_t conf_get_ident(char *, char*);
 extern mddev_dev_t conf_get_devs(char *);
 
 extern mddev_ident_t conf_get_ident(char *, char*);
 extern mddev_dev_t conf_get_devs(char *);
+
+extern char *human_size(long kbytes);
diff --git a/mdctl.man b/mdctl.man
new file mode 100644 (file)
index 0000000..682bc82
--- /dev/null
+++ b/mdctl.man
@@ -0,0 +1,476 @@
+mdctl(8)                                                 mdctl(8)
+
+
+
+N\bNA\bAM\bME\bE
+       mdctl - manage MD devices _\ba_\bk_\ba Linux Software Raid.
+
+
+S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
+       m\bmd\bdc\bct\btl\bl _\b[_\bm_\bo_\bd_\be_\b] _\b<_\br_\ba_\bi_\bd_\bd_\be_\bv_\bi_\bc_\be_\b> _\b[_\bo_\bp_\bt_\bi_\bo_\bn_\bs_\b] _\b<_\bs_\bu_\bb_\bd_\be_\bv_\bi_\bc_\be_\bs_\b>
+
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       RAID  devices are virtual devices created from two or more
+       real block devices. This allows  multiple  devices  (typi-
+       cally  disk  drives or partitions there-of) to be combined
+       into a single  device  to  hold  (for  example)  a  single
+       filesystem.   Some  RAID levels included redundancy and so
+       can survive some degree of device failure.
+
+       Linux Software RAID devices are implemented through the md
+       (Multiple Devices) device driver.
+
+       Currently, Linux supports L\bLI\bIN\bNE\bEA\bAR\bR md devices, R\bRA\bAI\bID\bD0\b0 (strip-
+       ing), R\bRA\bAI\bID\bD1\b1 (mirroring), R\bRA\bAI\bID\bD4\b4 and R\bRA\bAI\bID\bD5\b5.\b.
+
+       Recent kernels (2002) also support a mode known as  M\bMU\bUL\bLT\bTI\bI-\b-
+       P\bPA\bAT\bTH\bH.  m\bmd\bdc\bct\btl\bl does not support MULTIPATH as yet.
+
+       m\bmd\bdc\bct\btl\bl  is  a program that can be used to create and manage
+       MD devices.  As such it provides a similar  set  of  func-
+       tionality  to the r\bra\bai\bid\bdt\bto\boo\bol\bls\bs packages.  The key differences
+       between m\bmd\bdc\bct\btl\bl and r\bra\bai\bid\bdt\bto\boo\bol\bls\bs are:
+
+       +\bo   m\bmd\bdc\bct\btl\bl is a single program and not a collection of pro-
+           grams.
+
+       +\bo   m\bmd\bdc\bct\btl\bl  can perform (almost) all of its functions with-
+           out having a configuration  file.   Also  mdctl  helps
+           with management of the configuration file.
+
+       +\bo   m\bmd\bdc\bct\btl\bl   can  provide  information  about  your  arrays
+           (through Detail and Examine) that r\bra\bai\bid\bdt\bto\boo\bol\bls\bs cannot.
+
+       +\bo   r\bra\bai\bid\bdt\bto\boo\bol\bls\bs can manage  MULTIPATH  devices  which  m\bmd\bdc\bct\btl\bl
+           cannot yet manage.
+
+
+M\bMO\bOD\bDE\bES\bS
+       mdctl has 7 major modes of operation:
+
+       A\bAs\bss\bse\bem\bmb\bbl\ble\be
+              Assemble  the  parts  of a previously created array
+              into an active array. Components can be  explicitly
+              given  or  can  be searched for.  m\bmd\bdc\bct\btl\bl checks that
+              the components do form a bona fide array, and  can,
+              on  request, fiddle superblock information so as to
+              assemble a faulty array.
+
+
+       B\bBu\bui\bil\bld\bd  Build   a   legacy   array    without    per-device
+              superblocks.
+
+
+       C\bCr\bre\bea\bat\bte\be Create a new array with per-device superblocks.
+
+
+       D\bDe\bet\bta\bai\bil\bl Display  the details of a given md device.  Details
+              include the RAID  level,  the  number  of  devices,
+              which ones are faulty (if any), and the array UUID.
+
+
+       E\bEx\bxa\bam\bmi\bin\bne\be
+              Examine a device to see if it  is  part  of  an  md
+              array,  and  print  out  the details of that array.
+              This mode can also be used to examine a large  num-
+              ber  of  devices  and to print out a summary of the
+              arrays  found  in  a  format   suitable   for   the
+              m\bmd\bdc\bct\btl\bl.\b.c\bco\bon\bnf\bf configuration file.
+
+
+       F\bFo\bol\bll\blo\bow\bw o\bor\br M\bMo\bon\bni\bit\bto\bor\br
+              Monitor one or more md devices and act on any state
+              changes.
+
+
+       M\bMa\ban\bna\bag\bge\be This  is  for  odd  bits  an  pieces  like  hotadd,
+              hotremove, setfaulty, stop, readonly, readwrite.
+
+
+O\bOP\bPT\bTI\bIO\bON\bNS\bS
+       Available options are:
+
+
+       -\b-A\bA, -\b--\b-a\bas\bss\bse\bem\bmb\bbl\ble\be
+              Assemble an existing array.
+
+
+       -\b-B\bB, -\b--\b-b\bbu\bui\bil\bld\bd
+              Build a legacy array without superblocks.
+
+
+       -\b-C\bC, -\b--\b-c\bcr\bre\bea\bat\bte\be
+              Create a new array.
+
+
+       -\b-D\bD, -\b--\b-d\bde\bet\bta\bai\bil\bl
+              Print detail of one or more md devices.
+
+
+       -\b-E\bE, -\b--\b-e\bex\bxa\bam\bmi\bin\bne\be
+              Print content of md superblock on device(s).
+
+
+       -\b-F\bF, -\b--\b-f\bfo\bol\bll\blo\bow\bw, -\b--\b-m\bmo\bon\bni\bit\bto\bor\br
+              Select M\bMo\bon\bni\bit\bto\bor\br mode.
+
+
+       -\b-h\bh, -\b--\b-h\bhe\bel\blp\bp
+              Display  help  message or, after above option, mode
+              specific help message.
+
+
+       -\b-V\bV, -\b--\b-v\bve\ber\brs\bsi\bio\bon\bn
+              Print version information for mdctl.
+
+
+       -\b-v\bv, -\b--\b-v\bve\ber\brb\bbo\bos\bse\be
+              Be more verbose about what is happening.
+
+
+       -\b-b\bb, -\b--\b-b\bbr\bri\bie\bef\bf
+              Be less verbose.  This is used  with  -\b--\b-d\bde\bet\bta\bai\bil\bl  and
+              -\b--\b-e\bex\bxa\bam\bmi\bin\bne\be.
+
+
+F\bFo\bor\br c\bcr\bre\bea\bat\bte\be o\bor\br b\bbu\bui\bil\bld\bd:\b:
+       -\b-c\bc, -\b--\b-c\bch\bhu\bun\bnk\bk=\b=
+              Specify  chunk  size  of kibibytes.  The default is
+              64.
+
+
+       -\b--\b-r\bro\bou\bun\bnd\bdi\bin\bng\bg=\b=
+              Specify rounding factor for linear  array  (==chunk
+              size)
+
+
+       -\b-l\bl, -\b--\b-l\ble\bev\bve\bel\bl=\b=
+              Set  raid  level.   Options  are: linear, raid0, 0,
+              stripe, raid1,  1,  mirror,  raid5,  4,  raid5,  5.
+              Obviously  some  of these are synonymous.  Only the
+              first 4 are valid when Building.
+
+
+       -\b-p\bp, -\b--\b-p\bpa\bar\bri\bit\bty\by=\b=
+              Set   raid5   parity   algorithm.   Options    are:
+              {left,right}-{,a}symmetric,  la,  ra,  ls, rs.  The
+              default is left-symmetric.
+
+
+       -\b--\b-l\bla\bay\byo\bou\but\bt=\b=
+              same as --parity
+
+
+       -\b-n\bn, -\b--\b-r\bra\bai\bid\bd-\b-d\bdi\bis\bsk\bks\bs=\b=
+              number of active devices in array.
+
+
+       -\b-x\bx, -\b--\b-s\bsp\bpa\bar\bre\be-\b-d\bdi\bis\bsk\bks\bs=\b=
+              number of spare (eXtra)  disks  in  initial  array.
+              Spares can be added and removed later.
+
+
+       -\b-z\bz, -\b--\b-s\bsi\biz\bze\be=\b=
+              Amount  (in  Kibibytes)  of  space to use from each
+              drive in RAID1/4/5.  This must be a multiple of the
+              chunk  size, and must leave about 128Kb of space at
+              the end of the drive for the RAID  superblock.   If
+              this  is  not specified (as it normally is not) the
+              smallest drive (or partition) sets the size, though
+              if  there is a variance among the drives of greater
+              than 1%, a warning is issued.
+
+
+F\bFo\bor\br a\bas\bss\bse\bem\bmb\bbl\ble\be:\b:
+       -\b-u\bu, -\b--\b-u\buu\bui\bid\bd=\b=
+              uuid of array to assemble. Devices which don't have
+              this uuid are excluded
+
+
+       -\b-m\bm, -\b--\b-s\bsu\bup\bpe\ber\br-\b-m\bmi\bin\bno\bor\br=\b=
+              Minor  number of device that array was created for.
+              Devices which don't  have  this  minor  number  are
+              excluded.  If you create an array as /dev/md1, then
+              all superblock will contain  the  minor  number  1,
+              even if the array is later assembled as /dev/md2.
+
+
+       -\b-c\bc, -\b--\b-c\bco\bon\bnf\bfi\big\bg=\b=
+              config file.  Default is /\b/e\bet\btc\bc/\b/m\bmd\bdc\bct\btl\bl.\b.c\bco\bon\bnf\bf.
+
+
+       -\b-s\bs, -\b--\b-s\bsc\bca\ban\bn
+              scan config file for missing information
+
+
+       -\b-f\bf, -\b--\b-f\bfo\bor\brc\bce\be
+              Assemble  the array even if some superblocks appear
+              out-of-date
+
+
+       -\b-R\bR, -\b--\b-r\bru\bun\bn
+              Attempt to start the array  even  if  fewer  drives
+              were  given  than are needed for a full array. Nor-
+              mally if not all drives are found and -\b--\b-s\bsc\bca\ban\bn is not
+              used,  then  the  array  will  be assembled but not
+              started.  With -\b--\b-r\bru\bun\bn an attempt  will  be  made  to
+              start it anyway.
+
+
+G\bGe\ben\bne\ber\bra\bal\bl m\bma\ban\bna\bag\bge\bem\bme\ben\bnt\bt
+       -\b-a\ba, -\b--\b-a\bad\bdd\bd
+              hotadd listed devices.
+
+
+       -\b-r\br, -\b--\b-r\bre\bem\bmo\bov\bve\be
+              remove  listed  devices.   The  must not be active.
+              i.e. they should be failed or spare devices.
+
+
+       -\b-f\bf, -\b--\b-f\bfa\bai\bil\bl
+              mark listed devices as faulty.
+
+
+       -\b--\b-s\bse\bet\bt-\b-f\bfa\bau\bul\blt\bty\by
+              same as --fail.
+
+
+       -\b-R\bR, -\b--\b-r\bru\bun\bn
+              start a partially built array.
+
+
+       -\b-S\bS, -\b--\b-s\bst\bto\bop\bp
+              deactivate array, releasing all resources.
+
+
+       -\b-o\bo, -\b--\b-r\bre\bea\bad\bdo\bon\bnl\bly\by
+              mark array as readonly.
+
+
+       -\b-w\bw, -\b--\b-r\bre\bea\bad\bdw\bwr\bri\bit\bte\be
+              mark array as readwrite.
+
+
+
+A\bAS\bSS\bSE\bEM\bMB\bBL\bLY\bY M\bMO\bOD\bDE\bE
+       Usage: m\bmd\bdc\bct\btl\bl -\b--\b-a\bas\bss\bse\bem\bmb\bbl\ble\be _\bd_\be_\bv_\bi_\bc_\be _\bo_\bp_\bt_\bi_\bo_\bn_\bs_\b._\b._\b.
+
+       Usage: m\bmd\bdc\bct\btl\bl -\b--\b-a\bas\bss\bse\bem\bmb\bbl\ble\be -\b--\b-s\bsc\bca\ban\bn _\bo_\bp_\bt_\bi_\bo_\bn_\bs_\b._\b._\b.
+
+
+       This usage assembles one or more  raid  arrays  from  pre-
+       existing  components.  For each array, mdctl needs to know
+       the md device, the identity of the array, and a number  of
+       sub devices. These can be found in a number of ways.
+
+       The  md  device  is either given before -\b--\b-s\bsc\bca\ban\bn or is found
+       from the config file. In  the  latter  case,  multiple  md
+       devices can be started with a single mdctl command.
+
+       The identity can be given with the -\b--\b-u\buu\bui\bid\bd option, with the
+       -\b--\b-s\bsu\bup\bpe\ber\br-\b-m\bmi\bin\bno\bor\br option, can be found in in the config  file,
+       or  will be taken from the super block on the first subde-
+       vice listed on the command line.
+
+       Devices can be given on the  -\b--\b-a\bas\bss\bse\bem\bmb\bbl\ble\be  command  line  or
+       from  the  config  file.  Only  devices  which  have an md
+       superblock which contains the right identity will be  con-
+       sidered for any device.
+
+       The  config  file  is  only  used if explicitly named with
+       -\b--\b-c\bco\bon\bnf\bfi\big\bg or requested with -\b--\b-s\bsc\bca\ban\bn.\b.   In  the  later  case,
+       /\b/e\bet\btc\bc/\b/m\bmd\bdc\bct\btl\bl.\b.c\bco\bon\bnf\bf is used.
+
+       If  -\b--\b-s\bsc\bca\ban\bn is not given, then the config file will only be
+       used to find the identity of md arrays.
+
+       Normally the array will be started after it is  assembled.
+       However  is  -\b--\b-s\bsc\bca\ban\bn  is  not given and insufficient drives
+       were lists to start a complete (non-degraded) array,  then
+       the  array is not started (to guard against usage errors).
+       To insist that the array be started in this case  (as  may
+       work for RAID1 or RAID5), give the -\b--\b-r\bru\bun\bn flag.
+
+
+
+B\bBU\bUI\bIL\bLD\bD M\bMO\bOD\bDE\bE
+       Usage:  m\bmd\bdc\bct\btl\bl  -\b--\b-b\bbu\bui\bil\bld\bd  _\bd_\be_\bv_\bi_\bc_\be -\b--\b-c\bch\bhu\bun\bnk\bk=\b=_\bX -\b--\b-l\ble\bev\bve\bel\bl=\b=_\bY -\b--\b-r\bra\bai\bid\bd-\b-
+                   d\bdi\bis\bsk\bks\bs=\b=_\bZ _\bd_\be_\bv_\bi_\bc_\be_\bs
+
+
+       This usage is similar to -\b--\b-c\bcr\bre\bea\bat\bte\be.  The difference is that
+       it creates a legacy array without a superblock. With these
+       arrays there is no difference between  initially  creating
+       the  array  and  subsequently assembling the array, except
+       that hopefully there is useful data there  in  the  second
+       case.
+
+       The  level  may  only  be 0, raid0, or linear. All devices
+       must be listed and the array will  be  started  once  com-
+       plete.
+
+
+C\bCR\bRE\bEA\bAT\bTE\bE M\bMO\bOD\bDE\bE
+       Usage: m\bmd\bdc\bct\btl\bl -\b--\b-c\bcr\bre\bea\bat\bte\be _\bd_\be_\bv_\bi_\bc_\be -\b--\b-c\bch\bhu\bun\bnk\bk=\b=_\bX -\b--\b-l\ble\bev\bve\bel\bl=\b=_\bY
+                   -\b--\b-r\bra\bai\bid\bd-\b-d\bdi\bis\bsk\bks\bs=\b=_\bZ _\bd_\be_\bv_\bi_\bc_\be_\bs
+
+
+       This  usage will initialise a new md array, associate some
+       devices with it, and activate the array.
+
+       As devices are added, they are checked to see if they con-
+       tain  raid superblocks or filesystems. They are also check
+       to see if the variance in device size exceeds 1%.
+
+       If any discrepancy is found, the array will not  automati-
+       cally  be run, though the presence of a -\b--\b-r\bru\bun\bn can override
+       this caution.
+
+
+       The General Management options that are valid with  --cre-
+       ate are:
+
+       -\b--\b-r\bru\bun\bn  insist  of  running  the array even if some devices
+              look like they might be in use.
+
+
+       -\b--\b-r\bre\bea\bad\bdo\bon\bnl\bly\by
+              start the array readonly - not supported yet.
+
+
+D\bDE\bET\bTA\bAI\bIL\bL M\bMO\bOD\bDE\bE
+       Usage: m\bmd\bdc\bct\btl\bl -\b--\b-d\bde\bet\bta\bai\bil\bl [-\b--\b-b\bbr\bri\bie\bef\bf] _\bd_\be_\bv_\bi_\bc_\be _\b._\b._\b.
+
+
+       This usage sill print out the details of the  given  array
+       including a list of component devices.  To determine names
+       for the devices, m\bmd\bdc\bct\btl\bl searches /\b/d\bde\bev\bv for device files with
+       the right major and minor numbers.
+
+       With  -\b--\b-b\bbr\bri\bie\bef\bf  m\bmd\bdc\bct\btl\bl  prints a single line that identifies
+       the level, number of disks, and UUID of the  array.   This
+       line is suitable for inclusion in /\b/e\bet\btc\bc/\b/m\bmd\bdc\bct\btl\bl.\b.c\bco\bon\bnf\bf.
+
+
+E\bEX\bXA\bAM\bMI\bIN\bNE\bE M\bMO\bOD\bDE\bE
+       Usage: m\bmd\bdc\bct\btl\bl -\b--\b-e\bex\bxa\bam\bmi\bin\bne\be [-\b--\b-s\bsc\bca\ban\bn] [-\b--\b-b\bbr\bri\bie\bef\bf] _\bd_\be_\bv_\bi_\bc_\be _\b._\b._\b.
+
+       This  usage will examine some block devices to see if that
+       have a valid RAID superblock on them.  The information  in
+       each valid raid superblock will be printed.
+
+       If  -\b--\b-s\bsc\bca\ban\bn  is  used, the no devices should be listed, and
+       the complete set of devices identified in  the  configura-
+       tion  file  are  checked.  -\b--\b-s\bsc\bca\ban\bn implies -\b--\b-b\bbr\bri\bie\bef\bf but this
+       implication can be countered by specifying -\b--\b-v\bve\ber\brb\bbo\bos\bse\be.
+
+       With -\b--\b-b\bbr\bri\bie\bef\bf m\bmd\bdc\bct\btl\bl will output an  config  file  entry  of
+       each  distinct array that was found.  This entry will list
+       the UUID, the raid level, and a  list  of  the  individual
+       devices  on  which  a superblock for that array was found.
+       This output will by syntactically suitable  for  inclusion
+       in the configuration file, but should N\bNO\bOT\bT be used blindly.
+       Often the array description that you want in the  configu-
+       ration file is much less specific than that given by m\bmd\bdc\bct\btl\bl
+       -\b-B\bBs\bs.  For example, you normally do not want  to  list  the
+       devices, particularly if they are SCSI devices.
+
+
+
+F\bFI\bIL\bLE\bES\bS
+   /\b/p\bpr\bro\boc\bc/\b/m\bmd\bds\bst\bta\bat\bt
+       If  you're  using the /\b/p\bpr\bro\boc\bc filesystem, /\b/p\bpr\bro\boc\bc/\b/m\bmd\bds\bst\bta\bat\bt gives
+       you informations about md devices status.   This  file  is
+       not currently used by m\bmd\bdc\bct\btl\bl.
+
+
+   /\b/e\bet\btc\bc/\b/m\bmd\bdc\bct\btl\bl.\b.c\bco\bon\bnf\bf
+       The  config  file  is  line oriented with, as usual, blank
+       lines and lines beginning with a hash (or  pound  sign  or
+       sharp  or  number  sign,  whichever  you  like to call it)
+       ignored.  Lines that start with a  blank  are  treated  as
+       continuations  of the previous line (I don't like trailing
+       slashes).
+
+       Each line contains a sequence  of  space-separated  words,
+       the  first  of which identified the type of line. Keywords
+       are case-insensitive, and the first work on a line can  be
+       abbreviated to 3 letters.
+
+       There are two types of lines. ARRAY and DEVICE.
+
+       The  DEVICE  lines usually come first. All remaining words
+       on the line are treated as names of devices, possibly con-
+       taining  wild  cards  (see  _\bg_\bl_\bo_\bb(7)).   These list all the
+       devices that m\bmd\bdc\bct\btl\bl is allowed to  scan  when  looking  for
+       devices with RAID superblocks.  Each line can contain mul-
+       tiple device names,  and  there  can  be  multiple  DEVICE
+       lines.  For example:
+
+              DEVICE /dev/hda* /dev/hdc*
+              DEV    /dev/sd*
+              DEVICE /dev/discs/disc*/disc
+
+       The  ARRAY  lines identify actual arrays.  The second word
+       on the line should be the name of  the  device  where  the
+       array is normally assembled, such as /dev/md1.  Subsequent
+       words identify  the  array.  If  multiple  identities  are
+       given, then the array much match ALL identities to be con-
+       sidered a match.  Each identity word has a tag, and equals
+       sign, and some value.  The options are:
+
+
+       u\buu\bui\bid\bd=\b=  The  value should be a 128 bit uuid in hexadecimal,
+              with punctuation  interspersed  if  desired.   This
+              must match the uuid stored in the superblock.
+
+       s\bsu\bup\bpe\ber\br-\b-m\bmi\bin\bno\bor\br=\b=
+              The  value  is an integer which indicates the minor
+              number that was stored in the superblock  when  the
+              array  was  created.  When  an  array is created as
+              /dev/mdX, then the minor number X is stored.
+
+       d\bde\bev\bvi\bic\bce\bes\bs=\b=
+              The value is  a  comma  separated  list  of  device
+              names.  Precisely  these  devices  will  be used to
+              assemble the array.  Note that the  devices  listed
+              there must also be listed on a DEVICE line.
+
+       l\ble\bev\bve\bel\bl=\b= The  value  is a raid level.  This is normally used
+              to identify an array, but is supported so that  the
+              output   of  m\bmd\bdc\bct\btl\bl  -\b--\b-e\bex\bxa\bam\bmi\bin\bne\be  -\b--\b-s\bsc\bca\ban\bn  can  be  use
+              directly in the configuration file.
+
+       d\bdi\bis\bsk\bks\bs=\b= The value is the number  of  disks  in  a  complete
+              active  array.   As  with l\ble\bev\bve\bel\bl=\b= this is mainly for
+              compatibility with the output  of  m\bmd\bdc\bct\btl\bl  -\b--\b-e\bex\bxa\bam\bmi\bin\bne\be
+              -\b--\b-s\bsc\bca\ban\bn.
+
+
+T\bTO\bOD\bDO\bO
+       Finish and document Follow mode.
+
+
+S\bSE\bEE\bE A\bAL\bLS\bSO\bO
+       For information on the various levels of RAID, check out:
+
+
+              http://ostenfeld.dk/~jakob/Software-RAID.HOWTO/
+
+       for new releases of the RAID driver check out:
+
+
+              ftp://ftp.kernel.org/pub/linux/kernel/peo-
+              ple/mingo/raid-patches
+
+       or
+
+              http://www.cse.unsw.edu.au/~neilb/patches/linux-
+              stable/
+
+       _\br_\ba_\bi_\bd_\bt_\ba_\bb(5), _\br_\ba_\bi_\bd_\b0_\br_\bu_\bn(8), _\br_\ba_\bi_\bd_\bs_\bt_\bo_\bp(8), _\bm_\bk_\br_\ba_\bi_\bd(8)
+
+
+
+                                                         mdctl(8)
diff --git a/util.c b/util.c
index ea30b3109096a3501ad41aa8e5ef9d8556ab49ea..17a7e87d6272b968445f588aa52dd5ad0655a2bd 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,7 +1,7 @@
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
 /*
  * mdctl - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -424,3 +424,16 @@ int calc_sb_csum(mdp_super_t *super)
        super->sb_csum = oldcsum;
        return csum;
 }
        super->sb_csum = oldcsum;
        return csum;
 }
+
+char *human_size(long kbytes)
+{
+       static char buf[30];
+
+       if (kbytes < 2000)
+               buf[0]=0;
+       else if (kbytes < 2*1024*1024)
+               sprintf(buf, " (%d MiB)", kbytes>>10);
+       else
+               sprintf(buf, " (%d GiB)", kbytes>>20);
+       return buf;
+}