From d9751e06a601b5576b1b9e2c8126584083110ca5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 15 May 2012 09:51:03 +1000 Subject: [PATCH] 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 Signed-off-by: NeilBrown --- super1.c | 31 ++++++++++++++++--------------- 1 files changed, 16 insertions(+), 15 deletions(-) diff --git a/super1.c b/super1.c index be77c33..4f20cc3 100644 --- a/super1.c +++ b/super1.c @@ -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)) -- 1.7.7.6