]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
Merge branch 'master' in devel-3.0
[thirdparty/mdadm.git] / super1.c
index 2e3ef530106f5883ef7733ec31e6f13e4f090c3b..d1b8a9478ef86da4375177c59312c3c3ef19dbf6 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -141,13 +141,71 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
        return __cpu_to_le32(csum);
 }
 
+static char abuf[4096+4096];
+static int aread(int fd, void *buf, int len)
+{
+       /* aligned read.
+        * On devices with a 4K sector size, we need to read
+        * the full sector and copy relevant bits into
+        * the buffer
+        */
+       int bsize;
+       char *b;
+       int n;
+       if (ioctl(fd, BLKSSZGET, &bsize) != 0 ||
+           bsize <= len)
+               return read(fd, buf, len);
+       if (bsize > 4096)
+               return -1;
+       b = (char*)(((long)(abuf+4096))&~4095UL);
+
+       n = read(fd, b, bsize);
+       if (n <= 0)
+               return n;
+       lseek(fd, len - n, 1);
+       if (n > len)
+               n = len;
+       memcpy(buf, b, n);
+       return n;
+}
+
+static int awrite(int fd, void *buf, int len)
+{
+       /* aligned write.
+        * On devices with a 4K sector size, we need to write
+        * the full sector.  We pre-read if the sector is larger
+        * than the write.
+        * The address must be sector-aligned.
+        */
+       int bsize;
+       char *b;
+       int n;
+       if (ioctl(fd, BLKSSZGET, &bsize) != 0 ||
+           bsize <= len)
+               return write(fd, buf, len);
+       if (bsize > 4096)
+               return -1;
+       b = (char*)(((long)(abuf+4096))&~4095UL);
+
+       n = read(fd, b, bsize);
+       if (n <= 0)
+               return n;
+       lseek(fd, -n, 1);
+       memcpy(b, buf, len);
+       n = write(fd, b, bsize);
+       if (n <= 0)
+               return n;
+       lseek(fd, len - n, 1);
+       return len;
+}
+
 #ifndef MDASSEMBLE
 static void examine_super1(struct supertype *st, char *homehost)
 {
        struct mdp_superblock_1 *sb = st->sb;
        time_t atime;
        int d;
-       int faulty;
+       int role;
        int i;
        char *c;
        int l = homehost ? strlen(homehost) : 0;
@@ -248,10 +306,9 @@ static void examine_super1(struct supertype *st, char *homehost)
                                printf("     New Layout : %s\n", c?c:"-unknown-");
                        }
                        if (__le32_to_cpu(sb->level) == 10) {
-                               printf("     New Layout : near=%d, %s=%d\n",
-                                      __le32_to_cpu(sb->new_layout)&255,
-                                      (__le32_to_cpu(sb->new_layout)&0x10000)?"offset":"far",
-                                      (__le32_to_cpu(sb->new_layout)>>8)&255);
+                               printf("     New Layout :");
+                               print_r10_layout(__le32_to_cpu(sb->new_layout));
+                               printf("\n");
                        }
                }
                if (__le32_to_cpu(sb->new_chunk) != __le32_to_cpu(sb->chunksize))
@@ -281,10 +338,9 @@ static void examine_super1(struct supertype *st, char *homehost)
        }
        if (__le32_to_cpu(sb->level) == 10) {
                int lo = __le32_to_cpu(sb->layout);
-               printf("         Layout : near=%d, %s=%d\n",
-                      lo&255,
-                      (lo&0x10000)?"offset":"far",
-                      (lo>>8)&255);
+               printf("         Layout :");
+               print_r10_layout(lo);
+               printf("\n");
        }
        switch(__le32_to_cpu(sb->level)) {
        case 0:
@@ -300,6 +356,8 @@ static void examine_super1(struct supertype *st, char *homehost)
        default: break;
        }
        printf("\n");
+#if 0
+       /* This turns out to just be confusing */
        printf("    Array Slot : %d (", __le32_to_cpu(sb->dev_number));
        for (i= __le32_to_cpu(sb->max_dev); i> 0 ; i--)
                if (__le16_to_cpu(sb->dev_roles[i-1]) != 0xffff)
@@ -312,6 +370,18 @@ static void examine_super1(struct supertype *st, char *homehost)
                else printf("%d", role);
        }
        printf(")\n");
+#endif
+       printf("   Device Role : ");
+       d = __le32_to_cpu(sb->dev_number);
+       if (d < sb->raid_disks)
+               role = __le16_to_cpu(sb->dev_roles[d]);
+       else
+               role = 0xFFFF;
+       if (role >= 0xFFFE)
+               printf("spare\n");
+       else
+               printf("Active device %d\n", role);
+
        printf("   Array State : ");
        for (d=0; d<__le32_to_cpu(sb->raid_disks); d++) {
                int cnt = 0;
@@ -326,10 +396,11 @@ static void examine_super1(struct supertype *st, char *homehost)
                        }
                }
                if (cnt > 1) printf("?");
-               else if (cnt == 1 && me) printf("U");
-               else if (cnt == 1) printf("u");
-               else printf ("_");
+               else if (cnt == 1) printf("A");
+               else printf (".");
        }
+#if 0
+       /* This is confusing too */
        faulty = 0;
        for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
                int role = __le16_to_cpu(sb->dev_roles[i]);
@@ -337,6 +408,8 @@ static void examine_super1(struct supertype *st, char *homehost)
                        faulty++;
        }
        if (faulty) printf(" %d failed", faulty);
+#endif
+       printf(" ('A' == active, '.' == missing)");
        printf("\n");
 }
 
@@ -355,9 +428,11 @@ static void brief_examine_super1(struct supertype *st)
        else if (sb->set_name[0])
                nm = sb->set_name;
        else
-               nm = "??";
+               nm = NULL;
 
-       printf("ARRAY /dev/md/%s level=%s ", nm, c?c:"-unknown-");
+       printf("ARRAY%s%s level=%s ",
+              nm ? " /dev/md/":"", nm,
+              c?c:"-unknown-");
        sb_offset = __le64_to_cpu(sb->super_offset);
        if (sb_offset <= 4)
                printf("metadata=1.1 ");
@@ -456,12 +531,6 @@ static void export_detail_super1(struct supertype *st)
                }
        if (len)
                printf("MD_NAME=%.*s\n", len, sb->set_name);
-       printf("MD_UUID=");
-       for (i=0; i<16; i++) {
-               if ((i&3)==0 && i != 0) printf(":");
-               printf("%02x", sb->set_uuid[i]);
-       }
-       printf("\n");
 }
 
 #endif
@@ -603,7 +672,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
        }
        if (strcmp(update, "linear-grow-new") == 0) {
                int i;
-               int rfd;
+               int rfd, fd;
                int max = __le32_to_cpu(sb->max_dev);
 
                for (i=0 ; i < max ; i++)
@@ -624,6 +693,25 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
 
                sb->dev_roles[i] =
                        __cpu_to_le16(info->disk.raid_disk);
+
+               fd = open(devname, O_RDONLY);
+               if (fd >= 0) {
+                       unsigned long long ds;
+                       get_dev_size(fd, devname, &ds);
+                       close(fd);
+                       ds >>= 9;
+                       if (__le64_to_cpu(sb->super_offset) <
+                           __le64_to_cpu(sb->data_offset)) {
+                               sb->data_size = __cpu_to_le64(
+                                       ds - __le64_to_cpu(sb->data_offset));
+                       } else {
+                               ds -= 8*2;
+                               ds &= ~(unsigned long long)(4*2-1);
+                               sb->super_offset = __cpu_to_le64(ds);
+                               sb->data_size = __cpu_to_le64(
+                                       ds - __le64_to_cpu(sb->data_offset));
+                       }
+               }
        }
        if (strcmp(update, "linear-grow-update") == 0) {
                sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
@@ -695,8 +783,12 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
        int rfd;
        char defname[10];
 
-       posix_memalign((void**)&sb, 512, (1024 + 512 + 
-                                         sizeof(struct misc_dev_info)));
+       if (posix_memalign((void**)&sb, 512, (1024 + 512 + 
+                          sizeof(struct misc_dev_info))) != 0) {
+               fprintf(stderr, Name
+                       ": %s could not allocate superblock\n", __func__);
+               return 0;
+       }
        memset(sb, 0, 1024);
 
        st->sb = sb;
@@ -779,7 +871,7 @@ struct devinfo {
 };
 #ifndef MDASSEMBLE
 /* Add a device to the superblock being created */
-static void add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
+static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
                          int fd, char *devname)
 {
        struct mdp_superblock_1 *sb = st->sb;
@@ -793,6 +885,10 @@ static void add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
        else
                *rp = 0xfffe;
 
+       if (dk->number >= __le32_to_cpu(sb->max_dev) &&
+           __le32_to_cpu(sb->max_dev) < 384)
+               sb->max_dev = __cpu_to_le32(dk->number+1);
+
        sb->dev_number = __cpu_to_le32(dk->number);
        sb->sb_csum = calc_sb_1_csum(sb);
 
@@ -805,6 +901,8 @@ static void add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
        di->disk = *dk;
        di->next = NULL;
        *dip = di;
+
+       return 0;
 }
 #endif
 
@@ -864,7 +962,7 @@ static int store_super1(struct supertype *st, int fd)
        sbsize = sizeof(*sb) + 2 * __le32_to_cpu(sb->max_dev);
        sbsize = (sbsize+511)&(~511UL);
 
-       if (write(fd, sb, sbsize) != sbsize)
+       if (awrite(fd, sb, sbsize) != sbsize)
                return 4;
 
        if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) {
@@ -872,8 +970,8 @@ static int store_super1(struct supertype *st, int fd)
                        (((char*)sb)+1024);
                if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) {
                        locate_bitmap1(st, fd);
-                       if (write(fd, bm, ROUND_UP(sizeof(*bm),512)) !=
-                           ROUND_UP(sizeof(*bm),512))
+                       if (awrite(fd, bm, sizeof(*bm)) !=
+                           sizeof(*bm))
                            return 5;
                }
        }
@@ -1042,9 +1140,13 @@ static int compare_super1(struct supertype *st, struct supertype *tst)
                return 1;
 
        if (!first) {
-               posix_memalign((void**)&first, 512,
+               if (posix_memalign((void**)&first, 512,
                               1024 + 512 +
-                              sizeof(struct misc_dev_info));
+                              sizeof(struct misc_dev_info)) != 0) {
+                       fprintf(stderr, Name
+                               ": %s could not allocate superblock\n", __func__);
+                       return 1;
+               }
                memcpy(first, second, 1024 + 512 + 
                       sizeof(struct misc_dev_info));
                st->sb = first;
@@ -1158,11 +1260,15 @@ static int load_super1(struct supertype *st, int fd, char *devname)
                return 1;
        }
 
-       posix_memalign((void**)&super, 512,
+       if (posix_memalign((void**)&super, 512,
                       1024 + 512 +
-                      sizeof(struct misc_dev_info));
+                      sizeof(struct misc_dev_info)) != 0) {
+               fprintf(stderr, Name ": %s could not allocate superblock\n",
+                       __func__);
+               return 1;
+       }
 
-       if (read(fd, super, 1024) != 1024) {
+       if (aread(fd, super, 1024) != 1024) {
                if (devname)
                        fprintf(stderr, Name ": Cannot read superblock on %s\n",
                                devname);
@@ -1207,7 +1313,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
         * should get that written out.
         */
        locate_bitmap1(st, fd);
-       if (read(fd, ((char*)super)+1024, 512)
+       if (aread(fd, ((char*)super)+1024, 512)
            != 512)
                goto no_bitmap;
 
@@ -1232,15 +1338,21 @@ static struct supertype *match_metadata_desc1(char *arg)
        st->ss = &super1;
        st->max_devs = 384;
        st->sb = NULL;
-       if (strcmp(arg, "1.0") == 0) {
+       /* leading zeros can be safely ignored.  --detail generates them. */
+       while (*arg == '0')
+               arg++;
+       if (strcmp(arg, "1.0") == 0 ||
+           strcmp(arg, "1.00") == 0) {
                st->minor_version = 0;
                return st;
        }
-       if (strcmp(arg, "1.1") == 0) {
+       if (strcmp(arg, "1.1") == 0 ||
+           strcmp(arg, "1.01") == 0) {
                st->minor_version = 1;
                return st;
        }
-       if (strcmp(arg, "1.2") == 0) {
+       if (strcmp(arg, "1.2") == 0 ||
+           strcmp(arg, "1.02") == 0) {
                st->minor_version = 2;
                return st;
        }
@@ -1260,10 +1372,21 @@ static struct supertype *match_metadata_desc1(char *arg)
  */
 static __u64 avail_size1(struct supertype *st, __u64 devsize)
 {
+       struct mdp_superblock_1 *super = st->sb;
        if (devsize < 24)
                return 0;
 
-       devsize -= choose_bm_space(devsize);
+       if (super == NULL)
+               /* creating:  allow suitable space for bitmap */
+               devsize -= choose_bm_space(devsize);
+#ifndef MDASSEMBLE
+       else if (__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) {
+               /* hot-add. allow for actual size of bitmap */
+               struct bitmap_super_s *bsb;
+               bsb = (struct bitmap_super_s *)(((char*)super)+1024);
+               devsize -= bitmap_sectors(bsb);
+       }
+#endif
 
        switch(st->minor_version) {
        case -1: /* no specified.  Now time to set default */
@@ -1428,8 +1551,7 @@ static int write_bitmap1(struct supertype *st, int fd)
        int rv = 0;
 
        int towrite, n;
-       char abuf[4096+512];
-       char *buf = (char*)(((long)(abuf+512))&~511UL);
+       char *buf = (char*)(((long)(abuf+4096))&~4095UL);
 
        locate_bitmap1(st, fd);
 
@@ -1530,4 +1652,5 @@ struct superswitch super1 = {
 #else
        .swapuuid = 1,
 #endif
+       .name = "1.0",
 };