]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Manage.c
Create: cleanup after failed create in duplicated array member case
[thirdparty/mdadm.git] / Manage.c
index 6bd33b9408606c2d9b76186df1ce7fef32c1c00e..f6fb3ef1875e7d3e29942ad2d1da08b3982f7a3e 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -1,7 +1,7 @@
 /*
  * mdadm - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  *    Author: Neil Brown
- *    Email: <neilb@cse.unsw.edu.au>
- *    Paper: Neil Brown
- *           School of Computer Science and Engineering
- *           The University of New South Wales
- *           Sydney, 2052
- *           Australia
+ *    Email: <neilb@suse.de>
  */
 
 #include "mdadm.h"
@@ -145,7 +140,7 @@ static void remove_devices(int devnum, char *path)
                strcpy(path2, path);
                pe = path2 + strlen(path2);
        } else
-               path = NULL;
+               path2 = path = NULL;
        
        for (part = 0; part < 16; part++) {
                if (part) {
@@ -166,6 +161,7 @@ static void remove_devices(int devnum, char *path)
                                unlink(path2);
                }
        }
+       free(path2);
 }
        
 
@@ -240,11 +236,32 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet)
                           mdi->array.major_version == -1 &&
                           mdi->array.minor_version == -2 &&
                           !is_subarray(mdi->text_version)) {
+                       struct mdstat_ent *mds, *m;
                        /* container, possibly mdmon-managed.
                         * Make sure mdmon isn't opening it, which
                         * would interfere with the 'stop'
                         */
                        ping_monitor(mdi->sys_name);
+
+                       /* now check that there are no existing arrays
+                        * which are members of this array
+                        */
+                       mds = mdstat_read(0, 0);
+                       for (m=mds; m; m=m->next)
+                               if (m->metadata_version &&
+                                   strncmp(m->metadata_version, "external:", 9)==0 &&
+                                   is_subarray(m->metadata_version+9) &&
+                                   devname2devnum(m->metadata_version+10) == devnum) {
+                                       if (!quiet)
+                                               fprintf(stderr, Name
+                                                       ": Cannot stop container %s: "
+                                                       "member %s still active\n",
+                                                       devname, m->dev);
+                                       free_mdstat(mds);
+                                       if (mdi)
+                                               sysfs_free(mdi);
+                                       return 1;
+                               }
                }
 
                if (fd >= 0 && ioctl(fd, STOP_ARRAY, NULL)) {
@@ -281,11 +298,9 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet)
 
                if (quiet <= 0)
                        fprintf(stderr, Name ": stopped %s\n", devname);
-               if (devnum != NoMdDev) {
-                       map_delete(&map, devnum);
-                       map_write(map);
-                       map_free(map);
-               }
+               map_lock(&map);
+               map_remove(&map, devnum);
+               map_unlock(&map);
        }
        return 0;
 }
@@ -428,10 +443,22 @@ int Manage_subdevs(char *devname, int fd,
                } else {
                        j = 0;
 
-                       if (stat(dv->devname, &stb)) {
-                               fprintf(stderr, Name ": cannot find %s: %s\n",
-                                       dv->devname, strerror(errno));
-                               return 1;
+                       tfd = dev_open(dv->devname, O_RDONLY);
+                       if (tfd < 0 && dv->disposition == 'r' &&
+                           lstat(dv->devname, &stb) == 0)
+                               /* Be happy, the lstat worked, that is
+                                * enough for --remove
+                                */
+                               ;
+                       else {
+                               if (tfd < 0 || fstat(tfd, &stb) != 0) {
+                                       fprintf(stderr, Name ": cannot find %s: %s\n",
+                                               dv->devname, strerror(errno));
+                                       if (tfd >= 0)
+                                               close(tfd);
+                                       return 1;
+                               }
+                               close(tfd);
                        }
                        if ((stb.st_mode & S_IFMT) != S_IFBLK) {
                                fprintf(stderr, Name ": %s is not a "
@@ -454,7 +481,7 @@ int Manage_subdevs(char *devname, int fd,
                                return 1;
                        }
                        /* Make sure it isn't in use (in 2.6 or later) */
-                       tfd = open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT);
+                       tfd = dev_open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT);
                        if (tfd < 0) {
                                fprintf(stderr, Name ": Cannot open %s: %s\n",
                                        dv->devname, strerror(errno));
@@ -565,7 +592,10 @@ int Manage_subdevs(char *devname, int fd,
                                                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
                                                if (dv->writemostly == 2)
                                                        disc.state &= ~(1 << MD_DISK_WRITEMOSTLY);
-                                               if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
+                                               /* don't even try if disk is marked as faulty */
+                                               errno = 0;
+                                               if ((disc.state & 1) == 0 &&
+                                                   ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
                                                        if (verbose >= 0)
                                                                fprintf(stderr, Name ": re-added %s\n", dv->devname);
                                                        continue;
@@ -578,6 +608,12 @@ int Manage_subdevs(char *devname, int fd,
                                                /* fall back on normal-add */
                                        }
                                }
+                               if (dv->re_add) {
+                                       fprintf(stderr, Name
+                                               ": --re-add for %s to %s is not possible\n",
+                                               dv->devname, devname);
+                                       return 1;
+                               }
                        } else {
                                /* non-persistent. Must ensure that new drive
                                 * is at least array.size big.
@@ -610,7 +646,7 @@ int Manage_subdevs(char *devname, int fd,
                                int dfd;
                                if (dv->writemostly == 1)
                                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
-                               dfd = open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
+                               dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
                                if (tst->ss->add_to_super(tst, &disc, dfd,
                                                          dv->devname)) {
                                        close(dfd);
@@ -650,6 +686,7 @@ int Manage_subdevs(char *devname, int fd,
                                                disc.state |= (1<<MD_DISK_SYNC);
                                                break;
                                        }
+                               free(used);
                        }
                        if (dv->writemostly == 1)
                                disc.state |= (1 << MD_DISK_WRITEMOSTLY);
@@ -689,6 +726,7 @@ int Manage_subdevs(char *devname, int fd,
                                tst->ss->getinfo_super(tst, &new_mdi);
                                new_mdi.disk.major = disc.major;
                                new_mdi.disk.minor = disc.minor;
+                               new_mdi.recovery_start = 0;
                                if (sysfs_add_disk(sra, &new_mdi, 0) != 0) {
                                        fprintf(stderr, Name ": add new device to external metadata"
                                                " failed for %s\n", dv->devname);