Now that queue flags are no longer atomic (commit: 75ad23bc0fcb4f992a5d06982bf0857ab1738e9e) we must protect calls to blk_remove_plug with spin_lock(q->queue_lock). Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/md/md.c | 3 +++ drivers/md/raid1.c | 10 ++++++++-- drivers/md/raid10.c | 10 ++++++++-- drivers/md/raid5.c | 12 ++++++++++-- include/linux/raid/md_k.h | 3 +++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 606c8ee..e389978 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -283,6 +283,9 @@ static mddev_t * mddev_find(dev_t unit) kfree(new); return NULL; } + spin_lock_init(&new->queue_lock); + new->queue->queue_lock = &new->queue_lock; + /* Can be unlocked because the queue is new: no concurrency */ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6778b7c..79f19b1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -603,9 +603,13 @@ static int flush_pending_writes(conf_t *conf) spin_lock_irq(&conf->device_lock); if (conf->pending_bio_list.head) { + struct request_queue *q = conf->mddev->queue; struct bio *bio; + bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(conf->mddev->queue); + spin_lock(q->queue_lock); + blk_remove_plug(q); + spin_unlock(q->queue_lock); spin_unlock_irq(&conf->device_lock); /* flush any pending bitmap writes to * disk before proceeding w/ I/O */ @@ -964,7 +968,9 @@ static int make_request(struct request_queue *q, struct bio * bio) bio_list_merge(&conf->pending_bio_list, &bl); bio_list_init(&bl); - blk_plug_device(mddev->queue); + spin_lock(q->queue_lock); + blk_plug_device(q); + spin_unlock(q->queue_lock); spin_unlock_irqrestore(&conf->device_lock, flags); /* In case raid1d snuck into freeze_array */ diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 5938fa9..3ecd437 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -646,9 +646,13 @@ static int flush_pending_writes(conf_t *conf) spin_lock_irq(&conf->device_lock); if (conf->pending_bio_list.head) { + struct request_queue *q = conf->mddev->queue; struct bio *bio; + bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(conf->mddev->queue); + spin_lock(q->queue_lock); + blk_remove_plug(q); + spin_unlock(q->queue_lock); spin_unlock_irq(&conf->device_lock); /* flush any pending bitmap writes to disk * before proceeding w/ I/O */ @@ -955,7 +959,9 @@ static int make_request(struct request_queue *q, struct bio * bio) bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0); spin_lock_irqsave(&conf->device_lock, flags); bio_list_merge(&conf->pending_bio_list, &bl); - blk_plug_device(mddev->queue); + spin_lock(q->queue_lock); + blk_plug_device(q); + spin_unlock(q->queue_lock); spin_unlock_irqrestore(&conf->device_lock, flags); /* In case raid10d snuck in to freeze_array */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e057944..b64a545 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -124,17 +124,23 @@ static void print_raid5_conf (raid5_conf_t *conf); static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) { + struct request_queue *q = conf->mddev->queue; + if (atomic_dec_and_test(&sh->count)) { BUG_ON(!list_empty(&sh->lru)); BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) { list_add_tail(&sh->lru, &conf->delayed_list); - blk_plug_device(conf->mddev->queue); + spin_lock(q->queue_lock); + blk_plug_device(q); + spin_unlock(q->queue_lock); } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && sh->bm_seq - conf->seq_write > 0) { list_add_tail(&sh->lru, &conf->bitmap_list); - blk_plug_device(conf->mddev->queue); + spin_lock(q->queue_lock); + blk_plug_device(q); + spin_unlock(q->queue_lock); } else { clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); @@ -3268,10 +3274,12 @@ static void raid5_unplug_device(struct request_queue *q) spin_lock_irqsave(&conf->device_lock, flags); + spin_lock(q->queue_lock); if (blk_remove_plug(q)) { conf->seq_flush++; raid5_activate_delayed(conf); } + spin_unlock(q->queue_lock); md_wakeup_thread(mddev->thread); spin_unlock_irqrestore(&conf->device_lock, flags); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 812ffa5..000a215 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -240,6 +240,9 @@ struct mddev_s struct timer_list safemode_timer; atomic_t writes_pending; struct request_queue *queue; /* for plugging ... */ + spinlock_t queue_lock; /* we supply the lock + * for blk-core + */ atomic_t write_behind; /* outstanding async IO */ unsigned int max_write_behind; /* 0 = sync */ -- To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html