Commit cc371e66e340f35eed8dc4651c7c18e754c7fb26
Committed by
Jens Axboe
1 parent
b24498d477
Exists in
master
and in
39 other branches
Add bvec_merge_data to handle stacked devices and ->merge_bvec()
When devices are stacked, one device's merge_bvec_fn may need to perform the mapping and then call one or more functions for its underlying devices. The following bio fields are used: bio->bi_sector bio->bi_bdev bio->bi_size bio->bi_rw using bio_data_dir() This patch creates a new struct bvec_merge_data holding a copy of those fields to avoid having to change them directly in the struct bio when going down the stack only to have to change them back again on the way back up. (And then when the bio gets mapped for real, the whole exercise gets repeated, but that's a problem for another day...) Signed-off-by: Alasdair G Kergon <agk@redhat.com> Cc: Neil Brown <neilb@suse.de> Cc: Milan Broz <mbroz@redhat.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 7 changed files with 60 additions and 29 deletions Side-by-side Diff
drivers/block/pktcdvd.c
... | ... | @@ -2633,11 +2633,12 @@ |
2633 | 2633 | |
2634 | 2634 | |
2635 | 2635 | |
2636 | -static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec) | |
2636 | +static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, | |
2637 | + struct bio_vec *bvec) | |
2637 | 2638 | { |
2638 | 2639 | struct pktcdvd_device *pd = q->queuedata; |
2639 | - sector_t zone = ZONE(bio->bi_sector, pd); | |
2640 | - int used = ((bio->bi_sector - zone) << 9) + bio->bi_size; | |
2640 | + sector_t zone = ZONE(bmd->bi_sector, pd); | |
2641 | + int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size; | |
2641 | 2642 | int remaining = (pd->settings.size << 9) - used; |
2642 | 2643 | int remaining2; |
2643 | 2644 | |
... | ... | @@ -2645,7 +2646,7 @@ |
2645 | 2646 | * A bio <= PAGE_SIZE must be allowed. If it crosses a packet |
2646 | 2647 | * boundary, pkt_make_request() will split the bio. |
2647 | 2648 | */ |
2648 | - remaining2 = PAGE_SIZE - bio->bi_size; | |
2649 | + remaining2 = PAGE_SIZE - bmd->bi_size; | |
2649 | 2650 | remaining = max(remaining, remaining2); |
2650 | 2651 | |
2651 | 2652 | BUG_ON(remaining < 0); |
drivers/md/linear.c
... | ... | @@ -50,17 +50,19 @@ |
50 | 50 | /** |
51 | 51 | * linear_mergeable_bvec -- tell bio layer if two requests can be merged |
52 | 52 | * @q: request queue |
53 | - * @bio: the buffer head that's been built up so far | |
53 | + * @bvm: properties of new bio | |
54 | 54 | * @biovec: the request that could be merged to it. |
55 | 55 | * |
56 | 56 | * Return amount of bytes we can take at this offset |
57 | 57 | */ |
58 | -static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) | |
58 | +static int linear_mergeable_bvec(struct request_queue *q, | |
59 | + struct bvec_merge_data *bvm, | |
60 | + struct bio_vec *biovec) | |
59 | 61 | { |
60 | 62 | mddev_t *mddev = q->queuedata; |
61 | 63 | dev_info_t *dev0; |
62 | - unsigned long maxsectors, bio_sectors = bio->bi_size >> 9; | |
63 | - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); | |
64 | + unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; | |
65 | + sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); | |
64 | 66 | |
65 | 67 | dev0 = which_dev(mddev, sector); |
66 | 68 | maxsectors = (dev0->size << 1) - (sector - (dev0->offset<<1)); |
drivers/md/raid0.c
... | ... | @@ -241,18 +241,20 @@ |
241 | 241 | /** |
242 | 242 | * raid0_mergeable_bvec -- tell bio layer if a two requests can be merged |
243 | 243 | * @q: request queue |
244 | - * @bio: the buffer head that's been built up so far | |
244 | + * @bvm: properties of new bio | |
245 | 245 | * @biovec: the request that could be merged to it. |
246 | 246 | * |
247 | 247 | * Return amount of bytes we can accept at this offset |
248 | 248 | */ |
249 | -static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) | |
249 | +static int raid0_mergeable_bvec(struct request_queue *q, | |
250 | + struct bvec_merge_data *bvm, | |
251 | + struct bio_vec *biovec) | |
250 | 252 | { |
251 | 253 | mddev_t *mddev = q->queuedata; |
252 | - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); | |
254 | + sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); | |
253 | 255 | int max; |
254 | 256 | unsigned int chunk_sectors = mddev->chunk_size >> 9; |
255 | - unsigned int bio_sectors = bio->bi_size >> 9; | |
257 | + unsigned int bio_sectors = bvm->bi_size >> 9; | |
256 | 258 | |
257 | 259 | max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; |
258 | 260 | if (max < 0) max = 0; /* bio_add cannot handle a negative return */ |
drivers/md/raid10.c
... | ... | @@ -439,26 +439,27 @@ |
439 | 439 | /** |
440 | 440 | * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged |
441 | 441 | * @q: request queue |
442 | - * @bio: the buffer head that's been built up so far | |
442 | + * @bvm: properties of new bio | |
443 | 443 | * @biovec: the request that could be merged to it. |
444 | 444 | * |
445 | 445 | * Return amount of bytes we can accept at this offset |
446 | 446 | * If near_copies == raid_disk, there are no striping issues, |
447 | 447 | * but in that case, the function isn't called at all. |
448 | 448 | */ |
449 | -static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio, | |
450 | - struct bio_vec *bio_vec) | |
449 | +static int raid10_mergeable_bvec(struct request_queue *q, | |
450 | + struct bvec_merge_data *bvm, | |
451 | + struct bio_vec *biovec) | |
451 | 452 | { |
452 | 453 | mddev_t *mddev = q->queuedata; |
453 | - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); | |
454 | + sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); | |
454 | 455 | int max; |
455 | 456 | unsigned int chunk_sectors = mddev->chunk_size >> 9; |
456 | - unsigned int bio_sectors = bio->bi_size >> 9; | |
457 | + unsigned int bio_sectors = bvm->bi_size >> 9; | |
457 | 458 | |
458 | 459 | max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; |
459 | 460 | if (max < 0) max = 0; /* bio_add cannot handle a negative return */ |
460 | - if (max <= bio_vec->bv_len && bio_sectors == 0) | |
461 | - return bio_vec->bv_len; | |
461 | + if (max <= biovec->bv_len && bio_sectors == 0) | |
462 | + return biovec->bv_len; | |
462 | 463 | else |
463 | 464 | return max; |
464 | 465 | } |
drivers/md/raid5.c
... | ... | @@ -3319,15 +3319,17 @@ |
3319 | 3319 | /* We want read requests to align with chunks where possible, |
3320 | 3320 | * but write requests don't need to. |
3321 | 3321 | */ |
3322 | -static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) | |
3322 | +static int raid5_mergeable_bvec(struct request_queue *q, | |
3323 | + struct bvec_merge_data *bvm, | |
3324 | + struct bio_vec *biovec) | |
3323 | 3325 | { |
3324 | 3326 | mddev_t *mddev = q->queuedata; |
3325 | - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); | |
3327 | + sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); | |
3326 | 3328 | int max; |
3327 | 3329 | unsigned int chunk_sectors = mddev->chunk_size >> 9; |
3328 | - unsigned int bio_sectors = bio->bi_size >> 9; | |
3330 | + unsigned int bio_sectors = bvm->bi_size >> 9; | |
3329 | 3331 | |
3330 | - if (bio_data_dir(bio) == WRITE) | |
3332 | + if ((bvm->bi_rw & 1) == WRITE) | |
3331 | 3333 | return biovec->bv_len; /* always allow writes to be mergeable */ |
3332 | 3334 | |
3333 | 3335 | max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; |
fs/bio.c
... | ... | @@ -325,10 +325,19 @@ |
325 | 325 | if (page == prev->bv_page && |
326 | 326 | offset == prev->bv_offset + prev->bv_len) { |
327 | 327 | prev->bv_len += len; |
328 | - if (q->merge_bvec_fn && | |
329 | - q->merge_bvec_fn(q, bio, prev) < len) { | |
330 | - prev->bv_len -= len; | |
331 | - return 0; | |
328 | + | |
329 | + if (q->merge_bvec_fn) { | |
330 | + struct bvec_merge_data bvm = { | |
331 | + .bi_bdev = bio->bi_bdev, | |
332 | + .bi_sector = bio->bi_sector, | |
333 | + .bi_size = bio->bi_size, | |
334 | + .bi_rw = bio->bi_rw, | |
335 | + }; | |
336 | + | |
337 | + if (q->merge_bvec_fn(q, &bvm, prev) < len) { | |
338 | + prev->bv_len -= len; | |
339 | + return 0; | |
340 | + } | |
332 | 341 | } |
333 | 342 | |
334 | 343 | goto done; |
335 | 344 | |
... | ... | @@ -369,11 +378,18 @@ |
369 | 378 | * queue to get further control |
370 | 379 | */ |
371 | 380 | if (q->merge_bvec_fn) { |
381 | + struct bvec_merge_data bvm = { | |
382 | + .bi_bdev = bio->bi_bdev, | |
383 | + .bi_sector = bio->bi_sector, | |
384 | + .bi_size = bio->bi_size, | |
385 | + .bi_rw = bio->bi_rw, | |
386 | + }; | |
387 | + | |
372 | 388 | /* |
373 | 389 | * merge_bvec_fn() returns number of bytes it can accept |
374 | 390 | * at this offset |
375 | 391 | */ |
376 | - if (q->merge_bvec_fn(q, bio, bvec) < len) { | |
392 | + if (q->merge_bvec_fn(q, &bvm, bvec) < len) { | |
377 | 393 | bvec->bv_page = NULL; |
378 | 394 | bvec->bv_len = 0; |
379 | 395 | bvec->bv_offset = 0; |
include/linux/blkdev.h
... | ... | @@ -254,7 +254,14 @@ |
254 | 254 | typedef void (unplug_fn) (struct request_queue *); |
255 | 255 | |
256 | 256 | struct bio_vec; |
257 | -typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *); | |
257 | +struct bvec_merge_data { | |
258 | + struct block_device *bi_bdev; | |
259 | + sector_t bi_sector; | |
260 | + unsigned bi_size; | |
261 | + unsigned long bi_rw; | |
262 | +}; | |
263 | +typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *, | |
264 | + struct bio_vec *); | |
258 | 265 | typedef void (prepare_flush_fn) (struct request_queue *, struct request *); |
259 | 266 | typedef void (softirq_done_fn)(struct request *); |
260 | 267 | typedef int (dma_drain_needed_fn)(struct request *); |