summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-05-12 15:25:55 +1000
committerNeilBrown <neilb@suse.de>2009-05-12 15:25:55 +1000
commitc8b4de0cccfba18818416f62687e4094a5b83922 (patch)
treec433c9be537b65ddbdff135cd25824a7cc09cdc8
parentc7b474474c793e9a82bd0d84868fdf7367c89696 (diff)
downloadmdadm-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.c11
-rw-r--r--Grow.c2
-rw-r--r--Kill.c2
-rw-r--r--Manage.c2
-rw-r--r--ReadMe.c1
-rw-r--r--mdadm.c25
-rw-r--r--mdadm.h10
-rw-r--r--super0.c17
-rw-r--r--super1.c130
9 files changed, 144 insertions, 56 deletions
diff --git a/Create.c b/Create.c
index 9e65d0a..385d9a9 100644
--- 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 a8194bf..f9e6804 100644
--- 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 b1e19b5..d58203e 100644
--- 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",
diff --git a/Manage.c b/Manage.c
index fa4bb60..3b3b96e 100644
--- 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);
diff --git a/ReadMe.c b/ReadMe.c
index 818be0a..ca8c5a8 100644
--- 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 e889b9c..166ea9d 100644
--- 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 0eb8f39..d55daa9 100644
--- 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);
diff --git a/super0.c b/super0.c
index ebba534..c94c941 100644
--- 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);
diff --git a/super1.c b/super1.c
index 376b97d..cc4bdb3 100644
--- 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;