summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2005-06-07 23:16:32 +0000
committerNeil Brown <neilb@suse.de>2005-06-07 23:16:32 +0000
commit892debc8200517e8b00750367acd890199f9f4de (patch)
treeb8add571ad863cf2667ea3a65c7c1d2f25468933
parenteaac7dde0997d00241fea29b6e23659b7d167a65 (diff)
downloadmdadm-892debc8200517e8b00750367acd890199f9f4de.tar.gz
mdadm-892debc8200517e8b00750367acd890199f9f4de.tar.xz
mdadm-892debc8200517e8b00750367acd890199f9f4de.zip
Use ADD_NEW_DISK to hot-add to non-version-0 arrays
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
-rw-r--r--Manage.c71
-rw-r--r--super1.c18
2 files changed, 66 insertions, 23 deletions
diff --git a/Manage.c b/Manage.c
index c1debfa..85168f4 100644
--- 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));
diff --git a/super1.c b/super1.c
index 6330248..751e28d 100644
--- 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);