aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/raid5.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r--drivers/md/raid5.c62
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
3992struct raid5_plug_cb {
3993 struct blk_plug_cb cb;
3994 struct list_head list;
3995};
3996
3997static 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
4024static 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
3991static void make_request(struct mddev *mddev, struct bio * bi) 4048static 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);