diff options
Diffstat (limited to 'drivers/md/linear.c')
-rw-r--r-- | drivers/md/linear.c | 133 |
1 files changed, 52 insertions, 81 deletions
diff --git a/drivers/md/linear.c b/drivers/md/linear.c index b9cbee688fae..190147c79e79 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c | |||
@@ -16,16 +16,8 @@ | |||
16 | Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 16 | Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/module.h> | ||
20 | |||
21 | #include <linux/raid/md.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/raid/linear.h> | 19 | #include <linux/raid/linear.h> |
24 | 20 | ||
25 | #define MAJOR_NR MD_MAJOR | ||
26 | #define MD_DRIVER | ||
27 | #define MD_PERSONALITY | ||
28 | |||
29 | /* | 21 | /* |
30 | * find which device holds a particular offset | 22 | * find which device holds a particular offset |
31 | */ | 23 | */ |
@@ -33,16 +25,15 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) | |||
33 | { | 25 | { |
34 | dev_info_t *hash; | 26 | dev_info_t *hash; |
35 | linear_conf_t *conf = mddev_to_conf(mddev); | 27 | linear_conf_t *conf = mddev_to_conf(mddev); |
36 | sector_t block = sector >> 1; | ||
37 | 28 | ||
38 | /* | 29 | /* |
39 | * sector_div(a,b) returns the remainer and sets a to a/b | 30 | * sector_div(a,b) returns the remainer and sets a to a/b |
40 | */ | 31 | */ |
41 | block >>= conf->preshift; | 32 | sector >>= conf->sector_shift; |
42 | (void)sector_div(block, conf->hash_spacing); | 33 | (void)sector_div(sector, conf->spacing); |
43 | hash = conf->hash_table[block]; | 34 | hash = conf->hash_table[sector]; |
44 | 35 | ||
45 | while ((sector>>1) >= (hash->size + hash->offset)) | 36 | while (sector >= hash->num_sectors + hash->start_sector) |
46 | hash++; | 37 | hash++; |
47 | return hash; | 38 | return hash; |
48 | } | 39 | } |
@@ -65,7 +56,7 @@ static int linear_mergeable_bvec(struct request_queue *q, | |||
65 | sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); | 56 | sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); |
66 | 57 | ||
67 | dev0 = which_dev(mddev, sector); | 58 | dev0 = which_dev(mddev, sector); |
68 | maxsectors = (dev0->size << 1) - (sector - (dev0->offset<<1)); | 59 | maxsectors = dev0->num_sectors - (sector - dev0->start_sector); |
69 | 60 | ||
70 | if (maxsectors < bio_sectors) | 61 | if (maxsectors < bio_sectors) |
71 | maxsectors = 0; | 62 | maxsectors = 0; |
@@ -112,8 +103,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) | |||
112 | dev_info_t **table; | 103 | dev_info_t **table; |
113 | mdk_rdev_t *rdev; | 104 | mdk_rdev_t *rdev; |
114 | int i, nb_zone, cnt; | 105 | int i, nb_zone, cnt; |
115 | sector_t min_spacing; | 106 | sector_t min_sectors; |
116 | sector_t curr_offset; | 107 | sector_t curr_sector; |
117 | struct list_head *tmp; | 108 | struct list_head *tmp; |
118 | 109 | ||
119 | conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), | 110 | conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), |
@@ -145,7 +136,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) | |||
145 | mddev->queue->max_sectors > (PAGE_SIZE>>9)) | 136 | mddev->queue->max_sectors > (PAGE_SIZE>>9)) |
146 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); | 137 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); |
147 | 138 | ||
148 | disk->size = rdev->size; | 139 | disk->num_sectors = rdev->size * 2; |
149 | conf->array_sectors += rdev->size * 2; | 140 | conf->array_sectors += rdev->size * 2; |
150 | 141 | ||
151 | cnt++; | 142 | cnt++; |
@@ -155,34 +146,34 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) | |||
155 | goto out; | 146 | goto out; |
156 | } | 147 | } |
157 | 148 | ||
158 | min_spacing = conf->array_sectors / 2; | 149 | min_sectors = conf->array_sectors; |
159 | sector_div(min_spacing, PAGE_SIZE/sizeof(struct dev_info *)); | 150 | sector_div(min_sectors, PAGE_SIZE/sizeof(struct dev_info *)); |
160 | 151 | ||
161 | /* min_spacing is the minimum spacing that will fit the hash | 152 | /* min_sectors is the minimum spacing that will fit the hash |
162 | * table in one PAGE. This may be much smaller than needed. | 153 | * table in one PAGE. This may be much smaller than needed. |
163 | * We find the smallest non-terminal set of consecutive devices | 154 | * We find the smallest non-terminal set of consecutive devices |
164 | * that is larger than min_spacing as use the size of that as | 155 | * that is larger than min_sectors and use the size of that as |
165 | * the actual spacing | 156 | * the actual spacing |
166 | */ | 157 | */ |
167 | conf->hash_spacing = conf->array_sectors / 2; | 158 | conf->spacing = conf->array_sectors; |
168 | for (i=0; i < cnt-1 ; i++) { | 159 | for (i=0; i < cnt-1 ; i++) { |
169 | sector_t sz = 0; | 160 | sector_t tmp = 0; |
170 | int j; | 161 | int j; |
171 | for (j = i; j < cnt - 1 && sz < min_spacing; j++) | 162 | for (j = i; j < cnt - 1 && tmp < min_sectors; j++) |
172 | sz += conf->disks[j].size; | 163 | tmp += conf->disks[j].num_sectors; |
173 | if (sz >= min_spacing && sz < conf->hash_spacing) | 164 | if (tmp >= min_sectors && tmp < conf->spacing) |
174 | conf->hash_spacing = sz; | 165 | conf->spacing = tmp; |
175 | } | 166 | } |
176 | 167 | ||
177 | /* hash_spacing may be too large for sector_div to work with, | 168 | /* spacing may be too large for sector_div to work with, |
178 | * so we might need to pre-shift | 169 | * so we might need to pre-shift |
179 | */ | 170 | */ |
180 | conf->preshift = 0; | 171 | conf->sector_shift = 0; |
181 | if (sizeof(sector_t) > sizeof(u32)) { | 172 | if (sizeof(sector_t) > sizeof(u32)) { |
182 | sector_t space = conf->hash_spacing; | 173 | sector_t space = conf->spacing; |
183 | while (space > (sector_t)(~(u32)0)) { | 174 | while (space > (sector_t)(~(u32)0)) { |
184 | space >>= 1; | 175 | space >>= 1; |
185 | conf->preshift++; | 176 | conf->sector_shift++; |
186 | } | 177 | } |
187 | } | 178 | } |
188 | /* | 179 | /* |
@@ -194,9 +185,9 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) | |||
194 | unsigned round; | 185 | unsigned round; |
195 | unsigned long base; | 186 | unsigned long base; |
196 | 187 | ||
197 | sz = conf->array_sectors >> (conf->preshift + 1); | 188 | sz = conf->array_sectors >> conf->sector_shift; |
198 | sz += 1; /* force round-up */ | 189 | sz += 1; /* force round-up */ |
199 | base = conf->hash_spacing >> conf->preshift; | 190 | base = conf->spacing >> conf->sector_shift; |
200 | round = sector_div(sz, base); | 191 | round = sector_div(sz, base); |
201 | nb_zone = sz + (round ? 1 : 0); | 192 | nb_zone = sz + (round ? 1 : 0); |
202 | } | 193 | } |
@@ -211,32 +202,31 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) | |||
211 | * Here we generate the linear hash table | 202 | * Here we generate the linear hash table |
212 | * First calculate the device offsets. | 203 | * First calculate the device offsets. |
213 | */ | 204 | */ |
214 | conf->disks[0].offset = 0; | 205 | conf->disks[0].start_sector = 0; |
215 | for (i = 1; i < raid_disks; i++) | 206 | for (i = 1; i < raid_disks; i++) |
216 | conf->disks[i].offset = | 207 | conf->disks[i].start_sector = |
217 | conf->disks[i-1].offset + | 208 | conf->disks[i-1].start_sector + |
218 | conf->disks[i-1].size; | 209 | conf->disks[i-1].num_sectors; |
219 | 210 | ||
220 | table = conf->hash_table; | 211 | table = conf->hash_table; |
221 | curr_offset = 0; | ||
222 | i = 0; | 212 | i = 0; |
223 | for (curr_offset = 0; | 213 | for (curr_sector = 0; |
224 | curr_offset < conf->array_sectors / 2; | 214 | curr_sector < conf->array_sectors; |
225 | curr_offset += conf->hash_spacing) { | 215 | curr_sector += conf->spacing) { |
226 | 216 | ||
227 | while (i < raid_disks-1 && | 217 | while (i < raid_disks-1 && |
228 | curr_offset >= conf->disks[i+1].offset) | 218 | curr_sector >= conf->disks[i+1].start_sector) |
229 | i++; | 219 | i++; |
230 | 220 | ||
231 | *table ++ = conf->disks + i; | 221 | *table ++ = conf->disks + i; |
232 | } | 222 | } |
233 | 223 | ||
234 | if (conf->preshift) { | 224 | if (conf->sector_shift) { |
235 | conf->hash_spacing >>= conf->preshift; | 225 | conf->spacing >>= conf->sector_shift; |
236 | /* round hash_spacing up so that when we divide by it, | 226 | /* round spacing up so that when we divide by it, |
237 | * we err on the side of "too-low", which is safest. | 227 | * we err on the side of "too-low", which is safest. |
238 | */ | 228 | */ |
239 | conf->hash_spacing++; | 229 | conf->spacing++; |
240 | } | 230 | } |
241 | 231 | ||
242 | BUG_ON(table - conf->hash_table > nb_zone); | 232 | BUG_ON(table - conf->hash_table > nb_zone); |
@@ -317,7 +307,6 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) | |||
317 | const int rw = bio_data_dir(bio); | 307 | const int rw = bio_data_dir(bio); |
318 | mddev_t *mddev = q->queuedata; | 308 | mddev_t *mddev = q->queuedata; |
319 | dev_info_t *tmp_dev; | 309 | dev_info_t *tmp_dev; |
320 | sector_t block; | ||
321 | int cpu; | 310 | int cpu; |
322 | 311 | ||
323 | if (unlikely(bio_barrier(bio))) { | 312 | if (unlikely(bio_barrier(bio))) { |
@@ -332,29 +321,33 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) | |||
332 | part_stat_unlock(); | 321 | part_stat_unlock(); |
333 | 322 | ||
334 | tmp_dev = which_dev(mddev, bio->bi_sector); | 323 | tmp_dev = which_dev(mddev, bio->bi_sector); |
335 | block = bio->bi_sector >> 1; | ||
336 | 324 | ||
337 | if (unlikely(block >= (tmp_dev->size + tmp_dev->offset) | 325 | if (unlikely(bio->bi_sector >= (tmp_dev->num_sectors + |
338 | || block < tmp_dev->offset)) { | 326 | tmp_dev->start_sector) |
327 | || (bio->bi_sector < | ||
328 | tmp_dev->start_sector))) { | ||
339 | char b[BDEVNAME_SIZE]; | 329 | char b[BDEVNAME_SIZE]; |
340 | 330 | ||
341 | printk("linear_make_request: Block %llu out of bounds on " | 331 | printk("linear_make_request: Sector %llu out of bounds on " |
342 | "dev %s size %llu offset %llu\n", | 332 | "dev %s: %llu sectors, offset %llu\n", |
343 | (unsigned long long)block, | 333 | (unsigned long long)bio->bi_sector, |
344 | bdevname(tmp_dev->rdev->bdev, b), | 334 | bdevname(tmp_dev->rdev->bdev, b), |
345 | (unsigned long long)tmp_dev->size, | 335 | (unsigned long long)tmp_dev->num_sectors, |
346 | (unsigned long long)tmp_dev->offset); | 336 | (unsigned long long)tmp_dev->start_sector); |
347 | bio_io_error(bio); | 337 | bio_io_error(bio); |
348 | return 0; | 338 | return 0; |
349 | } | 339 | } |
350 | if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > | 340 | if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > |
351 | (tmp_dev->offset + tmp_dev->size)<<1)) { | 341 | tmp_dev->start_sector + tmp_dev->num_sectors)) { |
352 | /* This bio crosses a device boundary, so we have to | 342 | /* This bio crosses a device boundary, so we have to |
353 | * split it. | 343 | * split it. |
354 | */ | 344 | */ |
355 | struct bio_pair *bp; | 345 | struct bio_pair *bp; |
346 | |||
356 | bp = bio_split(bio, | 347 | bp = bio_split(bio, |
357 | ((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector); | 348 | tmp_dev->start_sector + tmp_dev->num_sectors |
349 | - bio->bi_sector); | ||
350 | |||
358 | if (linear_make_request(q, &bp->bio1)) | 351 | if (linear_make_request(q, &bp->bio1)) |
359 | generic_make_request(&bp->bio1); | 352 | generic_make_request(&bp->bio1); |
360 | if (linear_make_request(q, &bp->bio2)) | 353 | if (linear_make_request(q, &bp->bio2)) |
@@ -364,7 +357,8 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) | |||
364 | } | 357 | } |
365 | 358 | ||
366 | bio->bi_bdev = tmp_dev->rdev->bdev; | 359 | bio->bi_bdev = tmp_dev->rdev->bdev; |
367 | bio->bi_sector = bio->bi_sector - (tmp_dev->offset << 1) + tmp_dev->rdev->data_offset; | 360 | bio->bi_sector = bio->bi_sector - tmp_dev->start_sector |
361 | + tmp_dev->rdev->data_offset; | ||
368 | 362 | ||
369 | return 1; | 363 | return 1; |
370 | } | 364 | } |
@@ -372,29 +366,6 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) | |||
372 | static void linear_status (struct seq_file *seq, mddev_t *mddev) | 366 | static void linear_status (struct seq_file *seq, mddev_t *mddev) |
373 | { | 367 | { |
374 | 368 | ||
375 | #undef MD_DEBUG | ||
376 | #ifdef MD_DEBUG | ||
377 | int j; | ||
378 | linear_conf_t *conf = mddev_to_conf(mddev); | ||
379 | sector_t s = 0; | ||
380 | |||
381 | seq_printf(seq, " "); | ||
382 | for (j = 0; j < mddev->raid_disks; j++) | ||
383 | { | ||
384 | char b[BDEVNAME_SIZE]; | ||
385 | s += conf->smallest_size; | ||
386 | seq_printf(seq, "[%s", | ||
387 | bdevname(conf->hash_table[j][0].rdev->bdev,b)); | ||
388 | |||
389 | while (s > conf->hash_table[j][0].offset + | ||
390 | conf->hash_table[j][0].size) | ||
391 | seq_printf(seq, "/%s] ", | ||
392 | bdevname(conf->hash_table[j][1].rdev->bdev,b)); | ||
393 | else | ||
394 | seq_printf(seq, "] "); | ||
395 | } | ||
396 | seq_printf(seq, "\n"); | ||
397 | #endif | ||
398 | seq_printf(seq, " %dk rounding", mddev->chunk_size/1024); | 369 | seq_printf(seq, " %dk rounding", mddev->chunk_size/1024); |
399 | } | 370 | } |
400 | 371 | ||