super1: ensure bitmap doesn't overlap bad block log.

If a bad block log already exists when adding a bitmap,
make sure the bitmap stays before the log.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
NeilBrown 2012-10-03 17:07:20 +10:00
parent 688e99a77d
commit 88af981fa5
1 changed files with 25 additions and 1 deletions

View File

@ -1617,6 +1617,11 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
devsize -= bitmap_sectors(bsb);
}
#endif
/* Allow space for bad block log */
if (super && super->bblog_size)
devsize -= __le16_to_cpu(super->bblog_size);
else
devsize -= 8;
if (st->minor_version < 0)
/* not specified, so time to set default */
@ -1664,6 +1669,7 @@ add_internal_bitmap1(struct supertype *st,
unsigned long long max_bits;
unsigned long long min_chunk;
long offset;
long bbl_offset, bbl_size;
unsigned long long chunk = *chunkp;
int room = 0;
int creating = 0;
@ -1671,6 +1677,7 @@ add_internal_bitmap1(struct supertype *st,
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
int uuid[4];
if (__le64_to_cpu(sb->data_size) == 0)
/* Must be creating the array, else data_size would be non-zero */
creating = 1;
@ -1685,15 +1692,23 @@ add_internal_bitmap1(struct supertype *st,
*/
offset = 0;
room = choose_bm_space(__le64_to_cpu(sb->size));
bbl_size = 8;
} else {
room = __le64_to_cpu(sb->super_offset)
- __le64_to_cpu(sb->data_offset)
- __le64_to_cpu(sb->data_size);
bbl_size = __le16_to_cpu(sb->bblog_size);
if (bbl_size < 8)
bbl_size = 8;
bbl_offset = (__s32)__le32_to_cpu(sb->bblog_offset);
if (bbl_size < -bbl_offset)
bbl_size = -bbl_offset;
if (!may_change || (room < 3*2 &&
__le32_to_cpu(sb->max_dev) <= 384)) {
room = 3*2;
offset = 1*2;
bbl_size = 0;
} else {
offset = 0; /* means movable offset */
}
@ -1704,12 +1719,20 @@ add_internal_bitmap1(struct supertype *st,
if (creating) {
offset = 4*2;
room = choose_bm_space(__le64_to_cpu(sb->size));
bbl_size = 8;
} else {
room = __le64_to_cpu(sb->data_offset)
- __le64_to_cpu(sb->super_offset);
bbl_size = __le16_to_cpu(sb->bblog_size);
if (bbl_size)
room = __le32_to_cpu(sb->bblog_offset) + bbl_size;
else
bbl_size = 8;
if (!may_change) {
room -= 2; /* Leave 1K for superblock */
offset = 2;
bbl_size = 0;
} else {
room -= 4*2; /* leave 4K for superblock */
offset = 4*2;
@ -1720,6 +1743,7 @@ add_internal_bitmap1(struct supertype *st,
return 0;
}
room -= bbl_size;
if (chunk == UnSet && room > 128*2)
/* Limit to 128K of bitmap when chunk size not requested */
room = 128*2;
@ -1751,7 +1775,7 @@ add_internal_bitmap1(struct supertype *st,
bits = (size*512) / chunk + 1;
room = ((bits+7)/8 + sizeof(bitmap_super_t) +4095)/4096;
room *= 8; /* convert 4K blocks to sectors */
offset = -room;
offset = -room - bbl_size;
}
sb->bitmap_offset = (int32_t)__cpu_to_le32(offset);