]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
getinfo_super1: Use MaxSector in place of sb->size
[thirdparty/mdadm.git] / super1.c
index e8f59c6a1132afaf4dfa90a9975d2f4cf2cba619..d23d6e8e5464ebd734c35a884066ea482b2d8650 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -111,7 +111,6 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
        unsigned long long newcsum;
        int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2;
        unsigned int *isuper = (unsigned int*)sb;
-       int i;
 
 /* make sure I can count... */
        if (offsetof(struct mdp_superblock_1,data_offset) != 128 ||
@@ -123,7 +122,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
        disk_csum = sb->sb_csum;
        sb->sb_csum = 0;
        newcsum = 0;
-       for (i=0; size>=4; size -= 4 ) {
+       for (; size>=4; size -= 4 ) {
                newcsum += __le32_to_cpu(*isuper);
                isuper++;
        }
@@ -314,7 +313,7 @@ static void examine_super1(struct supertype *st, char *homehost)
                printf("\n");
        }
        if (sb->devflags) {
-               printf("      Flags :");
+               printf("          Flags :");
                if (sb->devflags & WriteMostly1)
                        printf(" write-mostly");
                printf("\n");
@@ -387,15 +386,11 @@ static void examine_super1(struct supertype *st, char *homehost)
        printf("   Array State : ");
        for (d=0; d<__le32_to_cpu(sb->raid_disks) + delta_extra; d++) {
                int cnt = 0;
-               int me = 0;
                unsigned int i;
                for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
                        unsigned int role = __le16_to_cpu(sb->dev_roles[i]);
-                       if (role == d) {
-                               if (i == __le32_to_cpu(sb->dev_number))
-                                       me = 1;
+                       if (role == d)
                                cnt++;
-                       }
                }
                if (cnt > 1) printf("?");
                else if (cnt == 1) printf("A");
@@ -558,13 +553,15 @@ static void uuid_from_super1(struct supertype *st, int uuid[4])
                cuuid[i] = super->set_uuid[i];
 }
 
-static void getinfo_super1(struct supertype *st, struct mdinfo *info)
+static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
 {
        struct mdp_superblock_1 *sb = st->sb;
        int working = 0;
        unsigned int i;
-       int role;
+       unsigned int role;
+       unsigned int map_disks = info->array.raid_disks;
 
+       memset(info, 0, sizeof(*info));
        info->array.major_version = 1;
        info->array.minor_version = st->minor_version;
        info->array.patch_version = 0;
@@ -576,11 +573,13 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
        info->array.utime = __le64_to_cpu(sb->utime);
        info->array.chunk_size = __le32_to_cpu(sb->chunksize)*512;
        info->array.state =
-               (__le64_to_cpu(sb->resync_offset) >= __le64_to_cpu(sb->size))
+               (__le64_to_cpu(sb->resync_offset) == MaxSector)
                ? 1 : 0;
 
        info->data_offset = __le64_to_cpu(sb->data_offset);
        info->component_size = __le64_to_cpu(sb->size);
+       if (sb->feature_map & __le32_to_cpu(MD_FEATURE_BITMAP_OFFSET))
+               info->bitmap_offset = __le32_to_cpu(sb->bitmap_offset);
 
        info->disk.major = 0;
        info->disk.minor = 0;
@@ -603,6 +602,8 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
                info->disk.state = 6; /* active and in sync */
                info->disk.raid_disk = role;
        }
+       if (sb->devflags & WriteMostly1)
+               info->disk.state |= (1 << MD_DISK_WRITEMOSTLY);
        info->events = __le64_to_cpu(sb->events);
        sprintf(info->text_version, "1.%d", st->minor_version);
        info->safe_mode_delay = 200;
@@ -629,22 +630,43 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info)
        } else
                info->reshape_active = 0;
 
+       info->recovery_blocked = info->reshape_active;
+
+       if (map)
+               for (i=0; i<map_disks; i++)
+                       map[i] = 0;
        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)
+               if (/*role == 0xFFFF || */role < (unsigned) info->array.raid_disks) {
                        working++;
+                       if (map && role < map_disks)
+                               map[role] = 1;
+               }
        }
 
        info->array.working_disks = working;
 }
 
+static struct mdinfo *container_content1(struct supertype *st, char *subarray)
+{
+       struct mdinfo *info;
+
+       if (subarray)
+               return NULL;
+
+       info = malloc(sizeof(*info));
+       getinfo_super1(st, info, NULL);
+       return info;
+}
+
 static int update_super1(struct supertype *st, struct mdinfo *info,
                         char *update,
                         char *devname, int verbose,
                         int uuid_set, char *homehost)
 {
-       /* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made.
-        * For others, the return value is ignored.
+       /* NOTE: for 'assemble' and 'force' we need to return non-zero
+        * if any change was made.  For others, the return value is
+        * ignored.
         */
        int rv = 0;
        struct mdp_superblock_1 *sb = st->sb;
@@ -656,8 +678,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                if (sb->events != __cpu_to_le64(info->events))
                        rv = 1;
                sb->events = __cpu_to_le64(info->events);
-       }
-       if (strcmp(update, "force-array")==0) {
+       } else if (strcmp(update, "force-array")==0) {
                /* Degraded array and 'force' requests to
                 * maybe need to mark it 'clean'.
                 */
@@ -668,8 +689,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                rv = 1;
                        sb->resync_offset = MaxSector;
                }
-       }
-       if (strcmp(update, "assemble")==0) {
+       } else if (strcmp(update, "assemble")==0) {
                int d = info->disk.number;
                int want;
                if (info->disk.state == 6)
@@ -694,8 +714,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        sb->reshape_position = __cpu_to_le64(info->reshape_progress);
                        rv = 1;
                }
-       }
-       if (strcmp(update, "linear-grow-new") == 0) {
+       } else if (strcmp(update, "linear-grow-new") == 0) {
                unsigned int i;
                int rfd, fd;
                unsigned int max = __le32_to_cpu(sb->max_dev);
@@ -737,17 +756,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                                        ds - __le64_to_cpu(sb->data_offset));
                        }
                }
-       }
-       if (strcmp(update, "linear-grow-update") == 0) {
+       } else if (strcmp(update, "linear-grow-update") == 0) {
                sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
                sb->dev_roles[info->disk.number] =
                        __cpu_to_le16(info->disk.raid_disk);
-       }
-       if (strcmp(update, "resync") == 0) {
+       } else if (strcmp(update, "resync") == 0) {
                /* make sure resync happens */
                sb->resync_offset = 0ULL;
-       }
-       if (strcmp(update, "uuid") == 0) {
+       } else if (strcmp(update, "uuid") == 0) {
                copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
 
                if (__le32_to_cpu(sb->feature_map)&MD_FEATURE_BITMAP_OFFSET) {
@@ -755,9 +771,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        bm = (struct bitmap_super_s*)(st->sb+1024);
                        memcpy(bm->uuid, sb->set_uuid, 16);
                }
-       }
-       if (strcmp(update, "homehost") == 0 &&
-           homehost) {
+       } else if (strcmp(update, "no-bitmap") == 0) {
+               sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
+       } else if (strcmp(update, "homehost") == 0 &&
+                  homehost) {
                char *c;
                update = "name";
                c = strchr(sb->set_name, ':');
@@ -766,8 +783,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                else
                        strncpy(info->name, sb->set_name, 32);
                info->name[32] = 0;
-       }
-       if (strcmp(update, "name") == 0) {
+       } else if (strcmp(update, "name") == 0) {
                if (info->name[0] == 0)
                        sprintf(info->name, "%d", info->array.md_minor);
                memset(sb->set_name, 0, sizeof(sb->set_name));
@@ -779,8 +795,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        strcat(sb->set_name, info->name);
                } else
                        strcpy(sb->set_name, info->name);
-       }
-       if (strcmp(update, "devicesize") == 0 &&
+       } else if (strcmp(update, "devicesize") == 0 &&
            __le64_to_cpu(sb->super_offset) <
            __le64_to_cpu(sb->data_offset)) {
                /* set data_size to device size less data_offset */
@@ -792,9 +807,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        misc->device_size - __le64_to_cpu(sb->data_offset));
                printf("Size is %llu\n", (unsigned long long)
                       __le64_to_cpu(sb->data_size));
-       }
-       if (strcmp(update, "_reshape_progress")==0)
+       } else if (strcmp(update, "_reshape_progress")==0)
                sb->reshape_position = __cpu_to_le64(info->reshape_progress);
+       else if (strcmp(update, "writemostly")==0)
+               sb->devflags |= WriteMostly1;
+       else if (strcmp(update, "readwrite")==0)
+               sb->devflags &= ~WriteMostly1;
+       else
+               rv = -1;
 
        sb->sb_csum = calc_sb_1_csum(sb);
        return rv;
@@ -913,6 +933,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
                sb->max_dev = __cpu_to_le32(dk->number+1);
 
        sb->dev_number = __cpu_to_le32(dk->number);
+       sb->devflags = 0; /* don't copy another disks flags */
        sb->sb_csum = calc_sb_1_csum(sb);
 
        dip = (struct devinfo **)&st->info;
@@ -1019,11 +1040,13 @@ static unsigned long choose_bm_space(unsigned long devsize)
        return 4*2;
 }
 
+static void free_super1(struct supertype *st);
+
 #ifndef MDASSEMBLE
 static int write_init_super1(struct supertype *st)
 {
        struct mdp_superblock_1 *sb = st->sb;
-       struct supertype refst;
+       struct supertype *refst;
        int rfd;
        int rv = 0;
        unsigned long long bm_space;
@@ -1043,7 +1066,9 @@ static int write_init_super1(struct supertype *st)
 
                sb->dev_number = __cpu_to_le32(di->disk.number);
                if (di->disk.state & (1<<MD_DISK_WRITEMOSTLY))
-                       sb->devflags |= __cpu_to_le32(WriteMostly1);
+                       sb->devflags |= WriteMostly1;
+               else
+                       sb->devflags &= ~WriteMostly1;
 
                if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 ||
                    read(rfd, sb->device_uuid, 16) != 16) {
@@ -1055,10 +1080,9 @@ static int write_init_super1(struct supertype *st)
 
                sb->events = 0;
 
-               refst =*st;
-               refst.sb = NULL;
-               if (load_super1(&refst, di->fd, NULL)==0) {
-                       struct mdp_superblock_1 *refsb = refst.sb;
+               refst = dup_super(st);
+               if (load_super1(refst, di->fd, NULL)==0) {
+                       struct mdp_superblock_1 *refsb = refst->sb;
 
                        memcpy(sb->device_uuid, refsb->device_uuid, 16);
                        if (memcmp(sb->set_uuid, refsb->set_uuid, 16)==0) {
@@ -1071,8 +1095,9 @@ static int write_init_super1(struct supertype *st)
                                if (get_linux_version() >= 2006018)
                                        sb->dev_number = refsb->dev_number;
                        }
-                       free(refsb);
+                       free_super1(refst);
                }
+               free(refst);
 
                if (!get_dev_size(di->fd, NULL, &dsize))
                        return 1;
@@ -1207,8 +1232,6 @@ static int compare_super1(struct supertype *st, struct supertype *tst)
        return 0;
 }
 
-static void free_super1(struct supertype *st);
-
 static int load_super1(struct supertype *st, int fd, char *devname)
 {
        unsigned long long dsize;
@@ -1220,9 +1243,6 @@ static int load_super1(struct supertype *st, int fd, char *devname)
 
        free_super1(st);
 
-       if (st->subarray[0])
-               return 1;
-
        if (st->ss == NULL || st->minor_version == -1) {
                int bestvers = -1;
                struct supertype tst;
@@ -1366,7 +1386,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
        return 0;
 
  no_bitmap:
-       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ~1);
+       super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map)
+                                          & ~MD_FEATURE_BITMAP_OFFSET);
        return 0;
 }
 
@@ -1377,6 +1398,7 @@ static struct supertype *match_metadata_desc1(char *arg)
        if (!st) return st;
 
        memset(st, 0, sizeof(*st));
+       st->container_dev = NoMdDev;
        st->ss = &super1;
        st->max_devs = 384;
        st->sb = NULL;
@@ -1467,12 +1489,10 @@ add_internal_bitmap1(struct supertype *st,
                     int may_change, int major)
 {
        /*
-        * If not may_change, then this is a 'Grow', and the bitmap
-        * must fit after the superblock.
-        * If may_change, then this is create, and we can put the bitmap
-        * before the superblock if we like, or may move the start.
-        * If !may_change, the bitmap MUST live at offset of 1K, until
-        * we get a sysfs interface.
+        * If not may_change, then this is a 'Grow' without sysfs support for
+        * bitmaps, and the bitmap must fit after the superblock at 1K offset.
+        * If may_change, then this is create or a Grow with sysfs syupport,
+        * and we can put the bitmap wherever we like.
         *
         * size is in sectors,  chunk is in bytes !!!
         */
@@ -1483,15 +1503,20 @@ add_internal_bitmap1(struct supertype *st,
        long offset;
        unsigned long long chunk = *chunkp;
        int room = 0;
+       int creating = 0;
        struct mdp_superblock_1 *sb = st->sb;
        bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
+       int uuid[4];
 
+       if (__le64_to_cpu(sb->data_size) == 0)
+               /* Must be creating the array, else data_size would be non-zero */
+               creating = 1;
        switch(st->minor_version) {
        case 0:
                /* either 3K after the superblock (when hot-add),
                 * or some amount of space before.
                 */
-               if (may_change) {
+               if (creating) {
                        /* We are creating array, so we *know* how much room has
                         * been left.
                         */
@@ -1501,8 +1526,8 @@ add_internal_bitmap1(struct supertype *st,
                        room = __le64_to_cpu(sb->super_offset)
                                - __le64_to_cpu(sb->data_offset)
                                - __le64_to_cpu(sb->data_size);
-                       /* remove '1 ||' when we can set offset via sysfs */
-                       if (1 || (room < 3*2 &&
+
+                       if (!may_change || (room < 3*2 &&
                                  __le32_to_cpu(sb->max_dev) <= 384)) {
                                room = 3*2;
                                offset = 1*2;
@@ -1513,17 +1538,17 @@ add_internal_bitmap1(struct supertype *st,
                break;
        case 1:
        case 2: /* between superblock and data */
-               if (may_change) {
+               if (creating) {
                        offset = 4*2;
                        room = choose_bm_space(__le64_to_cpu(sb->size));
                } else {
                        room = __le64_to_cpu(sb->data_offset)
                                - __le64_to_cpu(sb->super_offset);
-                       if (1 || __le32_to_cpu(sb->max_dev) <= 384) {
-                               room -= 2;
+                       if (!may_change) {
+                               room -= 2; /* Leave 1K for superblock */
                                offset = 2;
                        } else {
-                               room -= 4*2;
+                               room -= 4*2; /* leave 4K for superblock */
                                offset = 4*2;
                        }
                }
@@ -1568,11 +1593,13 @@ add_internal_bitmap1(struct supertype *st,
 
        sb->bitmap_offset = __cpu_to_le32(offset);
 
-       sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
+       sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map)
+                                       | MD_FEATURE_BITMAP_OFFSET);
        memset(bms, 0, sizeof(*bms));
        bms->magic = __cpu_to_le32(BITMAP_MAGIC);
        bms->version = __cpu_to_le32(major);
-       uuid_from_super1(st, (int*)bms->uuid);
+       uuid_from_super1(st, uuid);
+       memcpy(bms->uuid, uuid, 16);
        bms->chunksize = __cpu_to_le32(chunk);
        bms->daemon_sleep = __cpu_to_le32(delay);
        bms->sync_size = __cpu_to_le64(size);
@@ -1582,7 +1609,6 @@ add_internal_bitmap1(struct supertype *st,
        return 1;
 }
 
-
 static void locate_bitmap1(struct supertype *st, int fd)
 {
        unsigned long long offset;
@@ -1610,7 +1636,7 @@ static int write_bitmap1(struct supertype *st, int fd)
        int rv = 0;
 
        int towrite, n;
-       char *buf = (char*)(((long)(abuf+4096))&~4095UL);
+       char buf[4096];
 
        locate_bitmap1(st, fd);
 
@@ -1625,7 +1651,7 @@ static int write_bitmap1(struct supertype *st, int fd)
                n = towrite;
                if (n > 4096)
                        n = 4096;
-               n = write(fd, buf, n);
+               n = awrite(fd, buf, n);
                if (n > 0)
                        towrite -= n;
                else
@@ -1643,13 +1669,20 @@ static void free_super1(struct supertype *st)
 {
        if (st->sb)
                free(st->sb);
+       while (st->info) {
+               struct devinfo *di = st->info;
+               st->info = di->next;
+               if (di->fd >= 0)
+                       close(di->fd);
+               free(di);
+       }
        st->sb = NULL;
 }
 
 #ifndef MDASSEMBLE
 static int validate_geometry1(struct supertype *st, int level,
                              int layout, int raiddisks,
-                             int chunk, unsigned long long size,
+                             int *chunk, unsigned long long size,
                              char *subdev, unsigned long long *freesize,
                              int verbose)
 {
@@ -1661,6 +1694,9 @@ static int validate_geometry1(struct supertype *st, int level,
                        fprintf(stderr, Name ": 1.x metadata does not support containers\n");
                return 0;
        }
+       if (chunk && *chunk == UnSet)
+               *chunk = DEFAULT_CHUNK;
+
        if (!subdev)
                return 1;
 
@@ -1698,6 +1734,7 @@ struct superswitch super1 = {
        .match_home = match_home1,
        .uuid_from_super = uuid_from_super1,
        .getinfo_super = getinfo_super1,
+       .container_content = container_content1,
        .update_super = update_super1,
        .init_super = init_super1,
        .store_super = store_super1,