]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
Add gpt pseudo-metadata
[thirdparty/mdadm.git] / super1.c
index fee22a971aa1ce16496e7d636a93b0cc43a47921..01473d14e68897666d0ef536df01d32ebf1aac30 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -76,8 +76,8 @@ struct mdp_superblock_1 {
        __u64   utime;          /* 40 bits second, 24 btes microseconds */
        __u64   events;         /* incremented when superblock updated */
        __u64   resync_offset;  /* data before this offset (from data_offset) known to be in sync */
-       __u32   sb_csum;        /* checksum upto devs[max_dev] */
-       __u32   max_dev;        /* size of devs[] array to consider */
+       __u32   sb_csum;        /* checksum upto dev_roles[max_dev] */
+       __u32   max_dev;        /* size of dev_roles[] array to consider */
        __u8    pad3[64-32];    /* set to 0 when writing */
 
        /* device state information. Indexed by dev_number.
@@ -199,8 +199,9 @@ static void examine_super1(struct supertype *st, char *homehost)
 {
        struct mdp_superblock_1 *sb = st->sb;
        time_t atime;
-       int d;
+       unsigned int d;
        int role;
+       int delta_extra = 0;
        int i;
        char *c;
        int l = homehost ? strlen(homehost) : 0;
@@ -238,7 +239,7 @@ static void examine_super1(struct supertype *st, char *homehost)
        printf(" Avail Dev Size : %llu%s\n",
               (unsigned long long)__le64_to_cpu(sb->data_size),
               human_size(__le64_to_cpu(sb->data_size)<<9));
-       if (__le32_to_cpu(sb->level) >= 0) {
+       if (__le32_to_cpu(sb->level) > 0) {
                int ddsks=0;
                switch(__le32_to_cpu(sb->level)) {
                case 1: ddsks=1;break;
@@ -283,13 +284,11 @@ static void examine_super1(struct supertype *st, char *homehost)
                       human_size(__le64_to_cpu(sb->reshape_position)<<9));
                if (__le32_to_cpu(sb->delta_disks)) {
                        printf("  Delta Devices : %d", __le32_to_cpu(sb->delta_disks));
-                       if (__le32_to_cpu(sb->delta_disks))
-                               printf(" (%d->%d)\n",
-                                      __le32_to_cpu(sb->raid_disks)-__le32_to_cpu(sb->delta_disks),
-                                      __le32_to_cpu(sb->raid_disks));
-                       else
-                               printf(" (%d->%d)\n", __le32_to_cpu(sb->raid_disks),
-                                      __le32_to_cpu(sb->raid_disks)+__le32_to_cpu(sb->delta_disks));
+                       printf(" (%d->%d)\n",
+                              __le32_to_cpu(sb->raid_disks)-__le32_to_cpu(sb->delta_disks),
+                              __le32_to_cpu(sb->raid_disks));
+                       if ((int)__le32_to_cpu(sb->delta_disks) < 0)
+                               delta_extra = -__le32_to_cpu(sb->delta_disks);
                }
                if (__le32_to_cpu(sb->new_level) != __le32_to_cpu(sb->level)) {
                        c = map_num(pers, __le32_to_cpu(sb->new_level));
@@ -300,6 +299,10 @@ static void examine_super1(struct supertype *st, char *homehost)
                                c = map_num(r5layout, __le32_to_cpu(sb->new_layout));
                                printf("     New Layout : %s\n", c?c:"-unknown-");
                        }
+                       if (__le32_to_cpu(sb->level) == 6) {
+                               c = map_num(r6layout, __le32_to_cpu(sb->new_layout));
+                               printf("     New Layout : %s\n", c?c:"-unknown-");
+                       }
                        if (__le32_to_cpu(sb->level) == 10) {
                                printf("     New Layout :");
                                print_r10_layout(__le32_to_cpu(sb->new_layout));
@@ -331,6 +334,10 @@ static void examine_super1(struct supertype *st, char *homehost)
                c = map_num(r5layout, __le32_to_cpu(sb->layout));
                printf("         Layout : %s\n", c?c:"-unknown-");
        }
+       if (__le32_to_cpu(sb->level) == 6) {
+               c = map_num(r6layout, __le32_to_cpu(sb->layout));
+               printf("         Layout : %s\n", c?c:"-unknown-");
+       }
        if (__le32_to_cpu(sb->level) == 10) {
                int lo = __le32_to_cpu(sb->layout);
                printf("         Layout :");
@@ -368,7 +375,7 @@ static void examine_super1(struct supertype *st, char *homehost)
 #endif
        printf("   Device Role : ");
        d = __le32_to_cpu(sb->dev_number);
-       if (d < sb->raid_disks)
+       if (d < __le32_to_cpu(sb->max_dev))
                role = __le16_to_cpu(sb->dev_roles[d]);
        else
                role = 0xFFFF;
@@ -378,12 +385,12 @@ static void examine_super1(struct supertype *st, char *homehost)
                printf("Active device %d\n", role);
 
        printf("   Array State : ");
-       for (d=0; d<__le32_to_cpu(sb->raid_disks); d++) {
+       for (d=0; d<__le32_to_cpu(sb->raid_disks) + delta_extra; d++) {
                int cnt = 0;
                int me = 0;
-               int i;
+               unsigned int i;
                for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
-                       int role = __le16_to_cpu(sb->dev_roles[i]);
+                       unsigned int role = __le16_to_cpu(sb->dev_roles[i]);
                        if (role == d) {
                                if (i == __le32_to_cpu(sb->dev_number))
                                        me = 1;
@@ -555,7 +562,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
 {
        struct mdp_superblock_1 *sb = st->sb;
        int working = 0;
-       int i;
+       unsigned int i;
        int role;
 
        info->array.major_version = 1;
@@ -587,7 +594,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
        info->disk.raid_disk = -1;
        switch(role) {
        case 0xFFFF:
-               info->disk.state = 2; /* spare: ACTIVE, not sync, not faulty */
+               info->disk.state = 0; /* spare: not active, not sync, not faulty */
                break;
        case 0xFFFE:
                info->disk.state = 1; /* faulty */
@@ -605,6 +612,11 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
        strncpy(info->name, sb->set_name, 32);
        info->name[32] = 0;
 
+       if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RECOVERY_OFFSET))
+               info->recovery_start = __le32_to_cpu(sb->recovery_offset);
+       else
+               info->recovery_start = MaxSector;
+
        if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) {
                info->reshape_active = 1;
                info->reshape_progress = __le64_to_cpu(sb->reshape_position);
@@ -612,10 +624,12 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
                info->delta_disks = __le32_to_cpu(sb->delta_disks);
                info->new_layout = __le32_to_cpu(sb->new_layout);
                info->new_chunk = __le32_to_cpu(sb->new_chunk)<<9;
+               if (info->delta_disks < 0)
+                       info->array.raid_disks -= info->delta_disks;
        } else
                info->reshape_active = 0;
 
-       for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
+       for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) {
                role = __le16_to_cpu(sb->dev_roles[i]);
                if (/*role == 0xFFFF || */role < info->array.raid_disks)
                        working++;
@@ -650,9 +664,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                switch(__le32_to_cpu(sb->level)) {
                case 5: case 4: case 6:
                        /* need to force clean */
-                       if (sb->resync_offset != ~0ULL)
+                       if (sb->resync_offset != MaxSector)
                                rv = 1;
-                       sb->resync_offset = ~0ULL;
+                       sb->resync_offset = MaxSector;
                }
        }
        if (strcmp(update, "assemble")==0) {
@@ -668,9 +682,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                }
        }
        if (strcmp(update, "linear-grow-new") == 0) {
-               int i;
+               unsigned int i;
                int rfd, fd;
-               int max = __le32_to_cpu(sb->max_dev);
+               unsigned int max = __le32_to_cpu(sb->max_dev);
 
                for (i=0 ; i < max ; i++)
                        if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe)
@@ -846,7 +860,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
        sb->utime = sb->ctime;
        sb->events = __cpu_to_le64(1);
        if (info->state & (1<<MD_SB_CLEAN))
-               sb->resync_offset = ~0ULL;
+               sb->resync_offset = MaxSector;
        else
                sb->resync_offset = 0;
        sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/
@@ -880,7 +894,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
        else
                *rp = 0xfffe;
 
-       if (dk->number >= __le32_to_cpu(sb->max_dev) &&
+       if (dk->number >= (int)__le32_to_cpu(sb->max_dev) &&
            __le32_to_cpu(sb->max_dev) < 384)
                sb->max_dev = __cpu_to_le32(dk->number+1);
 
@@ -980,6 +994,8 @@ static unsigned long choose_bm_space(unsigned long devsize)
 {
        /* if the device is bigger than 8Gig, save 64k for bitmap usage,
         * if bigger than 200Gig, save 128k
+        * NOTE: result must be multiple of 4K else bad things happen
+        * on 4K-sector devices.
         */
        if (devsize < 64*2) return 0;
        if (devsize - 64*2 >= 200*1024*1024*2)
@@ -996,10 +1012,11 @@ static int write_init_super1(struct supertype *st)
        struct supertype refst;
        int rfd;
        int rv = 0;
-       int bm_space;
+       unsigned long long bm_space;
+       unsigned long long reserved;
        struct devinfo *di;
        unsigned long long dsize, array_size;
-       long long sb_offset;
+       unsigned long long sb_offset;
 
        for (di = st->info; di && ! rv ; di = di->next) {
                if (di->disk.state == 1)
@@ -1007,8 +1024,8 @@ static int write_init_super1(struct supertype *st)
                if (di->fd < 0)
                        continue;
 
-               Kill(di->devname, 0, 1, 1);
-               Kill(di->devname, 0, 1, 1);
+               while (Kill(di->devname, NULL, 0, 1, 1) == 0)
+                       ;
 
                sb->dev_number = __cpu_to_le32(di->disk.number);
                if (di->disk.state & (1<<MD_DISK_WRITEMOSTLY))
@@ -1074,16 +1091,23 @@ static int write_init_super1(struct supertype *st)
                        sb_offset &= ~(4*2-1);
                        sb->super_offset = __cpu_to_le64(sb_offset);
                        sb->data_offset = __cpu_to_le64(0);
-               if (sb_offset - bm_space < array_size)
-                       bm_space = sb_offset - array_size;
+                       if (sb_offset < array_size + bm_space)
+                               bm_space = sb_offset - array_size;
                        sb->data_size = __cpu_to_le64(sb_offset - bm_space);
                        break;
                case 1:
                        sb->super_offset = __cpu_to_le64(0);
-                       if (4*2 + bm_space + __le64_to_cpu(sb->size) > dsize)
-                               bm_space = dsize - __le64_to_cpu(sb->size) -4*2;
-                       sb->data_offset = __cpu_to_le64(bm_space + 4*2);
-                       sb->data_size = __cpu_to_le64(dsize - bm_space - 4*2);
+                       reserved = bm_space + 4*2;
+                       /* Try for multiple of 1Meg so it is nicely aligned */
+                       #define ONE_MEG (2*1024)
+                       reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
+                       if (reserved + __le64_to_cpu(sb->size) > dsize)
+                               reserved = dsize - __le64_to_cpu(sb->size);
+                       /* force 4K alignment */
+                       reserved &= ~7ULL;
+
+                       sb->data_offset = __cpu_to_le64(reserved);
+                       sb->data_size = __cpu_to_le64(dsize - reserved);
                        break;
                case 2:
                        sb_offset = 4*2;
@@ -1092,9 +1116,18 @@ static int write_init_super1(struct supertype *st)
                            > dsize)
                                bm_space = dsize - __le64_to_cpu(sb->size)
                                        - 4*2 - 4*2;
-                       sb->data_offset = __cpu_to_le64(4*2 + 4*2 + bm_space);
-                       sb->data_size = __cpu_to_le64(dsize - 4*2 - 4*2
-                                                     - bm_space );
+
+                       reserved = bm_space + 4*2 + 4*2;
+                       /* Try for multiple of 1Meg so it is nicely aligned */
+                       #define ONE_MEG (2*1024)
+                       reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
+                       if (reserved + __le64_to_cpu(sb->size) > dsize)
+                               reserved = dsize - __le64_to_cpu(sb->size);
+                       /* force 4K alignment */
+                       reserved &= ~7ULL;
+
+                       sb->data_offset = __cpu_to_le64(reserved);
+                       sb->data_size = __cpu_to_le64(dsize - reserved);
                        break;
                default:
                        return -EINVAL;
@@ -1342,11 +1375,15 @@ static struct supertype *match_metadata_desc1(char *arg)
                return st;
        }
        if (strcmp(arg, "1.1") == 0 ||
-           strcmp(arg, "1.01") == 0) {
+           strcmp(arg, "1.01") == 0
+               ) {
                st->minor_version = 1;
                return st;
        }
        if (strcmp(arg, "1.2") == 0 ||
+#ifndef DEFAULT_OLD_METADATA /* ifdef in super0.c */
+           strcmp(arg, "default") == 0 ||
+#endif /* DEFAULT_OLD_METADATA */
            strcmp(arg, "1.02") == 0) {
                st->minor_version = 2;
                return st;
@@ -1383,10 +1420,19 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
        }
 #endif
 
+       if (st->minor_version < 0)
+               /* not specified, so time to set default */
+               st->minor_version = 2;
+       if (super == NULL && st->minor_version > 0) {
+               /* haven't committed to a size yet, so allow some
+                * slack for alignment of data_offset.
+                * We haven't access to device details so allow
+                * 1 Meg if bigger than 1Gig
+                */
+               if (devsize > 1024*1024*2)
+                       devsize -= 1024*2;
+       }
        switch(st->minor_version) {
-       case -1: /* no specified.  Now time to set default */
-               st->minor_version = 0;
-               /* FALL THROUGH */
        case 0:
                /* at end */
                return ((devsize - 8*2 ) & ~(4*2-1));
@@ -1421,15 +1467,15 @@ add_internal_bitmap1(struct supertype *st,
        unsigned long long max_bits;
        unsigned long long min_chunk;
        long offset;
-       int chunk = *chunkp;
+       unsigned long long chunk = *chunkp;
        int room = 0;
        struct mdp_superblock_1 *sb = st->sb;
        bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
 
        switch(st->minor_version) {
        case 0:
-               /* either 3K after the superblock, or some amount of space
-                * before.
+               /* either 3K after the superblock (when hot-add),
+                * or some amount of space before.
                 */
                if (may_change) {
                        /* We are creating array, so we *know* how much room has
@@ -1437,11 +1483,6 @@ add_internal_bitmap1(struct supertype *st,
                         */
                        offset = 0;
                        room = choose_bm_space(__le64_to_cpu(sb->size));
-                       if (room == 4*2) {
-                               /* make it 3K after the superblock */
-                               room = 3*2;
-                               offset = 2;
-                       }
                } else {
                        room = __le64_to_cpu(sb->super_offset)
                                - __le64_to_cpu(sb->data_offset)
@@ -1489,16 +1530,25 @@ add_internal_bitmap1(struct supertype *st,
                min_chunk *= 2;
                bits = (bits+1)/2;
        }
-       if (chunk == UnSet)
+       if (chunk == UnSet) {
+               /* For practical purpose, 64Meg is a good
+                * default chunk size for internal bitmaps.
+                */
                chunk = min_chunk;
-       else if (chunk < min_chunk)
+               if (chunk < 64*1024*1024)
+                       chunk = 64*1024*1024;
+       } else if (chunk < min_chunk)
                return 0; /* chunk size too small */
        if (chunk == 0) /* rounding problem */
                return 0;
 
        if (offset == 0) {
+               /* start bitmap on a 4K boundary with enough space for
+                * the bitmap
+                */
                bits = (size*512) / chunk + 1;
-               room = ((bits+7)/8 + sizeof(bitmap_super_t) +511)/512;
+               room = ((bits+7)/8 + sizeof(bitmap_super_t) +4095)/4096;
+               room *= 8; /* convert 4K blocks to sectors */
                offset = -room;
        }
 
@@ -1592,8 +1642,11 @@ static int validate_geometry1(struct supertype *st, int level,
        unsigned long long ldsize;
        int fd;
 
-       if (level == LEVEL_CONTAINER)
+       if (level == LEVEL_CONTAINER) {
+               if (verbose)
+                       fprintf(stderr, Name ": 1.x metadata does not support containers\n");
                return 0;
+       }
        if (!subdev)
                return 1;