diff options
| -rw-r--r-- | drivers/md/raid5.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b86ceba04f6f..269b7771a30b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -2633,6 +2633,84 @@ static int raid5_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_ | |||
| 2633 | return max; | 2633 | return max; |
| 2634 | } | 2634 | } |
| 2635 | 2635 | ||
| 2636 | |||
| 2637 | static int in_chunk_boundary(mddev_t *mddev, struct bio *bio) | ||
| 2638 | { | ||
| 2639 | sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); | ||
| 2640 | unsigned int chunk_sectors = mddev->chunk_size >> 9; | ||
| 2641 | unsigned int bio_sectors = bio->bi_size >> 9; | ||
| 2642 | |||
| 2643 | return chunk_sectors >= | ||
| 2644 | ((sector & (chunk_sectors - 1)) + bio_sectors); | ||
| 2645 | } | ||
| 2646 | |||
| 2647 | /* | ||
| 2648 | * The "raid5_align_endio" should check if the read succeeded and if it | ||
| 2649 | * did, call bio_endio on the original bio (having bio_put the new bio | ||
| 2650 | * first). | ||
| 2651 | * If the read failed.. | ||
| 2652 | */ | ||
| 2653 | int raid5_align_endio(struct bio *bi, unsigned int bytes , int error) | ||
| 2654 | { | ||
| 2655 | struct bio* raid_bi = bi->bi_private; | ||
| 2656 | if (bi->bi_size) | ||
| 2657 | return 1; | ||
| 2658 | bio_put(bi); | ||
| 2659 | bio_endio(raid_bi, bytes, error); | ||
| 2660 | return 0; | ||
| 2661 | } | ||
| 2662 | |||
| 2663 | static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio) | ||
| 2664 | { | ||
| 2665 | mddev_t *mddev = q->queuedata; | ||
| 2666 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
| 2667 | const unsigned int raid_disks = conf->raid_disks; | ||
| 2668 | const unsigned int data_disks = raid_disks - 1; | ||
| 2669 | unsigned int dd_idx, pd_idx; | ||
| 2670 | struct bio* align_bi; | ||
| 2671 | mdk_rdev_t *rdev; | ||
| 2672 | |||
| 2673 | if (!in_chunk_boundary(mddev, raid_bio)) { | ||
| 2674 | printk("chunk_aligned_read : non aligned\n"); | ||
| 2675 | return 0; | ||
| 2676 | } | ||
| 2677 | /* | ||
| 2678 | * use bio_clone to make a copy of the bio | ||
| 2679 | */ | ||
| 2680 | align_bi = bio_clone(raid_bio, GFP_NOIO); | ||
| 2681 | if (!align_bi) | ||
| 2682 | return 0; | ||
| 2683 | /* | ||
| 2684 | * set bi_end_io to a new function, and set bi_private to the | ||
| 2685 | * original bio. | ||
| 2686 | */ | ||
| 2687 | align_bi->bi_end_io = raid5_align_endio; | ||
| 2688 | align_bi->bi_private = raid_bio; | ||
| 2689 | /* | ||
| 2690 | * compute position | ||
| 2691 | */ | ||
| 2692 | align_bi->bi_sector = raid5_compute_sector(raid_bio->bi_sector, | ||
| 2693 | raid_disks, | ||
| 2694 | data_disks, | ||
| 2695 | &dd_idx, | ||
| 2696 | &pd_idx, | ||
| 2697 | conf); | ||
| 2698 | |||
| 2699 | rcu_read_lock(); | ||
| 2700 | rdev = rcu_dereference(conf->disks[dd_idx].rdev); | ||
| 2701 | if (rdev && test_bit(In_sync, &rdev->flags)) { | ||
| 2702 | align_bi->bi_bdev = rdev->bdev; | ||
| 2703 | atomic_inc(&rdev->nr_pending); | ||
| 2704 | rcu_read_unlock(); | ||
| 2705 | generic_make_request(align_bi); | ||
| 2706 | return 1; | ||
| 2707 | } else { | ||
| 2708 | rcu_read_unlock(); | ||
| 2709 | return 0; | ||
| 2710 | } | ||
| 2711 | } | ||
| 2712 | |||
| 2713 | |||
| 2636 | static int make_request(request_queue_t *q, struct bio * bi) | 2714 | static int make_request(request_queue_t *q, struct bio * bi) |
| 2637 | { | 2715 | { |
| 2638 | mddev_t *mddev = q->queuedata; | 2716 | mddev_t *mddev = q->queuedata; |
