]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
Show all bitmaps while examining bitmap
[thirdparty/mdadm.git] / super1.c
index b6e1e91955601e0a0cc2caa824ff8f60cf7317c0..bbb9f88a5f9d3072776f41c98864e9b797b4e782 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -22,6 +22,7 @@
  *    Email: <neilb@suse.de>
  */
 
+#include <stddef.h>
 #include "mdadm.h"
 /*
  * The version-1 superblock :
@@ -133,9 +134,6 @@ struct misc_dev_info {
                                        |MD_FEATURE_NEW_OFFSET          \
                                        )
 
-#ifndef offsetof
-#define offsetof(t,f) ((size_t)&(((t*)0)->f))
-#endif
 static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
 {
        unsigned int disk_csum, csum;
@@ -199,8 +197,7 @@ static int aread(struct align_fd *afd, void *buf, int len)
 
        if (!bsize || bsize > 4096 || len > 4096) {
                if (!bsize)
-                       fprintf(stderr, "WARNING - aread() called with "
-                               "invalid block size\n");
+                       fprintf(stderr, "WARNING - aread() called with invalid block size\n");
                return -1;
        }
        b = ROUND_UP_PTR((char *)abuf, 4096);
@@ -232,8 +229,7 @@ static int awrite(struct align_fd *afd, void *buf, int len)
        bsize = afd->blk_sz;
        if (!bsize || bsize > 4096 || len > 4096) {
                if (!bsize)
-                       fprintf(stderr, "WARNING - awrite() called with "
-                               "invalid block size\n");
+                       fprintf(stderr, "WARNING - awrite() called with invalid block size\n");
                return -1;
        }
        b = ROUND_UP_PTR((char *)abuf, 4096);
@@ -813,7 +809,7 @@ static int examine_badblocks_super1(struct supertype *st, int fd, char *devname)
 
        size = __le32_to_cpu(sb->bblog_size)* 512;
        if (posix_memalign((void**)&bbl, 4096, size) != 0) {
-               pr_err("%s could not allocate badblocks list\n", __func__);
+               pr_err("could not allocate badblocks list\n");
                return 0;
        }
        offset = __le64_to_cpu(sb->super_offset) +
@@ -1247,12 +1243,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                /* set data_size to device size less data_offset */
                struct misc_dev_info *misc = (struct misc_dev_info*)
                        (st->sb + MAX_SB_SIZE + BM_SUPER_SIZE);
-               printf("Size was %llu\n", (unsigned long long)
-                      __le64_to_cpu(sb->data_size));
                sb->data_size = __cpu_to_le64(
                        misc->device_size - __le64_to_cpu(sb->data_offset));
-               printf("Size is %llu\n", (unsigned long long)
-                      __le64_to_cpu(sb->data_size));
        } else if (strcmp(update, "revert-reshape") == 0) {
                rv = -2;
                if (!(sb->feature_map & __cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE)))
@@ -1276,14 +1268,17 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                         * So we reject a revert-reshape unless the
                         * alignment is good.
                         */
-                       reshape_sectors = __le64_to_cpu(sb->reshape_position);
-                       reshape_chunk = __le32_to_cpu(sb->new_chunk);
-                       reshape_chunk *= __le32_to_cpu(sb->raid_disks) - __le32_to_cpu(sb->delta_disks) -
-                               (__le32_to_cpu(sb->level)==6 ? 2 : 1);
-                       if (reshape_sectors % reshape_chunk) {
-                               pr_err("Reshape position is not suitably aligned.\n");
-                               pr_err("Try normal assembly as stop again\n");
-                               return -2;
+                       if (__le32_to_cpu(sb->level) >= 4 &&
+                           __le32_to_cpu(sb->level) <= 6) {
+                               reshape_sectors = __le64_to_cpu(sb->reshape_position);
+                               reshape_chunk = __le32_to_cpu(sb->new_chunk);
+                               reshape_chunk *= __le32_to_cpu(sb->raid_disks) - __le32_to_cpu(sb->delta_disks) -
+                                       (__le32_to_cpu(sb->level)==6 ? 2 : 1);
+                               if (reshape_sectors % reshape_chunk) {
+                                       pr_err("Reshape position is not suitably aligned.\n");
+                                       pr_err("Try normal assembly and stop again\n");
+                                       return -2;
+                               }
                        }
                        sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) -
                                                       __le32_to_cpu(sb->delta_disks));
@@ -1301,9 +1296,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        sb->chunksize = temp;
 
                        if (sb->feature_map & __cpu_to_le32(MD_FEATURE_NEW_OFFSET)) {
-                               sb->data_offset = __cpu_to_le64(__le64_to_cpu(sb->data_offset) +
-                                                               (long)(int32_t)__le32_to_cpu(sb->new_offset));
-                               sb->new_offset = __cpu_to_le32(-(int32_t)__le32_to_cpu(sb->new_offset));
+                               long offset_delta = (int32_t)__le32_to_cpu(sb->new_offset);
+                               sb->data_offset = __cpu_to_le64(__le64_to_cpu(sb->data_offset) + offset_delta);
+                               sb->new_offset = __cpu_to_le32(-offset_delta);
+                               sb->data_size = __cpu_to_le64(__le64_to_cpu(sb->data_size) - offset_delta);
                        }
                }
        } else if (strcmp(update, "_reshape_progress")==0)
@@ -1330,7 +1326,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
        int sbsize;
 
        if (posix_memalign((void**)&sb, 4096, SUPER1_SIZE) != 0) {
-               pr_err("%s could not allocate superblock\n", __func__);
+               pr_err("could not allocate superblock\n");
                return 0;
        }
        memset(sb, 0, SUPER1_SIZE);
@@ -1549,14 +1545,13 @@ static int write_init_super1(struct supertype *st)
        int rfd;
        int rv = 0;
        unsigned long long bm_space;
-       unsigned long long reserved;
        struct devinfo *di;
        unsigned long long dsize, array_size;
-       unsigned long long sb_offset, headroom;
+       unsigned long long sb_offset;
        unsigned long long data_offset;
 
        for (di = st->info; di; di = di->next) {
-               if (di->disk.state == 1)
+               if (di->disk.state & (1 << MD_DISK_FAULTY))
                        continue;
                if (di->fd < 0)
                        continue;
@@ -1618,35 +1613,25 @@ static int write_init_super1(struct supertype *st)
                 * 0: At least 8K, but less than 12K, from end of device
                 * 1: At start of device
                 * 2: 4K from start of device.
-                * Depending on the array size, we might leave extra space
-                * for a bitmap.
-                * Also leave 4K for bad-block log.
+                * data_offset has already been set.
                 */
                array_size = __le64_to_cpu(sb->size);
                /* work out how much space we left for a bitmap,
                 * Add 8 sectors for bad block log */
                bm_space = choose_bm_space(array_size) + 8;
 
-               /* We try to leave 0.1% at the start for reshape
-                * operations, but limit this to 128Meg (0.1% of 10Gig)
-                * which is plenty for efficient reshapes
-                * However we make it at least 2 chunks as one chunk
-                * is minimum needed for reshape.
-                */
-               headroom = 128 * 1024 * 2;
-               while  (headroom << 10 > array_size &&
-                       headroom/2 >= __le32_to_cpu(sb->chunksize) * 2)
-                       headroom >>= 1;
-
                data_offset = di->data_offset;
+               if (data_offset == INVALID_SECTORS)
+                       data_offset = st->data_offset;
                switch(st->minor_version) {
                case 0:
+                       if (data_offset == INVALID_SECTORS)
+                               data_offset = 0;
                        sb_offset = dsize;
                        sb_offset -= 8*2;
                        sb_offset &= ~(4*2-1);
+                       sb->data_offset = __cpu_to_le64(data_offset);
                        sb->super_offset = __cpu_to_le64(sb_offset);
-                       if (data_offset == INVALID_SECTORS)
-                               sb->data_offset = 0;
                        if (sb_offset < array_size + bm_space)
                                bm_space = sb_offset - array_size;
                        sb->data_size = __cpu_to_le64(sb_offset - bm_space);
@@ -1657,79 +1642,49 @@ static int write_init_super1(struct supertype *st)
                        break;
                case 1:
                        sb->super_offset = __cpu_to_le64(0);
-                       if (data_offset == INVALID_SECTORS) {
-                               reserved = bm_space + 4*2;
-                               if (reserved < headroom)
-                                       reserved = headroom;
-                               if (reserved + array_size > dsize)
-                                       reserved = dsize - array_size;
-                               /* Try for multiple of 1Meg so it is nicely aligned */
-                               #define ONE_MEG (2*1024)
-                               if (reserved > ONE_MEG)
-                                       reserved = (reserved/ONE_MEG) * ONE_MEG;
-
-                               /* force 4K alignment */
-                               reserved &= ~7ULL;
-
-                       } else
-                               reserved = data_offset;
-
-                       sb->data_offset = __cpu_to_le64(reserved);
-                       sb->data_size = __cpu_to_le64(dsize - reserved);
-                       if (reserved >= 8 + 32*2 + 8) {
+                       if (data_offset == INVALID_SECTORS)
+                               data_offset = 16;
+
+                       sb->data_offset = __cpu_to_le64(data_offset);
+                       sb->data_size = __cpu_to_le64(dsize - data_offset);
+                       if (data_offset >= 8 + 32*2 + 8) {
                                sb->bblog_size = __cpu_to_le16(8);
                                sb->bblog_offset = __cpu_to_le32(8 + 32*2);
-                       } else if (reserved >= 16) {
+                       } else if (data_offset >= 16) {
                                sb->bblog_size = __cpu_to_le16(8);
-                               sb->bblog_offset = __cpu_to_le32(reserved-8);
+                               sb->bblog_offset = __cpu_to_le32(data_offset-8);
                        }
                        break;
                case 2:
                        sb_offset = 4*2;
-                       sb->super_offset = __cpu_to_le64(4*2);
-                       if (data_offset == INVALID_SECTORS) {
-                               if (4*2 + 4*2 + bm_space + array_size
-                                   > dsize)
-                                       bm_space = dsize - array_size
-                                               - 4*2 - 4*2;
-
-                               reserved = bm_space + 4*2 + 4*2;
-                               if (reserved < headroom)
-                                       reserved = headroom;
-                               if (reserved + array_size > dsize)
-                                       reserved = dsize - array_size;
-                               /* Try for multiple of 1Meg so it is nicely aligned */
-                               #define ONE_MEG (2*1024)
-                               if (reserved > ONE_MEG)
-                                       reserved = (reserved/ONE_MEG) * ONE_MEG;
-
-                               /* force 4K alignment */
-                               reserved &= ~7ULL;
-
-                       } else
-                               reserved = data_offset;
-
-                       sb->data_offset = __cpu_to_le64(reserved);
-                       sb->data_size = __cpu_to_le64(dsize - reserved);
-                       if (reserved >= 16 + 32*2 + 8) {
+                       sb->super_offset = __cpu_to_le64(sb_offset);
+                       if (data_offset == INVALID_SECTORS)
+                               data_offset = 24;
+
+                       sb->data_offset = __cpu_to_le64(data_offset);
+                       sb->data_size = __cpu_to_le64(dsize - data_offset);
+                       if (data_offset >= 16 + 32*2 + 8) {
                                sb->bblog_size = __cpu_to_le16(8);
                                sb->bblog_offset = __cpu_to_le32(8 + 32*2);
-                       } else if (reserved >= 16+16) {
+                       } else if (data_offset >= 16+16) {
                                sb->bblog_size = __cpu_to_le16(8);
                                /* '8' sectors for the bblog, and another '8'
                                 * because we want offset from superblock, not
                                 * start of device.
                                 */
-                               sb->bblog_offset = __cpu_to_le32(reserved-8-8);
+                               sb->bblog_offset = __cpu_to_le32(data_offset-8-8);
                        }
                        break;
                default:
-                       pr_err("Failed to write invalid "
-                              "metadata format 1.%i to %s\n",
+                       pr_err("Failed to write invalid metadata format 1.%i to %s\n",
                               st->minor_version, di->devname);
                        rv = -EINVAL;
                        goto out;
                }
+               if (conf_get_create_info()->bblist == 0) {
+                       sb->bblog_size = 0;
+                       sb->bblog_offset = 0;
+               }
 
                sb->sb_csum = calc_sb_1_csum(sb);
                rv = store_super1(st, di->fd);
@@ -1768,7 +1723,7 @@ static int compare_super1(struct supertype *st, struct supertype *tst)
 
        if (!first) {
                if (posix_memalign((void**)&first, 4096, SUPER1_SIZE) != 0) {
-                       pr_err("%s could not allocate superblock\n", __func__);
+                       pr_err("could not allocate superblock\n");
                        return 1;
                }
                memcpy(first, second, SUPER1_SIZE);
@@ -1879,8 +1834,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
        }
 
        if (posix_memalign((void**)&super, 4096, SUPER1_SIZE) != 0) {
-               pr_err("%s could not allocate superblock\n",
-                       __func__);
+               pr_err("could not allocate superblock\n");
                return 1;
        }
 
@@ -1920,6 +1874,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
 
        misc = (struct misc_dev_info*) (((char*)super)+MAX_SB_SIZE+BM_SUPER_SIZE);
        misc->device_size = dsize;
+       if (st->data_offset == INVALID_SECTORS)
+               st->data_offset = __le64_to_cpu(super->data_offset);
 
        /* Now check on the bitmap superblock */
        if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0)
@@ -1952,6 +1908,7 @@ static struct supertype *match_metadata_desc1(char *arg)
        st->ss = &super1;
        st->max_devs = MAX_DEVS;
        st->sb = NULL;
+       st->data_offset = INVALID_SECTORS;
        /* leading zeros can be safely ignored.  --detail generates them. */
        while (*arg == '0')
                arg++;
@@ -1988,19 +1945,17 @@ static struct supertype *match_metadata_desc1(char *arg)
  * superblock type st, and reserving 'reserve' sectors for
  * a possible bitmap
  */
-static __u64 _avail_size1(struct supertype *st, __u64 devsize,
-                         unsigned long long data_offset, int chunksize)
+static __u64 avail_size1(struct supertype *st, __u64 devsize,
+                        unsigned long long data_offset)
 {
        struct mdp_superblock_1 *super = st->sb;
        int bmspace = 0;
+       int bbspace = 0;
        if (devsize < 24)
                return 0;
 
-       if (super == NULL)
-               /* creating:  allow suitable space for bitmap */
-               bmspace = choose_bm_space(devsize);
 #ifndef MDASSEMBLE
-       else if (__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) {
+       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)+MAX_SB_SIZE);
@@ -2008,19 +1963,20 @@ static __u64 _avail_size1(struct supertype *st, __u64 devsize,
        }
 #endif
        /* Allow space for bad block log */
-       if (super && super->bblog_size)
-               devsize -= __le16_to_cpu(super->bblog_size);
-       else
-               devsize -= 8;
+       if (super->bblog_size)
+               bbspace = __le16_to_cpu(super->bblog_size);
 
        if (st->minor_version < 0)
                /* not specified, so time to set default */
                st->minor_version = 2;
 
+       if (data_offset == INVALID_SECTORS)
+               data_offset = st->data_offset;
+
        if (data_offset != INVALID_SECTORS)
                switch(st->minor_version) {
                case 0:
-                       return devsize - data_offset - 8*2;
+                       return devsize - data_offset - 8*2 - bbspace;
                case 1:
                case 2:
                        return devsize - data_offset;
@@ -2030,36 +1986,19 @@ static __u64 _avail_size1(struct supertype *st, __u64 devsize,
 
        devsize -= bmspace;
 
-       if (super == NULL && st->minor_version > 0) {
-               /* haven't committed to a size yet, so allow some
-                * slack for space for reshape.
-                * Limit slack to 128M, but aim for about 0.1%
-                */
-               unsigned long long headroom = 128*1024*2;
-               while ((headroom << 10) > devsize &&
-                      (chunksize == 0 ||
-                       headroom / 2 >= ((unsigned)chunksize*2)*2))
-                       headroom >>= 1;
-               devsize -= headroom;
-       }
        switch(st->minor_version) {
        case 0:
                /* at end */
-               return ((devsize - 8*2 ) & ~(4*2-1));
+               return ((devsize - 8*2 - bbspace ) & ~(4*2-1));
        case 1:
                /* at start, 4K for superblock and possible bitmap */
-               return devsize - 4*2;
+               return devsize - 4*2 - bbspace;
        case 2:
                /* 4k from start, 4K for superblock and possible bitmap */
-               return devsize - (4+4)*2;
+               return devsize - (4+4)*2 - bbspace;
        }
        return 0;
 }
-static __u64 avail_size1(struct supertype *st, __u64 devsize,
-                        unsigned long long data_offset)
-{
-       return _avail_size1(st, devsize, data_offset, 0);
-}
 
 static int
 add_internal_bitmap1(struct supertype *st,
@@ -2101,8 +2040,8 @@ add_internal_bitmap1(struct supertype *st,
                         * been left.
                         */
                        offset = 0;
-                       room = choose_bm_space(__le64_to_cpu(sb->size));
                        bbl_size = 8;
+                       room = choose_bm_space(__le64_to_cpu(sb->size)) + bbl_size;
                } else {
                        room = __le64_to_cpu(sb->super_offset)
                                - __le64_to_cpu(sb->data_offset)
@@ -2115,7 +2054,7 @@ add_internal_bitmap1(struct supertype *st,
                                bbl_size = -bbl_offset;
 
                        if (!may_change || (room < 3*2 &&
-                                 __le32_to_cpu(sb->max_dev) <= 384)) {
+                                           __le32_to_cpu(sb->max_dev) <= 384)) {
                                room = 3*2;
                                offset = 1*2;
                                bbl_size = 0;
@@ -2128,8 +2067,8 @@ add_internal_bitmap1(struct supertype *st,
        case 2: /* between superblock and data */
                if (creating) {
                        offset = 4*2;
-                       room = choose_bm_space(__le64_to_cpu(sb->size));
                        bbl_size = 8;
+                       room = choose_bm_space(__le64_to_cpu(sb->size)) + bbl_size;
                } else {
                        room = __le64_to_cpu(sb->data_offset)
                                - __le64_to_cpu(sb->super_offset);
@@ -2158,6 +2097,10 @@ add_internal_bitmap1(struct supertype *st,
                /* Limit to 128K of bitmap when chunk size not requested */
                room = 128*2;
 
+       if (room <= 1)
+               /* No room for a bitmap */
+               return 0;
+
        max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
 
        min_chunk = 4096; /* sub-page chunks don't work yet.. */
@@ -2201,6 +2144,10 @@ add_internal_bitmap1(struct supertype *st,
        bms->daemon_sleep = __cpu_to_le32(delay);
        bms->sync_size = __cpu_to_le64(size);
        bms->write_behind = __cpu_to_le32(write_behind);
+       bms->nodes = __cpu_to_le32(st->nodes);
+       if (st->cluster_name)
+               strncpy((char *)bms->cluster_name,
+                       st->cluster_name, strlen(st->cluster_name));
 
        *chunkp = chunk;
        return 1;
@@ -2234,6 +2181,7 @@ static int write_bitmap1(struct supertype *st, int fd)
        void *buf;
        int towrite, n;
        struct align_fd afd;
+       unsigned int i = 0;
 
        init_afd(&afd, fd);
 
@@ -2242,27 +2190,41 @@ static int write_bitmap1(struct supertype *st, int fd)
        if (posix_memalign(&buf, 4096, 4096))
                return -ENOMEM;
 
-       memset(buf, 0xff, 4096);
-       memcpy(buf, (char *)bms, sizeof(bitmap_super_t));
-
-       towrite = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9);
-       towrite = (towrite+7) >> 3; /* bits to bytes */
-       towrite += sizeof(bitmap_super_t);
-       towrite = ROUND_UP(towrite, 512);
-       while (towrite > 0) {
-               n = towrite;
-               if (n > 4096)
-                       n = 4096;
-               n = awrite(&afd, buf, n);
-               if (n > 0)
-                       towrite -= n;
+       do {
+               /* Only the bitmap[0] should resync
+                * whole device on initial assembly
+                */
+               if (i)
+                       memset(buf, 0x00, 4096);
                else
+                       memset(buf, 0xff, 4096);
+               memcpy(buf, (char *)bms, sizeof(bitmap_super_t));
+
+               towrite = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9);
+               towrite = (towrite+7) >> 3; /* bits to bytes */
+               towrite += sizeof(bitmap_super_t);
+               /* we need the bitmaps to be at 4k boundary */
+               towrite = ROUND_UP(towrite, 4096);
+               while (towrite > 0) {
+                       n = towrite;
+                       if (n > 4096)
+                               n = 4096;
+                       n = awrite(&afd, buf, n);
+                       if (n > 0)
+                               towrite -= n;
+                       else
+                               break;
+                       if (i)
+                               memset(buf, 0x00, 4096);
+                       else
+                               memset(buf, 0xff, 4096);
+               }
+               fsync(fd);
+               if (towrite) {
+                       rv = -2;
                        break;
-               memset(buf, 0xff, 4096);
-       }
-       fsync(fd);
-       if (towrite)
-               rv = -2;
+               }
+       } while (++i < __le32_to_cpu(bms->nodes));
 
        free(buf);
        return rv;
@@ -2290,7 +2252,9 @@ static int validate_geometry1(struct supertype *st, int level,
                              char *subdev, unsigned long long *freesize,
                              int verbose)
 {
-       unsigned long long ldsize;
+       unsigned long long ldsize, devsize;
+       int bmspace;
+       unsigned long long headroom;
        int fd;
 
        if (level == LEVEL_CONTAINER) {
@@ -2298,12 +2262,16 @@ static int validate_geometry1(struct supertype *st, int level,
                        pr_err("1.x metadata does not support containers\n");
                return 0;
        }
-       if (chunk && *chunk == UnSet)
+       if (*chunk == UnSet)
                *chunk = DEFAULT_CHUNK;
 
        if (!subdev)
                return 1;
 
+       if (st->minor_version < 0)
+               /* not specified, so time to set default */
+               st->minor_version = 2;
+
        fd = open(subdev, O_RDONLY|O_EXCL, 0);
        if (fd < 0) {
                if (verbose)
@@ -2318,7 +2286,57 @@ static int validate_geometry1(struct supertype *st, int level,
        }
        close(fd);
 
-       *freesize = _avail_size1(st, ldsize >> 9, data_offset, *chunk);
+       devsize = ldsize >> 9;
+       if (devsize < 24) {
+               *freesize = 0;
+               return 0;
+       }
+
+       /* creating:  allow suitable space for bitmap */
+       bmspace = choose_bm_space(devsize);
+
+       if (data_offset == INVALID_SECTORS)
+               data_offset = st->data_offset;
+       if (data_offset == INVALID_SECTORS)
+               switch (st->minor_version) {
+               case 0:
+                       data_offset = 0;
+                       break;
+               case 1:
+               case 2:
+                       /* Choose data offset appropriate for this device
+                        * and use as default for whole array.
+                        * The data_offset must allow for bitmap space
+                        * and base metadata, should allow for some headroom
+                        * for reshape, and should be rounded to multiple
+                        * of 1M.
+                        * Headroom is limited to 128M, but aim for about 0.1%
+                        */
+                       headroom = 128*1024*2;
+                       while ((headroom << 10) > devsize &&
+                              (*chunk == 0 ||
+                               headroom / 2 >= ((unsigned)(*chunk)*2)*2))
+                               headroom >>= 1;
+                       data_offset = 12*2 + bmspace + headroom;
+                       #define ONE_MEG (2*1024)
+                       if (data_offset > ONE_MEG)
+                               data_offset = (data_offset / ONE_MEG) * ONE_MEG;
+                       break;
+               }
+       if (st->data_offset == INVALID_SECTORS)
+               st->data_offset = data_offset;
+       switch(st->minor_version) {
+       case 0: /* metadata at end.  Round down and subtract space to reserve */
+               devsize = (devsize & ~(4ULL*2-1));
+               /* space for metadata, bblog, bitmap */
+               devsize -= 8*2 + 8 + bmspace;
+               break;
+       case 1:
+       case 2:
+               devsize -= data_offset;
+               break;
+       }
+       *freesize = devsize;
        return 1;
 }
 #endif /* MDASSEMBLE */