summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-03-03 15:22:56 +1100
committerNeilBrown <neilb@suse.de>2010-03-03 15:22:56 +1100
commita380e2751efea7dfe8acf0b95419c65ccacfa7cf (patch)
tree95c63e7b06391723b16695a9e0fd155ce3b2e405
parentd1d3482b562369b0d32e4267c2e245a3371d1f10 (diff)
downloadmdadm-a380e2751efea7dfe8acf0b95419c65ccacfa7cf.tar.gz
mdadm-a380e2751efea7dfe8acf0b95419c65ccacfa7cf.tar.xz
mdadm-a380e2751efea7dfe8acf0b95419c65ccacfa7cf.zip
super1: encourage data alignment on 1Meg boundary
For 1.1 and 1.2 metadata where data_offset is not zero, it is important to align the data_offset to underlying block size. We don't currently have access to the particular device in avail_size so just try to force to a 1Meg boundary. Also default 1.x metadata to 1.2 as documented. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--super1.c52
1 files changed, 40 insertions, 12 deletions
diff --git a/super1.c b/super1.c
index 73f4149..f3be7ce 100644
--- a/super1.c
+++ b/super1.c
@@ -994,6 +994,8 @@ 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
+ * NOTE: result must be multiple of 4K else bad things happen
+ * on 4K-sector devices.
*/
if (devsize < 64*2) return 0;
if (devsize - 64*2 >= 200*1024*1024*2)
@@ -1011,6 +1013,7 @@ static int write_init_super1(struct supertype *st)
int rfd;
int rv = 0;
int bm_space;
+ unsigned long long reserved;
struct devinfo *di;
unsigned long long dsize, array_size;
long long sb_offset;
@@ -1088,16 +1091,23 @@ static int write_init_super1(struct supertype *st)
sb_offset &= ~(4*2-1);
sb->super_offset = __cpu_to_le64(sb_offset);
sb->data_offset = __cpu_to_le64(0);
- if (sb_offset - bm_space < array_size)
- bm_space = sb_offset - 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);
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);
+ reserved = bm_space + 4*2;
+ /* 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);
+ /* force 4K alignment */
+ reserved &= ~7ULL;
+
+ sb->data_offset = __cpu_to_le64(reserved);
+ sb->data_size = __cpu_to_le64(dsize - reserved);
break;
case 2:
sb_offset = 4*2;
@@ -1106,9 +1116,18 @@ static int write_init_super1(struct supertype *st)
> 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 );
+
+ reserved = bm_space + 4*2 + 4*2;
+ /* 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);
+ /* force 4K alignment */
+ reserved &= ~7ULL;
+
+ sb->data_offset = __cpu_to_le64(reserved);
+ sb->data_size = __cpu_to_le64(dsize - reserved);
break;
default:
return -EINVAL;
@@ -1400,10 +1419,19 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize)
}
#endif
+ if (st->minor_version < 0)
+ /* not specified, so time to set default */
+ st->minor_version = 2;
+ if (super == NULL && st->minor_version > 0) {
+ /* haven't committed to a size yet, so allow some
+ * slack for alignment of data_offset.
+ * We haven't access to device details so allow
+ * 1 Meg if bigger than 1Gig
+ */
+ if (devsize > 1024*1024*2)
+ devsize -= 1024*2;
+ }
switch(st->minor_version) {
- case -1: /* no specified. Now time to set default */
- st->minor_version = 0;
- /* FALL THROUGH */
case 0:
/* at end */
return ((devsize - 8*2 ) & ~(4*2-1));