From f752781f81a68588d0225cf8e3d96eeb6867b245 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 21 May 2007 14:25:37 +1000 Subject: [PATCH] Fix --grow --add for linear arrays. The new superblock needs to have a new disk.number. This is a bit of a hack... Fix handling of negative bitmap offsets on 64bit hosts. The bitmap offset is a signed 32bit number, so casting to (long) isn't sufficient. We must cast to (int32_t). Fix various problems with --grow --add for linear. The code to add a drive to a live linear array had never been tested properly and so was buggy. This tidies it up and means that the new regression-test passes. --- ChangeLog | 1 + Grow.c | 15 +++++++-------- super0.c | 13 ++++++++++--- super1.c | 31 +++++++++++++++++++++++++++---- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index caa25391..a25463e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Changes Prior to this release - fix internal bitmap allocation problems with v1.1, v1.2 metadata. - --help now goes to stdout so you can direct it to a pager. - Various manpage updates. + - Make "--grow --add" for linear arrays really work. Changes Prior to 2.6.1 release - --monitor was producing some meaningless warnings due to a bug. diff --git a/Grow.c b/Grow.c index c160f2c6..c28c1ac5 100644 --- a/Grow.c +++ b/Grow.c @@ -121,10 +121,12 @@ int Grow_Add_device(char *devname, int fd, char *newdev) info.disk.minor = minor(stb.st_rdev); info.disk.raid_disk = d; info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); - st->ss->update_super(&info, super, "grow", newdev, 0, 0, NULL); + st->ss->update_super(&info, super, "linear-grow-new", newdev, + 0, 0, NULL); if (st->ss->store_super(st, nfd, super)) { - fprintf(stderr, Name ": Cannot store new superblock on %s\n", newdev); + fprintf(stderr, Name ": Cannot store new superblock on %s\n", + newdev); close(nfd); return 1; } @@ -174,12 +176,9 @@ int Grow_Add_device(char *devname, int fd, char *newdev) info.array.nr_disks = nd+1; info.array.active_disks = nd+1; info.array.working_disks = nd+1; - info.disk.number = nd; - info.disk.major = major(stb.st_rdev); - info.disk.minor = minor(stb.st_rdev); - info.disk.raid_disk = nd; - info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); - st->ss->update_super(&info, super, "grow", dv, 0, 0, NULL); + + st->ss->update_super(&info, super, "linear-grow-update", dv, + 0, 0, NULL); if (st->ss->store_super(st, fd2, super)) { fprintf(stderr, Name ": Cannot store new superblock on %s\n", dv); diff --git a/super0.c b/super0.c index 5828e15b..30da8aa2 100644 --- a/super0.c +++ b/super0.c @@ -459,7 +459,16 @@ static int update_super0(struct mdinfo *info, void *sbv, char *update, rv = 1; } } - if (strcmp(update, "grow") == 0) { + if (strcmp(update, "linear-grow-new") == 0) { + memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0])); + sb->disks[info->disk.number].number = info->disk.number; + sb->disks[info->disk.number].major = info->disk.major; + sb->disks[info->disk.number].minor = info->disk.minor; + sb->disks[info->disk.number].raid_disk = info->disk.raid_disk; + sb->disks[info->disk.number].state = info->disk.state; + sb->this_disk = sb->disks[info->disk.number]; + } + if (strcmp(update, "linear-grow-update") == 0) { sb->raid_disks = info->array.raid_disks; sb->nr_disks = info->array.nr_disks; sb->active_disks = info->array.active_disks; @@ -470,8 +479,6 @@ static int update_super0(struct mdinfo *info, void *sbv, char *update, sb->disks[info->disk.number].minor = info->disk.minor; sb->disks[info->disk.number].raid_disk = info->disk.raid_disk; sb->disks[info->disk.number].state = info->disk.state; - if (sb->this_disk.number == info->disk.number) - sb->this_disk = sb->disks[info->disk.number]; } if (strcmp(update, "resync") == 0) { /* make sure resync happens */ diff --git a/super1.c b/super1.c index 5995bb61..0e70e1e9 100644 --- a/super1.c +++ b/super1.c @@ -549,11 +549,34 @@ static int update_super1(struct mdinfo *info, void *sbv, char *update, rv = 1; } } - if (strcmp(update, "grow") == 0) { + if (strcmp(update, "linear-grow-new") == 0) { + int i; + int rfd; + int max = __le32_to_cpu(sb->max_dev); + + for (i=0 ; i < max ; i++) + if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe) + break; + sb->dev_number = __cpu_to_le32(i); + info->disk.number = i; + if (max >= __le32_to_cpu(sb->max_dev)) + sb->max_dev = __cpu_to_le32(max+1); + + if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || + read(rfd, sb->device_uuid, 16) != 16) { + *(__u32*)(sb->device_uuid) = random(); + *(__u32*)(sb->device_uuid+4) = random(); + *(__u32*)(sb->device_uuid+8) = random(); + *(__u32*)(sb->device_uuid+12) = random(); + } + + sb->dev_roles[i] = + __cpu_to_le16(info->disk.raid_disk); + } + if (strcmp(update, "linear-grow-update") == 0) { sb->raid_disks = __cpu_to_le32(info->array.raid_disks); - /* As we are just adding a spare, there is no need to - * make any change to the dev_roles array - */ + sb->dev_roles[info->disk.number] = + __cpu_to_le16(info->disk.raid_disk); } if (strcmp(update, "resync") == 0) { /* make sure resync happens */ -- 2.39.2