diff options
author | NeilBrown <neilb@suse.de> | 2009-05-12 15:25:55 +1000 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-05-12 15:25:55 +1000 |
commit | c8b4de0cccfba18818416f62687e4094a5b83922 (patch) | |
tree | c433c9be537b65ddbdff135cd25824a7cc09cdc8 | |
parent | c7b474474c793e9a82bd0d84868fdf7367c89696 (diff) | |
download | mdadm-2.tar.gz |
Create: add --reserve-space support to reserve space at the start of each devicemdadm-2
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>
-rw-r--r-- | Create.c | 11 | ||||
-rw-r--r-- | Grow.c | 2 | ||||
-rw-r--r-- | Kill.c | 2 | ||||
-rw-r--r-- | Manage.c | 2 | ||||
-rw-r--r-- | ReadMe.c | 1 | ||||
-rw-r--r-- | mdadm.c | 25 | ||||
-rw-r--r-- | mdadm.h | 10 | ||||
-rw-r--r-- | super0.c | 17 | ||||
-rw-r--r-- | super1.c | 130 |
9 files changed, 144 insertions, 56 deletions
@@ -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) { @@ -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; } @@ -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", @@ -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); @@ -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'}, @@ -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') { @@ -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); @@ -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); @@ -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; |