]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Use ADD_NEW_DISK to hot-add to non-version-0 arrays
authorNeil Brown <neilb@suse.de>
Tue, 7 Jun 2005 23:16:32 +0000 (23:16 +0000)
committerNeil Brown <neilb@suse.de>
Tue, 7 Jun 2005 23:16:32 +0000 (23:16 +0000)
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Manage.c
super1.c

index c1debfa97f9ba9ca7e6af8ed019fb72f30e273c5..85168f4c623e2c773571d991bc02e3ece6b306d6 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -169,8 +169,8 @@ int Manage_subdevs(char *devname, int fd,
        struct stat stb;
        int j;
        int tfd;
-       int save_errno;
-       static char buf[4096];
+       struct supertype *st;
+       void *dsuper = NULL;
 
        if (ioctl(fd, GET_ARRAY_INFO, &array)) {
                fprintf(stderr, Name ": cannot get array info for %s\n",
@@ -203,26 +203,54 @@ int Manage_subdevs(char *devname, int fd,
                                return 1;
                        }
                        close(tfd);
-                       if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) {
-                               fprintf(stderr, Name ": hot added %s\n",
-                                       dv->devname);
-                               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 
-                                */
+                       if (array.major_version == 0) {
+                               if (ioctl(fd, HOT_ADD_DISK,
+                                         (unsigned long)stb.st_rdev)==0) {
+                                       fprintf(stderr, Name ": hot added %s\n",
+                                               dv->devname);
+                                       continue;
+                               }
+
                                fprintf(stderr, Name ": hot add failed for %s: %s\n",
-                                       dv->devname, strerror(save_errno));
+                                       dv->devname, strerror(errno));
                                return 1;
                        }
-                       /* try ADD_NEW_DISK.
-                        * we might be creating, we might be assembling,
-                        * it is hard to tell.
-                        * set up number/raid_disk/state just
-                        * in case
+
+                       /* need to find a sample superblock to copy, and
+                        * a spare slot to use 
                         */
+                       st = super_by_version(array.major_version,
+                                             array.minor_version);
+                       if (!st) {
+                               fprintf(stderr, Name ": unsupport array - version %d.%d\n",
+                                       array.major_version, array.minor_version);
+                               return 1;
+                       }
+                       for (j=0; j<array.active_disks+array.spare_disks+ array.failed_disks; j++) {
+                               char *dev;
+                               int dfd;
+                               disc.number = j;
+                               if (ioctl(fd, GET_DISK_INFO, &disc))
+                                       continue;
+                               if (disc.major==0 && disc.minor==0)
+                                       continue;
+                               if ((disc.state & 4)==0) continue; /* sync */
+                               /* Looks like a good device to try */
+                               dev = map_dev(disc.major, disc.minor);
+                               if (!dev) continue;
+                               dfd = open(dev, O_RDONLY);
+                               if (dfd < 0) continue;
+                               if (st->ss->load_super(st, dfd, &dsuper, NULL)) {
+                                       close(dfd);
+                                       continue;
+                               }
+                               close(dfd);
+                               break;
+                       }
+                       if (!dsuper) {
+                               fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
+                               return 1;
+                       }
                        for (j=0; j<array.nr_disks; j++) {
                                disc.number = j;
                                if (ioctl(fd, GET_DISK_INFO, &disc))
@@ -232,11 +260,12 @@ int Manage_subdevs(char *devname, int fd,
                                if (disc.state & 8) /* removed */
                                        break;
                        }
-                       disc.number =j;
-                       disc.raid_disk = j;
-                       disc.state = 0;
                        disc.major = major(stb.st_rdev);
                        disc.minor = minor(stb.st_rdev);
+                       disc.number =j;
+                       disc.state = 0;
+                       if (st->ss->write_init_super(st, dsuper, &disc, dv->devname))
+                               return 1;
                        if (ioctl(fd,ADD_NEW_DISK, &disc)) {
                                fprintf(stderr, Name ": add new device failed for %s: %s\n",
                                        dv->devname, strerror(errno));
index 6330248496276fa24fcfdd67a9ff080020b60499..751e28d59908aa9247daa349086762b14a56c70d 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -459,10 +459,13 @@ static int store_super1(int fd, void *sbv)
        return 0;
 }
 
+static int load_super1(struct supertype *st, int fd, void **sbp, char *devname);
+
 static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname)
 {
        struct mdp_superblock_1 *sb = sbv;
-       int fd = open(devname, O_RDWR, O_EXCL);
+       struct mdp_superblock_1 *refsb = NULL;
+       int fd = open(devname, O_RDWR | O_EXCL);
        int rv;
 
        long size;
@@ -476,11 +479,22 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
        }
 
        sb->dev_number = __cpu_to_le32(dinfo->number);
+
        *(__u32*)(sb->device_uuid) = random();
        *(__u32*)(sb->device_uuid+4) = random();
        *(__u32*)(sb->device_uuid+8) = random();
        *(__u32*)(sb->device_uuid+12) = random();
-
+       sb->events = 0;
+
+       if (load_super1(st, fd, (void**)&refsb, NULL)==0) {
+               memcpy(sb->device_uuid, refsb->device_uuid, 16);
+               if (memcmp(sb->set_uuid, refsb->set_uuid, 16)==0) {
+                       /* same array, so preserve events and dev_number */
+                       sb->events = refsb->events;
+                       sb->dev_number = refsb->dev_number;
+               }
+               free(refsb);
+       }
     
        if (ioctl(fd, BLKGETSIZE, &size)) {
                close(fd);