diff options
author | NeilBrown <neilb@suse.de> | 2012-05-15 09:51:03 +1000 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2012-05-15 09:51:03 +1000 |
commit | d9751e06a601b5576b1b9e2c8126584083110ca5 (patch) | |
tree | af25fa11f8041eea8e172acf0eb14db65adcdbd5 | |
parent | 9f9a7d034f04a786665cff5b4dd6a8f963a3fabb (diff) | |
download | mdadm-d9751e06a601b5576b1b9e2c8126584083110ca5.tar.gz |
super1: fix choice of data_offset.
While it is nice to set a high data_offset to leave plenty of head
room it is much more important to leave enough space to allow
of the data of the array.
So after we check that sb->size is still available, only reduce the
'reserved', don't increase it.
This fixes a bug where --adding a spare fails because it does not have
enough space in it.
Reported-by: nowhere <nowhere@hakkenden.ath.cx>
Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r-- | super1.c | 31 |
1 files changed, 16 insertions, 15 deletions
@@ -1189,40 +1189,42 @@ static int write_init_super1(struct supertype *st) case 1: sb->super_offset = __cpu_to_le64(0); reserved = bm_space + 4*2; + if (reserved < headroom) + reserved = headroom; + if (reserved + array_size > dsize) + reserved = dsize - array_size; /* Try for multiple of 1Meg so it is nicely aligned */ #define ONE_MEG (2*1024) - reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG; - if (reserved + __le64_to_cpu(sb->size) > dsize) - reserved = dsize - __le64_to_cpu(sb->size); + if (reserved > ONE_MEG) + reserved = (reserved/ONE_MEG) * ONE_MEG; + /* force 4K alignment */ reserved &= ~7ULL; - if (reserved < headroom) - reserved = headroom; - sb->data_offset = __cpu_to_le64(reserved); sb->data_size = __cpu_to_le64(dsize - reserved); 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) + if (4*2 + 4*2 + bm_space + array_size > dsize) - bm_space = dsize - __le64_to_cpu(sb->size) + bm_space = dsize - array_size - 4*2 - 4*2; reserved = bm_space + 4*2 + 4*2; + if (reserved < headroom) + reserved = headroom; + if (reserved + array_size > dsize) + reserved = dsize - array_size; /* Try for multiple of 1Meg so it is nicely aligned */ #define ONE_MEG (2*1024) - reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG; - if (reserved + __le64_to_cpu(sb->size) > dsize) - reserved = dsize - __le64_to_cpu(sb->size); + if (reserved > ONE_MEG) + reserved = (reserved/ONE_MEG) * ONE_MEG; + /* force 4K alignment */ reserved &= ~7ULL; - if (reserved < headroom) - reserved = headroom; - sb->data_offset = __cpu_to_le64(reserved); sb->data_size = __cpu_to_le64(dsize - reserved); break; @@ -1234,7 +1236,6 @@ static int write_init_super1(struct supertype *st) goto out; } - sb->sb_csum = calc_sb_1_csum(sb); rv = store_super1(st, di->fd); if (rv == 0 && (__le32_to_cpu(sb->feature_map) & 1)) |