diff options
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index bde9da2baa39..978ba9b7a3c4 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -471,7 +471,8 @@ get_active_stripe(struct r5conf *conf, sector_t sector, | |||
471 | } else { | 471 | } else { |
472 | if (atomic_read(&sh->count)) { | 472 | if (atomic_read(&sh->count)) { |
473 | BUG_ON(!list_empty(&sh->lru) | 473 | BUG_ON(!list_empty(&sh->lru) |
474 | && !test_bit(STRIPE_EXPANDING, &sh->state)); | 474 | && !test_bit(STRIPE_EXPANDING, &sh->state) |
475 | && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)); | ||
475 | } else { | 476 | } else { |
476 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | 477 | if (!test_bit(STRIPE_HANDLE, &sh->state)) |
477 | atomic_inc(&conf->active_stripes); | 478 | atomic_inc(&conf->active_stripes); |
@@ -3988,6 +3989,62 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf) | |||
3988 | return sh; | 3989 | return sh; |
3989 | } | 3990 | } |
3990 | 3991 | ||
3992 | struct raid5_plug_cb { | ||
3993 | struct blk_plug_cb cb; | ||
3994 | struct list_head list; | ||
3995 | }; | ||
3996 | |||
3997 | static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule) | ||
3998 | { | ||
3999 | struct raid5_plug_cb *cb = container_of( | ||
4000 | blk_cb, struct raid5_plug_cb, cb); | ||
4001 | struct stripe_head *sh; | ||
4002 | struct mddev *mddev = cb->cb.data; | ||
4003 | struct r5conf *conf = mddev->private; | ||
4004 | |||
4005 | if (cb->list.next && !list_empty(&cb->list)) { | ||
4006 | spin_lock_irq(&conf->device_lock); | ||
4007 | while (!list_empty(&cb->list)) { | ||
4008 | sh = list_first_entry(&cb->list, struct stripe_head, lru); | ||
4009 | list_del_init(&sh->lru); | ||
4010 | /* | ||
4011 | * avoid race release_stripe_plug() sees | ||
4012 | * STRIPE_ON_UNPLUG_LIST clear but the stripe | ||
4013 | * is still in our list | ||
4014 | */ | ||
4015 | smp_mb__before_clear_bit(); | ||
4016 | clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state); | ||
4017 | __release_stripe(conf, sh); | ||
4018 | } | ||
4019 | spin_unlock_irq(&conf->device_lock); | ||
4020 | } | ||
4021 | kfree(cb); | ||
4022 | } | ||
4023 | |||
4024 | static void release_stripe_plug(struct mddev *mddev, | ||
4025 | struct stripe_head *sh) | ||
4026 | { | ||
4027 | struct blk_plug_cb *blk_cb = blk_check_plugged( | ||
4028 | raid5_unplug, mddev, | ||
4029 | sizeof(struct raid5_plug_cb)); | ||
4030 | struct raid5_plug_cb *cb; | ||
4031 | |||
4032 | if (!blk_cb) { | ||
4033 | release_stripe(sh); | ||
4034 | return; | ||
4035 | } | ||
4036 | |||
4037 | cb = container_of(blk_cb, struct raid5_plug_cb, cb); | ||
4038 | |||
4039 | if (cb->list.next == NULL) | ||
4040 | INIT_LIST_HEAD(&cb->list); | ||
4041 | |||
4042 | if (!test_and_set_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)) | ||
4043 | list_add_tail(&sh->lru, &cb->list); | ||
4044 | else | ||
4045 | release_stripe(sh); | ||
4046 | } | ||
4047 | |||
3991 | static void make_request(struct mddev *mddev, struct bio * bi) | 4048 | static void make_request(struct mddev *mddev, struct bio * bi) |
3992 | { | 4049 | { |
3993 | struct r5conf *conf = mddev->private; | 4050 | struct r5conf *conf = mddev->private; |
@@ -4116,8 +4173,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) | |||
4116 | if ((bi->bi_rw & REQ_SYNC) && | 4173 | if ((bi->bi_rw & REQ_SYNC) && |
4117 | !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | 4174 | !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) |
4118 | atomic_inc(&conf->preread_active_stripes); | 4175 | atomic_inc(&conf->preread_active_stripes); |
4119 | mddev_check_plugged(mddev); | 4176 | release_stripe_plug(mddev, sh); |
4120 | release_stripe(sh); | ||
4121 | } else { | 4177 | } else { |
4122 | /* cannot get stripe for read-ahead, just give-up */ | 4178 | /* cannot get stripe for read-ahead, just give-up */ |
4123 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | 4179 | clear_bit(BIO_UPTODATE, &bi->bi_flags); |