]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Create: add --reserve-space support to reserve space at the start of each device mdadm-2
authorNeilBrown <neilb@suse.de>
Tue, 12 May 2009 05:25:55 +0000 (15:25 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 12 May 2009 05:25:55 +0000 (15:25 +1000)
This only works for 1.x metadata.
The idea is to reserve some space at the start of each device for
storing a boot loader.
As a boot loader will need sector 0, metadata 1.1 doesn't make sense.

The number given to reserve-space will be in kilobytes, though a
suffix of M can give Megabytes (or G gigabytes, but 2 is the limit).

When a spare is added to an array, we preserve the amount of reserved
space.

It is not yet possible to hot-add an internal bitmap to a 1.1 or 1.2
array with reserved space.

This option is not yet documented.

In future, we might copy the content of the reserved space from one
drive to any new spare that is added.

Signed-off-by: NeilBrown <neilb@suse.de>
Create.c
Grow.c
Kill.c
Manage.c
ReadMe.c
mdadm.c
mdadm.h
super0.c
super1.c

index 9e65d0a9f6516d125cfb5f1c96efb7106a678f46..385d9a98d2aba31ffa3542b5c160a9ea4d97c00a 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -37,7 +37,8 @@ int Create(struct supertype *st, char *mddev, int mdfd,
           char *name, char *homehost, int *uuid,
           int subdevs, mddev_dev_t devlist,
           int runstop, int verbose, int force, int assume_clean,
-          char *bitmap_file, int bitmap_chunk, int write_behind, int delay)
+          char *bitmap_file, int bitmap_chunk, int write_behind, int delay,
+          unsigned long reserve_space)
 {
        /*
         * Create a new raid array.
@@ -235,7 +236,8 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                         */
                        int i;
                        char *name = "default";
-                       if (level >= 1 && ldsize > (0x7fffffffULL<<10))
+                       if (reserve_space ||
+                           (level >= 1 && ldsize > (0x7fffffffULL<<10)))
                                name = "default/large";
                        for(i=0; !st && superlist[i]; i++)
                                st = superlist[i]->match_metadata_desc(name);
@@ -251,7 +253,7 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                                        st->ss->major,
                                        st->minor_version);
                }
-               freesize = st->ss->avail_size(st, ldsize >> 9);
+               freesize = st->ss->avail_size(st, ldsize >> 9, reserve_space);
                if (freesize == 0) {
                        fprintf(stderr, Name ": %s is too small: %luK\n",
                                dname, (unsigned long)(ldsize>>10));
@@ -450,7 +452,8 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                                name += 2;
                }
        }
-       if (!st->ss->init_super(st, &info.array, size, name, homehost, uuid))
+       if (!st->ss->init_super(st, &info.array, size, name, homehost, 
+                               uuid, reserve_space))
                return 1;
 
        if (bitmap_file && vers < 9003) {
diff --git a/Grow.c b/Grow.c
index a8194bf05b69e3e86b5eefcc88241bdb837ea398..f9e6804219a3a651edbe7234fdcaedfff90bacb1 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -312,7 +312,7 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
                                                )
                                                st->ss->write_bitmap(st, fd2);
                                        else {
-                                               fprintf(stderr, Name ": failed to create internal bitmap - chunksize problem.\n");
+                                               fprintf(stderr, Name ": failed to create internal bitmap.\n");
                                                close(fd2);
                                                return 1;
                                        }
diff --git a/Kill.c b/Kill.c
index b1e19b56dd8bbdb57d7b4ac9268c8656fff5d0d5..d58203ec7b1b307682c2af9239e38ff977974fc1 100644 (file)
--- a/Kill.c
+++ b/Kill.c
@@ -66,7 +66,7 @@ int Kill(char *dev, int force, int quiet)
                mdu_array_info_t info;
                info.major_version = -1; /* zero superblock */
                st->ss->free_super(st);
-               st->ss->init_super(st, &info, 0, "", NULL, NULL);
+               st->ss->init_super(st, &info, 0, "", NULL, NULL, 0);
                if (st->ss->store_super(st, fd)) {
                        if (!quiet)
                                fprintf(stderr, Name ": Could not zero superblock on %s\n",
index fa4bb60fc4c1df662f75b8799f5abf3cd0418423..3b3b96e3f1dcafa794104193748e1da92d550072 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -384,7 +384,7 @@ int Manage_subdevs(char *devname, int fd,
                                }
 
                                /* Make sure device is large enough */
-                               if (tst->ss->avail_size(tst, ldsize/512) <
+                               if (tst->ss->avail_size(tst, ldsize/512, 0) <
                                    array_size) {
                                        fprintf(stderr, Name ": %s not large enough to join array\n",
                                                dv->devname);
index 818be0adf9bc9dd64d041d8bbedd1b3d41b69032..ca8c5a8a8b8ac71e5cd6edc354bf3959005f9da8 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -140,6 +140,7 @@ struct option long_options[] = {
     {"homehost",  1, 0,  HomeHost},
     {"auto-update-homehost", 0, 0, AutoHomeHost},
     {"symlinks",  1, 0,  Symlinks},
+    {"reserve-space", 1, 0, ReserveSpace},
 
     /* For assemble */
     {"uuid",      1, 0, 'u'},
diff --git a/mdadm.c b/mdadm.c
index e889b9c2714fcbf17b0409dd3bd7183e130ea2e4..166ea9d6cda99c0ae9abf87493194e708b7a38a0 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -46,6 +46,7 @@ int main(int argc, char *argv[])
 
        int chunk = 0;
        long long size = -1;
+       unsigned long reserve_space = 0;
        int level = UnSet;
        int layout = UnSet;
        int raiddisks = 0;
@@ -862,6 +863,27 @@ int main(int argc, char *argv[])
                case O(INCREMENTAL, 'r'):
                        rebuild_map = 1;
                        continue;
+
+               case O(CREATE, ReserveSpace):
+                       reserve_space = strtoul(optarg, &c, 10)*2;
+                       if (reserve_space > 0) {
+                               switch (*c++) {
+                               default: c--; break;
+                               case 'K': break;
+                               case 'M':
+                                       reserve_space <<= 10;
+                                       break;
+                               case 'G':
+                                       reserve_space <<= 20;
+                                       break;
+                               }
+                       }
+                       if (reserve_space == 0 || *c) {
+                               fprintf(stderr, Name ": Invalid value for reserve-space: %s\n",
+                                       optarg);
+                               exit(2);
+                       }
+                       continue;
                }
                /* We have now processed all the valid options. Anything else is
                 * an error
@@ -1182,7 +1204,8 @@ int main(int argc, char *argv[])
                            raiddisks, sparedisks, ident.name, homehost,
                            ident.uuid_set ? ident.uuid : NULL,
                            devs_found-1, devlist->next, runstop, verbose-quiet, force, assume_clean,
-                           bitmap_file, bitmap_chunk, write_behind, delay);
+                           bitmap_file, bitmap_chunk, write_behind, delay,
+                           reserve_space);
                break;
        case MISC:
                if (devmode == 'E') {
diff --git a/mdadm.h b/mdadm.h
index 0eb8f399a3ed738e271d3a0ae2879fe84e305218..d55daa93cbba65e7417ce73495dd7a55956f3e59 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -189,6 +189,7 @@ enum special_options {
        AutoHomeHost,
        Symlinks,
        AutoDetect,
+       ReserveSpace,
 };
 
 /* structures read from config file */
@@ -343,7 +344,8 @@ extern struct superswitch {
                            int uuid_set, char *homehost);
        int (*init_super)(struct supertype *st, mdu_array_info_t *info,
                          unsigned long long size, char *name,
-                         char *homehost, int *uuid);
+                         char *homehost, int *uuid,
+                         unsigned long reserve_space);
        void (*add_to_super)(struct supertype *st, mdu_disk_info_t *dinfo);
        int (*store_super)(struct supertype *st, int fd);
        int (*write_init_super)(struct supertype *st, mdu_disk_info_t *dinfo,
@@ -351,7 +353,8 @@ extern struct superswitch {
        int (*compare_super)(struct supertype *st, struct supertype *tst);
        int (*load_super)(struct supertype *st, int fd, char *devname);
        struct supertype * (*match_metadata_desc)(char *arg);
-       __u64 (*avail_size)(struct supertype *st, __u64 size);
+       __u64 (*avail_size)(struct supertype *st, __u64 size,
+                           unsigned long reserve_space);
        int (*add_internal_bitmap)(struct supertype *st, int *chunkp,
                                   int delay, int write_behind,
                                   unsigned long long size, int may_change, int major);
@@ -452,7 +455,8 @@ extern int Create(struct supertype *st, char *mddev, int mdfd,
                  char *name, char *homehost, int *uuid,
                  int subdevs, mddev_dev_t devlist,
                  int runstop, int verbose, int force, int assume_clean,
-                 char *bitmap_file, int bitmap_chunk, int write_behind, int delay);
+                 char *bitmap_file, int bitmap_chunk, int write_behind, int delay,
+                 unsigned long reserve_space);
 
 extern int Detail(char *dev, int brief, int export, int test, char *homehost);
 extern int Query(char *dev);
index ebba5341d2e1f7e21a32b0b2761f2a6d4b882d9a..c94c9417cb1f705110b2c3dda83ab4b5680a6928 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -549,13 +549,20 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
 
 static int init_super0(struct supertype *st, mdu_array_info_t *info,
                       unsigned long long size, char *ignored_name, char *homehost,
-                      int *uuid)
+                      int *uuid, unsigned long reserve_space)
 {
        mdp_super_t *sb = malloc(MD_SB_BYTES + sizeof(bitmap_super_t));
        int spares;
        memset(sb, 0, MD_SB_BYTES + sizeof(bitmap_super_t));
 
        st->sb = sb;
+       if (reserve_space) {
+               /* impossible - should already have been caught
+                * by avail_size
+                */
+               return 0;
+       }
+
        if (info->major_version == -1) {
                /* zeroing the superblock */
                return 0;
@@ -869,8 +876,14 @@ static struct supertype *match_metadata_desc0(char *arg)
        return NULL;
 }
 
-static __u64 avail_size0(struct supertype *st, __u64 devsize)
+static __u64 avail_size0(struct supertype *st, __u64 devsize,
+                        unsigned long reserve_space)
 {
+       if (reserve_space) {
+               fprintf(stderr, Name ": --reserve-space is not supported v0.90 metadata.\n"
+                       "        use e.g. --metadata=1.0\n");
+               return 0ULL;
+       }
        if (devsize < MD_RESERVED_SECTORS)
                return 0ULL;
        return MD_NEW_SIZE_SECTORS(devsize);
index 376b97d9a4a4e855f2eabfe6583f48ac9c11a6c3..cc4bdb335f881596caee8d468a38e717fbd65ebc 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -700,13 +700,28 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
        return rv;
 }
 
+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
+        */
+       if (devsize < 64*2) return 0;
+       if (devsize - 64*2 >= 200*1024*1024*2)
+               return 128*2;
+       if (devsize - 4*2 > 8*1024*1024*2)
+               return 64*2;
+       return 4*2;
+}
+
 static int init_super1(struct supertype *st, mdu_array_info_t *info,
-                      unsigned long long size, char *name, char *homehost, int *uuid)
+                      unsigned long long size, char *name, char *homehost,
+                      int *uuid, unsigned long reserve_space)
 {
        struct mdp_superblock_1 *sb = malloc(1024 + sizeof(bitmap_super_t) +
                                             sizeof(struct misc_dev_info));
        int spares;
        int rfd;
+       int bm_space;
        char defname[10];
        memset(sb, 0, 1024);
 
@@ -760,11 +775,31 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
        sb->chunksize = __cpu_to_le32(info->chunk_size>>9);
        sb->raid_disks = __cpu_to_le32(info->raid_disks);
 
-       sb->data_offset = __cpu_to_le64(0);
-       sb->data_size = __cpu_to_le64(0);
+               sb->data_size = __cpu_to_le64(0);
        sb->super_offset = __cpu_to_le64(0);
        sb->recovery_offset = __cpu_to_le64(0);
 
+       bm_space = choose_bm_space(size*2);
+
+       switch(st->minor_version) {
+       case 0:
+               sb->data_offset = __cpu_to_le64(reserve_space);
+               sb->bitmap_offset = __cpu_to_le32(0);
+               break;
+       case 1:
+               sb->super_offset = __cpu_to_le64(0);
+               sb->data_offset = __cpu_to_le64(4*2 +
+                                               reserve_space + bm_space);
+               sb->bitmap_offset = __cpu_to_le32(reserve_space + 4*2);
+               break;
+       case 2:
+               sb->super_offset = __cpu_to_le64(4*2);
+               sb->data_offset = __cpu_to_le64(4*2 + 4*2 +
+                                               reserve_space + bm_space);
+               sb->bitmap_offset = __cpu_to_le32(reserve_space + 4*2);
+               break;
+       }
+
        sb->utime = sb->ctime;
        sb->events = __cpu_to_le64(1);
        if (info->state & (1<<MD_SB_CLEAN))
@@ -869,19 +904,6 @@ static int store_super1(struct supertype *st, int fd)
 
 static int load_super1(struct supertype *st, int fd, char *devname);
 
-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
-        */
-       if (devsize < 64*2) return 0;
-       if (devsize - 64*2 >= 200*1024*1024*2)
-               return 128*2;
-       if (devsize - 4*2 > 8*1024*1024*2)
-               return 64*2;
-       return 4*2;
-}
-
 static int write_init_super1(struct supertype *st,
                             mdu_disk_info_t *dinfo, char *devname)
 {
@@ -953,9 +975,6 @@ static int write_init_super1(struct supertype *st,
         * Depending on the array size, we might leave extra space
         * for a bitmap.
         */
-       array_size = __le64_to_cpu(sb->size);
-       /* work out how much space we left for a bitmap */
-       bm_space = choose_bm_space(array_size);
 
        switch(st->minor_version) {
        case 0:
@@ -963,25 +982,24 @@ static int write_init_super1(struct supertype *st,
                sb_offset -= 8*2;
                sb_offset &= ~(4*2-1);
                sb->super_offset = __cpu_to_le64(sb_offset);
-               sb->data_offset = __cpu_to_le64(0);
+
+               array_size = __le64_to_cpu(sb->size);
+               /* work out how much space we left for a bitmap */
+               bm_space = choose_bm_space(array_size);
                if (sb_offset - bm_space < array_size)
                        bm_space = sb_offset - array_size;
-               sb->data_size = __cpu_to_le64(sb_offset - bm_space);
+               sb->data_size = __cpu_to_le64(sb_offset - bm_space -
+                                             __le64_to_cpu(sb->data_offset));
                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);
+               sb_offset = 0;
+               sb->data_size = __cpu_to_le64(dsize -
+                                             __le64_to_cpu(sb->data_offset));
                break;
        case 2:
                sb_offset = 4*2;
-               sb->super_offset = __cpu_to_le64(4*2);
-               if (4*2 + 4*2 + bm_space + __le64_to_cpu(sb->size) > 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 );
+               sb->data_size = __cpu_to_le64(dsize -
+                                             __le64_to_cpu(sb->data_offset));
                break;
        default:
                return -EINVAL;
@@ -1233,7 +1251,8 @@ 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)
+static __u64 avail_size1(struct supertype *st, __u64 devsize,
+                        unsigned long reserve_space)
 {
        struct mdp_superblock_1 *super = st->sb;
        if (devsize < 24)
@@ -1257,13 +1276,19 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
                /* FALL THROUGH */
        case 0:
                /* at end */
-               return ((devsize - 8*2 ) & ~(4*2-1));
+               if (reserve_space == 0 && super)
+                       reserve_space = __le64_to_cpu(super->data_offset);
+               return ((devsize - 8*2 ) & ~(4*2-1)) - reserve_space;
        case 1:
                /* at start, 4K for superblock and possible bitmap */
-               return devsize - 4*2;
+               if (reserve_space == 0 && super)
+                       return devsize - __le64_to_cpu(super->data_offset);
+               return devsize - 4*2 - reserve_space;
        case 2:
                /* 4k from start, 4K for superblock and possible bitmap */
-               return devsize - (4+4)*2;
+               if (reserve_space == 0 && super)
+                       return devsize - __le64_to_cpu(super->data_offset);
+               return devsize - (4+4)*2 - reserve_space;
        }
        return 0;
 }
@@ -1327,17 +1352,36 @@ add_internal_bitmap1(struct supertype *st,
        case 1:
        case 2: /* between superblock and data */
                if (may_change) {
-                       offset = 4*2;
+                       int room2;
+                       /* init_super already set this up */
+                       offset = __le32_to_cpu(sb->bitmap_offset);
+                       if (offset == 0)
+                               offset = 4*2;
                        room = choose_bm_space(__le64_to_cpu(sb->size));
+                       room2 = __le64_to_cpu(sb->data_offset) - offset;
+                       if (room > room2)
+                               room = room2;
+                               
                } 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;
-                               offset = 2;
+                       if (__le32_to_cpu(sb->bitmap_offset) < 4*2) {
+                               room = __le64_to_cpu(sb->data_offset)
+                                       - __le64_to_cpu(sb->super_offset);
+
+                               if (1 || __le32_to_cpu(sb->max_dev) <= 384) {
+                                       room -= 2;
+                                       offset = 2;
+                               } else {
+                                       room -= 4*2;
+                                       offset = 4*2;
+                               }
                        } else {
-                               room -= 4*2;
-                               offset = 4*2;
+                               room = __le64_to_cpu(sb->data_offset) -
+                                       __le32_to_cpu(sb->bitmap_offset);
+                               offset = __le32_to_cpu(sb->bitmap_offset);
+                               fprintf(stderr, Name ": adding internal bitmaps "
+                                       "to array with a reserved offset is not "
+                                       "yet supported, sorry.\n");
+                               return 0;
                        }
                }
                break;