summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2006-12-14 17:31:00 +1100
committerNeil Brown <neilb@suse.de>2006-12-14 17:31:00 +1100
commit199171a297a87d7696b6b8c07ee520363f4603c1 (patch)
treec14892a4cca18dd1dd01539a3c39f91f28045228
parent90cf1dddb25f047494b943cf2dd67ebffd42ed05 (diff)
downloadmdadm-199171a297a87d7696b6b8c07ee520363f4603c1.tar.gz
mdadm-199171a297a87d7696b6b8c07ee520363f4603c1.tar.xz
mdadm-199171a297a87d7696b6b8c07ee520363f4603c1.zip
Improve allocation and use of space for bitmaps in version1 metadata
Depending on the size of the array we reserve space for up to 128K of bitmap, and we use it where possible. When hot-adding to a version 1.0 we can still only use the 3K at the end though - need a sysfs interface to improve that. If a small chunksize is requested on Create, we don't auto-enlarge the reserved space - this still needs to be fixed.
-rw-r--r--Create.c3
-rw-r--r--Grow.c8
-rw-r--r--mdadm.h3
-rw-r--r--super0.c8
-rw-r--r--super1.c126
5 files changed, 114 insertions, 34 deletions
diff --git a/Create.c b/Create.c
index e0cc797..cd4356c 100644
--- a/Create.c
+++ b/Create.c
@@ -435,7 +435,8 @@ int Create(struct supertype *st, char *mddev, int mdfd,
fprintf(stderr, Name ": internal bitmaps not supported by this kernel.\n");
return 1;
}
- if (!st->ss->add_internal_bitmap(st, super, bitmap_chunk, delay, write_behind,
+ if (!st->ss->add_internal_bitmap(st, super, &bitmap_chunk,
+ delay, write_behind,
bitmapsize, 1, major)) {
fprintf(stderr, Name ": Given bitmap chunk size not supported.\n");
return 1;
diff --git a/Grow.c b/Grow.c
index 1ab4fbc..2a13a71 100644
--- a/Grow.c
+++ b/Grow.c
@@ -305,9 +305,11 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
if (fd2 < 0)
continue;
if (st->ss->load_super(st, fd2, &super, NULL)==0) {
- if (st->ss->add_internal_bitmap(st, super,
- chunk, delay, write_behind,
- bitmapsize, 0, major))
+ if (st->ss->add_internal_bitmap(
+ st, super,
+ &chunk, delay, write_behind,
+ bitmapsize, 0, major)
+ )
st->ss->write_bitmap(st, fd2, super);
else {
fprintf(stderr, Name ": failed to create internal bitmap - chunksize problem.\n");
diff --git a/mdadm.h b/mdadm.h
index f8abf09..f6e7b5e 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -323,7 +323,8 @@ extern struct superswitch {
int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname);
struct supertype * (*match_metadata_desc)(char *arg);
__u64 (*avail_size)(struct supertype *st, __u64 size);
- int (*add_internal_bitmap)(struct supertype *st, void *sbv, int chunk, int delay, int write_behind,
+ int (*add_internal_bitmap)(struct supertype *st, void *sbv, int *chunkp,
+ int delay, int write_behind,
unsigned long long size, int may_change, int major);
void (*locate_bitmap)(struct supertype *st, int fd, void *sbv);
int (*write_bitmap)(struct supertype *st, int fd, void *sbv);
diff --git a/super0.c b/super0.c
index 600aae0..fbb7eb9 100644
--- a/super0.c
+++ b/super0.c
@@ -827,7 +827,10 @@ static __u64 avail_size0(struct supertype *st, __u64 devsize)
return MD_NEW_SIZE_SECTORS(devsize);
}
-static int add_internal_bitmap0(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size, int may_change, int major)
+static int add_internal_bitmap0(struct supertype *st, void *sbv, int *chunkp,
+ int delay, int write_behind,
+ unsigned long long size, int may_change,
+ int major)
{
/*
* The bitmap comes immediately after the superblock and must be 60K in size
@@ -838,6 +841,7 @@ static int add_internal_bitmap0(struct supertype *st, void *sbv, int chunk, int
unsigned long long bits;
unsigned long long max_bits = 60*1024*8;
unsigned long long min_chunk;
+ int chunk = *chunkp;
mdp_super_t *sb = sbv;
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MD_SB_BYTES);
@@ -863,7 +867,7 @@ static int add_internal_bitmap0(struct supertype *st, void *sbv, int chunk, int
bms->daemon_sleep = __cpu_to_le32(delay);
bms->sync_size = __cpu_to_le64(size);
bms->write_behind = __cpu_to_le32(write_behind);
-
+ *chunkp = chunk;
return 1;
}
diff --git a/super1.c b/super1.c
index c8a5702..7aa324f 100644
--- a/super1.c
+++ b/super1.c
@@ -193,9 +193,10 @@ static void examine_super1(void *sbv, char *homehost)
human_size(__le64_to_cpu(sb->size)<<9));
}
if (sb->data_offset)
- printf(" Data Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->data_offset));
- if (sb->super_offset)
- printf(" Super Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->super_offset));
+ printf(" Data Offset : %llu sectors\n",
+ (unsigned long long)__le64_to_cpu(sb->data_offset));
+ printf(" Super Offset : %llu sectors\n",
+ (unsigned long long)__le64_to_cpu(sb->super_offset));
if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_RECOVERY_OFFSET)
printf("Recovery Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->recovery_offset));
printf(" State : %s\n", (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean");
@@ -743,8 +744,9 @@ static int write_init_super1(struct supertype *st, void *sbv,
int fd = open(devname, O_RDWR | O_EXCL);
int rfd;
int rv;
+ int bm_space;
- unsigned long size, space;
+ unsigned long space;
unsigned long long dsize, array_size;
long long sb_offset;
@@ -789,6 +791,7 @@ static int write_init_super1(struct supertype *st, void *sbv,
if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
#endif
{
+ unsigned long size;
if (ioctl(fd, BLKGETSIZE, &size))
return 1;
else
@@ -813,6 +816,14 @@ static int write_init_super1(struct supertype *st, void *sbv,
* for a bitmap.
*/
array_size = __le64_to_cpu(sb->size);
+ /* work out how much space we left of a bitmap */
+ if (array_size >= 200*1024*1024*2)
+ bm_space = 128*2;
+ else if (array_size > 8*1024*1024*2)
+ bm_space = 64*2;
+ else
+ bm_space = 0;
+
switch(st->minor_version) {
case 0:
sb_offset = dsize;
@@ -820,19 +831,12 @@ static int write_init_super1(struct supertype *st, void *sbv,
sb_offset &= ~(4*2-1);
sb->super_offset = __cpu_to_le64(sb_offset);
sb->data_offset = __cpu_to_le64(0);
- if (sb_offset-64*2 >= array_size && array_size > 8*1024*1024*2)
- sb->data_size = __cpu_to_le64(sb_offset-64*2);
- else
- sb->data_size = __cpu_to_le64(sb_offset);
+ sb->data_size = __cpu_to_le64(sb_offset - bm_space);
break;
case 1:
sb->super_offset = __cpu_to_le64(0);
- if (dsize - 64*2 >= array_size && array_size > 8*1024*1024*2)
- space = 64*2;
- else
- space = 4*2;
- sb->data_offset = __cpu_to_le64(space); /* leave space for super and bitmap */
- sb->data_size = __cpu_to_le64(dsize - space);
+ sb->data_offset = __cpu_to_le64(bm_space + 4*2);
+ sb->data_size = __cpu_to_le64(dsize - bm_space - 4*2);
break;
case 2:
sb_offset = 4*2;
@@ -840,9 +844,9 @@ static int write_init_super1(struct supertype *st, void *sbv,
space = 64*2;
else
space = 4*2;
- sb->super_offset = __cpu_to_le64(sb_offset);
- sb->data_offset = __cpu_to_le64(sb_offset+space);
- sb->data_size = __cpu_to_le64(dsize - 4*2 - space);
+ sb->super_offset = __cpu_to_le64(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 );
break;
default:
return -EINVAL;
@@ -1088,11 +1092,11 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
return 0;
/* if the device is bigger than 8Gig, save 64k for bitmap usage,
- * if biffer than 200Gig, save 128k
+ * if bigger than 200Gig, save 128k
*/
- if (devsize > 200*1024*1024*2)
+ if (devsize-64*2 >= 200*1024*1024*2)
devsize -= 128*2;
- else if (devsize > 8*1024*1024*2)
+ else if (devsize >= 8*1024*1024*2)
devsize -= 64*2;
switch(st->minor_version) {
@@ -1111,7 +1115,8 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
static int
add_internal_bitmap1(struct supertype *st, void *sbv,
- int chunk, int delay, int write_behind, unsigned long long size,
+ int *chunkp, int delay, int write_behind,
+ unsigned long long size,
int may_change, int major)
{
/*
@@ -1119,22 +1124,82 @@ add_internal_bitmap1(struct supertype *st, void *sbv,
* 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.
- * For now, just squeeze the bitmap into 3k and don't change anything.
+ * If !may_change, the bitmap MUST live at offset of 1K, until
+ * we get a sysfs interface.
*
* size is in sectors, chunk is in bytes !!!
*/
unsigned long long bits;
- unsigned long long max_bits = (6*512 - sizeof(bitmap_super_t)) * 8;
+ unsigned long long max_bits;
unsigned long long min_chunk;
+ long offset;
+ int chunk = *chunkp;
+ int room;
struct mdp_superblock_1 *sb = sbv;
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
- if (st->minor_version && !may_change &&
- __le64_to_cpu(sb->data_offset) - __le64_to_cpu(sb->super_offset) < 8)
- return 0; /* doesn't fit */
+ switch(st->minor_version) {
+ case 0:
+ /* either 3K after the superblock, or some amount of space
+ * before.
+ */
+ if (may_change) {
+ /* We are creating array, so we *know* how much room has
+ * been left.
+ */
+ offset = 0;
+ if (__le64_to_cpu(sb->size) >= 200*1024*1024*2)
+ room = 128*2;
+ else if (__le64_to_cpu(sb->size) > 8*1024*1024*2)
+ room = 64*2;
+ else {
+ room = 3*2;
+ offset = 2;
+ }
+ } else {
+ 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 &&
+ __le32_to_cpu(sb->max_dev) <= 384)) {
+ room = 3*2;
+ offset = 1*2;
+ } else {
+ offset = 0; /* means movable offset */
+ }
+ }
+ break;
+ case 1:
+ case 2: /* between superblock and data */
+ if (may_change) {
+ offset = 4*2;
+ if (__le64_to_cpu(sb->size) >= 200*1024*1024*2)
+ room = 128*2;
+ else if (__le64_to_cpu(sb->size) > 8*1024*1024*2)
+ room = 64*2;
+ else
+ room = 3*2;
+ } 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;
+ } else {
+ room -= 4*2;
+ offset = 4*2;
+ }
+ }
+ break;
+ }
+ if (chunk == UnSet && room > 128*2)
+ /* Limit to 128K of bitmap when chunk size not requested */
+ room = 128*2;
+ max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
min_chunk = 4096; /* sub-page chunks don't work yet.. */
bits = (size*512)/min_chunk +1;
@@ -1149,7 +1214,13 @@ add_internal_bitmap1(struct supertype *st, void *sbv,
if (chunk == 0) /* rounding problem */
return 0;
- sb->bitmap_offset = __cpu_to_le32(2);
+ if (offset == 0) {
+ bits = (size*512) / chunk + 1;
+ room = ((bits+7)/8 + sizeof(bitmap_super_t) +511)/512;
+ offset = -room;
+ }
+
+ sb->bitmap_offset = __cpu_to_le32(offset);
sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
memset(bms, 0, sizeof(*bms));
@@ -1161,6 +1232,7 @@ add_internal_bitmap1(struct supertype *st, void *sbv,
bms->sync_size = __cpu_to_le64(size);
bms->write_behind = __cpu_to_le32(write_behind);
+ *chunkp = chunk;
return 1;
}