summaryrefslogtreecommitdiff
path: root/debian/patches/0007-imsm-do-not-use-blocks_per_member-in-array-size-calc.patch
blob: f0fc0c42768b78381396805214161424ec7e950f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
From 444909385fdaccf961308c4319d7029b82bf8bb1 Mon Sep 17 00:00:00 2001
From: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
Date: Thu, 5 Apr 2018 13:38:38 +0200
Subject: [PATCH 7/9] imsm: do not use blocks_per_member in array size
 calculations

mdadm assumes that blocks_per_member value is equal to num_data_stripes *
blocks_per_stripe but it is not true. For IMSM arrays created in OROM
NUM_BLOCKS_DIRTY_STRIPE_REGION sectors are added up to this value. Because
of this mdadm shows invalid size of arrays created in OROM and to fix this
we need to use array size calculation based on num data stripes and blocks
per stripe.

Signed-off-by: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 super-intel.c | 105 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 76 insertions(+), 29 deletions(-)

diff --git a/super-intel.c b/super-intel.c
index 3fc3cf4c..c55c85f1 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -1233,6 +1233,20 @@ static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
 	split_ull(n, &dev->size_low, &dev->size_high);
 }
 
+static unsigned long long per_dev_array_size(struct imsm_map *map)
+{
+	unsigned long long array_size = 0;
+
+	if (map == NULL)
+		return array_size;
+
+	array_size = num_data_stripes(map) * map->blocks_per_strip;
+	if (get_imsm_raid_level(map) == 1 || get_imsm_raid_level(map) == 10)
+		array_size *= 2;
+
+	return array_size;
+}
+
 static struct extent *get_extents(struct intel_super *super, struct dl *dl)
 {
 	/* find a list of used extents on the given physical device */
@@ -1259,7 +1273,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
 
 		if (get_imsm_disk_slot(map, dl->index) >= 0) {
 			e->start = pba_of_lba0(map);
-			e->size = blocks_per_member(map);
+			e->size = per_dev_array_size(map);
 			e++;
 		}
 	}
@@ -2787,6 +2801,36 @@ static __u8 imsm_num_data_members(struct imsm_map *map)
 	}
 }
 
+static unsigned long long calc_component_size(struct imsm_map *map,
+					      struct imsm_dev *dev)
+{
+	unsigned long long component_size;
+	unsigned long long dev_size = imsm_dev_size(dev);
+	unsigned long long calc_dev_size = 0;
+	unsigned int member_disks = imsm_num_data_members(map);
+
+	if (member_disks == 0)
+		return 0;
+
+	component_size = per_dev_array_size(map);
+	calc_dev_size = component_size * member_disks;
+
+	/* Component size is rounded to 1MB so difference between size from
+	 * metadata and size calculated from num_data_stripes equals up to
+	 * 2048 blocks per each device. If the difference is higher it means
+	 * that array size was expanded and num_data_stripes was not updated.
+	 */
+	if ((unsigned int)abs(calc_dev_size - dev_size) >
+	    (1 << SECT_PER_MB_SHIFT) * member_disks) {
+		component_size = dev_size / member_disks;
+		dprintf("Invalid num_data_stripes in metadata; expected=%llu, found=%llu\n",
+			component_size / map->blocks_per_strip,
+			num_data_stripes(map));
+	}
+
+	return component_size;
+}
+
 static __u32 parity_segment_depth(struct imsm_dev *dev)
 {
 	struct imsm_map *map = get_imsm_map(dev, MAP_0);
@@ -3306,14 +3350,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
 	}
 
 	info->data_offset	  = pba_of_lba0(map_to_analyse);
-
-	if (info->array.level == 5) {
-		info->component_size = num_data_stripes(map_to_analyse) *
-				       map_to_analyse->blocks_per_strip;
-	} else {
-		info->component_size = blocks_per_member(map_to_analyse);
-	}
-
+	info->component_size = calc_component_size(map, dev);
 	info->component_size = imsm_component_size_aligment_check(
 							info->array.level,
 							info->array.chunk_size,
@@ -3381,7 +3418,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
 
 			used_disks = imsm_num_data_members(prev_map);
 			if (used_disks > 0) {
-				array_blocks = blocks_per_member(map) *
+				array_blocks = per_dev_array_size(map) *
 					used_disks;
 				info->custom_array_size =
 					round_size_to_mb(array_blocks,
@@ -5383,9 +5420,6 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 	vol->curr_migr_unit = 0;
 	map = get_imsm_map(dev, MAP_0);
 	set_pba_of_lba0(map, super->create_offset);
-	set_blocks_per_member(map, info_to_blocks_per_member(info,
-							     size_per_member /
-							     BLOCKS_PER_KB));
 	map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
 	map->failed_disk_num = ~0;
 	if (info->level > 0)
@@ -5417,6 +5451,11 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 	num_data_stripes /= map->num_domains;
 	set_num_data_stripes(map, num_data_stripes);
 
+	size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
+	set_blocks_per_member(map, info_to_blocks_per_member(info,
+							     size_per_member /
+							     BLOCKS_PER_KB));
+
 	map->num_members = info->raid_disks;
 	for (i = 0; i < map->num_members; i++) {
 		/* initialized in add_to_super */
@@ -7821,18 +7860,14 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 
 			info_d->events = __le32_to_cpu(mpb->generation_num);
 			info_d->data_offset = pba_of_lba0(map);
+			info_d->component_size = calc_component_size(map, dev);
 
 			if (map->raid_level == 5) {
-				info_d->component_size =
-						num_data_stripes(map) *
-						map->blocks_per_strip;
 				info_d->ppl_sector = this->ppl_sector;
 				info_d->ppl_size = this->ppl_size;
 				if (this->consistency_policy == CONSISTENCY_POLICY_PPL &&
 				    recovery_start == 0)
 					this->resync_start = 0;
-			} else {
-				info_d->component_size = blocks_per_member(map);
 			}
 
 			info_d->bb.supported = 1;
@@ -8156,7 +8191,7 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
 	if (new_size <= 0)
 		/* OLCE size change is caused by added disks
 		 */
-		array_blocks = blocks_per_member(map) * used_disks;
+		array_blocks = per_dev_array_size(map) * used_disks;
 	else
 		/* Online Volume Size Change
 		 * Using  available free space
@@ -8273,7 +8308,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
 				used_disks = imsm_num_data_members(map);
 				if (used_disks > 0) {
 					array_blocks =
-						blocks_per_member(map) *
+						per_dev_array_size(map) *
 						used_disks;
 					array_blocks =
 						round_size_to_mb(array_blocks,
@@ -8715,11 +8750,11 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
 			pos = 0;
 			array_start = pba_of_lba0(map);
 			array_end = array_start +
-				    blocks_per_member(map) - 1;
+				    per_dev_array_size(map) - 1;
 
 			do {
 				/* check that we can start at pba_of_lba0 with
-				 * blocks_per_member of space
+				 * num_data_stripes*blocks_per_stripe of space
 				 */
 				if (array_start >= pos && array_end < ex[j].start) {
 					found = 1;
@@ -9145,6 +9180,12 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
 				set_num_data_stripes(map, num_data_stripes);
 			}
 
+			/* ensure blocks_per_member has valid value
+			 */
+			set_blocks_per_member(map,
+					      per_dev_array_size(map) +
+					      NUM_BLOCKS_DIRTY_STRIPE_REGION);
+
 			/* add disk
 			 */
 			if (u->new_level != 5 || migr_map->raid_level != 0 ||
@@ -9211,15 +9252,21 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
 			int used_disks = imsm_num_data_members(map);
 			unsigned long long blocks_per_member;
 			unsigned long long num_data_stripes;
+			unsigned long long new_size_per_disk;
+
+			if (used_disks == 0)
+				return 0;
 
 			/* calculate new size
 			 */
-			blocks_per_member = u->new_size / used_disks;
-			num_data_stripes = blocks_per_member /
+			new_size_per_disk = u->new_size / used_disks;
+			blocks_per_member = new_size_per_disk +
+					    NUM_BLOCKS_DIRTY_STRIPE_REGION;
+			num_data_stripes = new_size_per_disk /
 					   map->blocks_per_strip;
 			num_data_stripes /= map->num_domains;
 			dprintf("(size: %llu, blocks per member: %llu, num_data_stipes: %llu)\n",
-				u->new_size, blocks_per_member,
+				u->new_size, new_size_per_disk,
 				num_data_stripes);
 			set_blocks_per_member(map, blocks_per_member);
 			set_num_data_stripes(map, num_data_stripes);
@@ -9476,7 +9523,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
 		unsigned long long num_data_stripes;
 
 		map->num_domains = 1;
-		num_data_stripes = blocks_per_member(map);
+		num_data_stripes = imsm_dev_size(dev) / 2;
 		num_data_stripes /= map->blocks_per_strip;
 		num_data_stripes /= map->num_domains;
 		set_num_data_stripes(map, num_data_stripes);
@@ -9692,7 +9739,7 @@ static void imsm_process_update(struct supertype *st,
 
 		new_map = get_imsm_map(&u->dev, MAP_0);
 		new_start = pba_of_lba0(new_map);
-		new_end = new_start + blocks_per_member(new_map);
+		new_end = new_start + per_dev_array_size(new_map);
 		inf = get_disk_info(u);
 
 		/* handle activate_spare versus create race:
@@ -9703,7 +9750,7 @@ static void imsm_process_update(struct supertype *st,
 			dev = get_imsm_dev(super, i);
 			map = get_imsm_map(dev, MAP_0);
 			start = pba_of_lba0(map);
-			end = start + blocks_per_member(map);
+			end = start + per_dev_array_size(map);
 			if ((new_start >= start && new_start <= end) ||
 			    (start >= new_start && start <= new_end))
 				/* overlap */;
@@ -10492,7 +10539,7 @@ static struct md_bb *imsm_get_badblocks(struct active_array *a, int slot)
 		return NULL;
 
 	get_volume_badblocks(super->bbm_log, ord_to_idx(ord), pba_of_lba0(map),
-			     blocks_per_member(map), &super->bb);
+			     per_dev_array_size(map), &super->bb);
 
 	return &super->bb;
 }
-- 
2.17.0