]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Assemble: --update=metadata converts v0.90 to v1.0
authorNeilBrown <neilb@suse.de>
Thu, 23 May 2013 04:41:29 +0000 (14:41 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 28 May 2013 06:44:22 +0000 (16:44 +1000)
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>
Assemble.c
mdadm.8.in
mdadm.c
mdadm.h
super0.c
super1.c

index ab7e249eecd5a84ca903db82b6a042adc1fa52e4..7e8cdb4de8ee75a16cfedb2a7b06dded4159ba13 100644 (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);
 
index c8559dae8e789a30e0c4ee826745a42980629977..e0b77cd9caae59b38abd55e3dd91f394c49ace1d 100644 (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.
diff --git a/mdadm.c b/mdadm.c
index c6a8ebf14c851d0e74c2d85ae952857aac6b9d41..83f1caa90f83fe4dee8cbed00124045378772487 100644 (file)
--- 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 4455b05ad77a501f7c86978ed6ee4579942007bc..d97055ae4f666c54c64351e4e3e86a9cdd22ad22 100644 (file)
--- 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);
index 061e475e52a70c6a2685879c0aaac33600e34cb6..01c31c27b7ce731129397d5b4821d83067d4be17 100644 (file)
--- 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<<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);
 
index b7fc83474bff909687c31d2419283c37e09b76df..a4677b9bbb91d0f3ddfe3ff06a45322a2a5e9d81 100644 (file)
--- 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<<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,