From: NeilBrown Date: Thu, 23 May 2013 04:41:29 +0000 (+1000) Subject: Assemble: --update=metadata converts v0.90 to v1.0 X-Git-Tag: mdadm-3.3-rc1~41 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=commitdiff_plain;h=afa368f49ac0a12185f243eeedfa8242f2c7a036 Assemble: --update=metadata converts v0.90 to v1.0 This allows the smooth conversion of legacy 0.90 arrays to 1.0 metadata. Old metadata is likely to remain but will be ignored. It can be removed with mdadm --zero-superblock --metadata=0.90 /dev/whatever Signed-off-by: NeilBrown --- diff --git a/Assemble.c b/Assemble.c index ab7e249e..7e8cdb4d 100644 --- a/Assemble.c +++ b/Assemble.c @@ -622,9 +622,10 @@ static int load_devices(struct devs *devices, char *devmap, ident->uuid_set, c->homehost); if (err < 0) { - pr_err("--update=%s not understood" - " for %s metadata\n", - c->update, tst->ss->name); + if (err == -1) + pr_err("--update=%s not understood" + " for %s metadata\n", + c->update, tst->ss->name); tst->ss->free_super(tst); free(tst); close(mdfd); @@ -1665,6 +1666,12 @@ try_again: /* First, fill in the map, so that udev can find our name * as soon as we become active. */ + if (c->update && strcmp(c->update, "metadata")==0) { + content->array.major_version = 1; + content->array.minor_version = 0; + strcpy(content->text_version, "1.0"); + } + map_update(&map, fd2devnm(mdfd), content->text_version, content->uuid, chosen_name); diff --git a/mdadm.8.in b/mdadm.8.in index c8559dae..e0b77cd9 100644 --- a/mdadm.8.in +++ b/mdadm.8.in @@ -1071,6 +1071,7 @@ argument given to this flag can be one of .BR no\-bitmap , .BR bbl , .BR no-\bbl , +.BR metadata , or .BR super\-minor . @@ -1167,6 +1168,19 @@ This will cause to determine the maximum usable amount of space on each device and update the relevant field in the metadata. +The +.B metadata +option only works on v0.90 metadata arrays and will convert them to +v1.0 metadata. The array must not be dirty (i.e. it must not need a +sync) and it must not have a write-intent bitmap. + +The old metadata will remain on the devices, but will appear older +than the new metadata and so will usually be ignored. The old metadata +(or indeed the new metadata) can be removed by giving the appropriate +.B \-\-metadata= +option to +.BR \-\-zero\-superblock . + The .B no\-bitmap option can be used when an array has an internal bitmap which is @@ -1488,7 +1502,9 @@ doesn't appear to be valid. If the device is a container and the argument to \-\-kill\-subarray specifies an inactive subarray in the container, then the subarray is deleted. Deleting all subarrays will leave an 'empty-container' or -spare superblock on the drives. See \-\-zero\-superblock for completely +spare superblock on the drives. See +.B \-\-zero\-superblock +for completely removing a superblock. Note that some formats depend on the subarray index for generating a UUID, this command will fail if it would change the UUID of an active subarray. diff --git a/mdadm.c b/mdadm.c index c6a8ebf1..83f1caa9 100644 --- a/mdadm.c +++ b/mdadm.c @@ -755,6 +755,8 @@ int main(int argc, char *argv[]) continue; if (strcmp(c.update, "no-bbl") == 0) continue; + if (strcmp(c.update, "metadata") == 0) + continue; if (strcmp(c.update, "byteorder")==0) { if (ss) { pr_err("must not set metadata" @@ -785,7 +787,7 @@ int main(int argc, char *argv[]) fprintf(outf, "Valid --update options are:\n" " 'sparc2.2', 'super-minor', 'uuid', 'name', 'resync',\n" " 'summaries', 'homehost', 'byteorder', 'devicesize',\n" - " 'no-bitmap'\n"); + " 'no-bitmap', 'metadata'\n"); exit(outf == stdout ? 0 : 2); case O(MANAGE,'U'): diff --git a/mdadm.h b/mdadm.h index 4455b05a..d97055ae 100644 --- a/mdadm.h +++ b/mdadm.h @@ -937,6 +937,8 @@ struct supertype { char container_devnm[32]; /* devnm of container */ void *sb; void *info; + void *other; /* Hack used to convert v0.90 to v1.0 */ + unsigned long long devsize; int ignore_hw_compat; /* used to inform metadata handlers that it should ignore HW/firmware related incompatability to load metadata. Used when examining metadata to display content of disk @@ -1320,6 +1322,8 @@ extern int child_monitor(int afd, struct mdinfo *sra, struct reshape *reshape, int dests, int *destfd, unsigned long long *destoffsets); void abort_reshape(struct mdinfo *sra); +void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0); + extern void fmt_devname(char *name, int num); extern char *stat2devnm(struct stat *st); extern char *fd2devnm(int fd); diff --git a/super0.c b/super0.c index 061e475e..01c31c27 100644 --- a/super0.c +++ b/super0.c @@ -625,6 +625,26 @@ static int update_super0(struct supertype *st, struct mdinfo *info, uuid_from_super0(st, uuid); memcpy(bm->uuid, uuid, 16); } + } else if (strcmp(update, "metadata") == 0) { + /* Create some v1.0 metadata to match ours but make the + * ctime bigger. Also update info->array.*_version. + * We need to arrange that store_super writes out + * the v1.0 metadata. + * Not permitted for unclean array, or array with + * bitmap. + */ + if (info->bitmap_offset) { + pr_err("Cannot update metadata when bitmap is present\n"); + rv = -2; + } else if (info->array.state != 1) { + pr_err("Cannot update metadata on unclean array\n"); + rv = -2; + } else { + info->array.major_version = 1; + info->array.minor_version = 0; + uuid_from_super0(st, info->uuid); + st->other = super1_make_v0(st, info, st->sb); + } } else if (strcmp(update, "no-bitmap") == 0) { sb->state &= ~(1<other) { + /* Writing out v1.0 metadata for --update=metadata */ + int ret; + + offset = dsize/512 - 8*2; + offset &= ~(4*2-1); + offset *= 512; + if (lseek64(fd, offset, 0)< 0LL) + ret = 3; + else if (write(fd, st->other, 1024) != 1024) + ret = 4; + else + fsync(fd); + free(st->other); + st->other = NULL; + return ret; + } + offset = MD_NEW_SIZE_SECTORS(dsize>>9); offset *= 512; @@ -915,6 +953,7 @@ static int load_super0(struct supertype *st, int fd, char *devname) devname, dsize); return 1; } + st->devsize = dsize; offset = MD_NEW_SIZE_SECTORS(dsize>>9); diff --git a/super1.c b/super1.c index b7fc8347..a4677b9b 100644 --- a/super1.c +++ b/super1.c @@ -2275,6 +2275,60 @@ static int validate_geometry1(struct supertype *st, int level, } #endif /* MDASSEMBLE */ +void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0) +{ + /* Create a v1.0 superblock based on 'info'*/ + void *ret; + struct mdp_superblock_1 *sb; + int i; + int rfd; + unsigned long long offset; + + if (posix_memalign(&ret, 4096, 1024) != 0) + return NULL; + sb = ret; + memset(ret, 0, 1024); + sb->magic = __cpu_to_le32(MD_SB_MAGIC); + sb->major_version = __cpu_to_le32(1); + + copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid); + sprintf(sb->set_name, "%d", sb0->md_minor); + sb->ctime = __cpu_to_le32(info->array.ctime+1); + sb->level = __cpu_to_le32(info->array.level); + sb->layout = __cpu_to_le32(info->array.layout); + sb->size = __cpu_to_le64(info->component_size); + sb->chunksize = __cpu_to_le32(info->array.chunk_size/512); + sb->raid_disks = __cpu_to_le32(info->array.raid_disks); + sb->data_size = sb->size; + sb->resync_offset = MaxSector; + sb->max_dev = __cpu_to_le32(MD_SB_DISKS); + sb->dev_number = __cpu_to_le32(info->disk.number); + sb->utime = __cpu_to_le64(info->array.utime); + + offset = st->devsize/512 - 8*2; + offset &= ~(4*2-1); + sb->super_offset = __cpu_to_le64(offset); + //*(__u64*)(st->other + 128 + 8 + 8) = __cpu_to_le64(offset); + + if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || + read(rfd, sb->device_uuid, 16) != 16) { + __u32 r[4] = {random(), random(), random(), random()}; + memcpy(sb->device_uuid, r, 16); + } + if (rfd >= 0) + close(rfd); + + for (i = 0; i < MD_SB_DISKS; i++) { + int state = sb0->disks[i].state; + sb->dev_roles[i] = 0xFFFF; + if ((state & (1<dev_roles[i] = __cpu_to_le16(sb0->disks[i].raid_disk); + } + sb->sb_csum = calc_sb_1_csum(sb); + return ret; +} + struct superswitch super1 = { #ifndef MDASSEMBLE .examine_super = examine_super1,