]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
super1: fix choice of data_offset.
authorNeilBrown <neilb@suse.de>
Mon, 14 May 2012 23:51:03 +0000 (09:51 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 14 May 2012 23:51:03 +0000 (09:51 +1000)
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>
super1.c

index be77c330cc789034e97c60a45ea8d25f026ae685..4f20cc3ddc29b67bf631bc4dae4e608bf44074c1 100644 (file)
--- 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))