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 <neilb@suse.de>
This commit is contained in:
NeilBrown 2013-05-23 14:41:29 +10:00
parent d6e4b44fdb
commit afa368f49a
6 changed files with 127 additions and 5 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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'):

View File

@ -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);

View File

@ -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<<MD_SB_BITMAP_PRESENT);
} else if (strcmp(update, "_reshape_progress")==0)
@ -788,6 +808,24 @@ static int store_super0(struct supertype *st, int fd)
if (dsize < MD_RESERVED_SECTORS*512)
return 2;
if (st->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);

View File

@ -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<<MD_DISK_SYNC)) &&
!(state & (1<<MD_DISK_FAULTY)))
sb->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,