aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2015-05-26 18:43:45 -0400
committerNeilBrown <neilb@suse.de>2015-05-27 21:34:40 -0400
commitd0852df543e5aa7db34c1ad26d053782bcbf48f1 (patch)
tree0276829b09beb6d16a4349afe2c75b3eaed80d47
parent2b6b24574256c05be145936f1493aec74c6904e5 (diff)
md/raid5: close race between STRIPE_BIT_DELAY and batching.
When we add a write to a stripe we need to make sure the bitmap bit is set. While doing that the stripe is not locked so it could be added to a batch after which further changes to STRIPE_BIT_DELAY and ->bm_seq are ineffective. So we need to hold off adding to a stripe until bitmap_startwrite has completed at least once, and we need to avoid further changes to STRIPE_BIT_DELAY once the stripe has been added to a batch. If a bitmap_startwrite() completes after the stripe was added to a batch, it will not have set the bit, only incremented a counter, so no extra delay of the stripe is needed. Reported-by: Shaohua Li <shli@kernel.org> Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--drivers/md/raid5.c25
-rw-r--r--drivers/md/raid5.h3
2 files changed, 25 insertions, 3 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c55a68f37c72..42d0ea6c8597 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -749,6 +749,7 @@ static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
749static bool stripe_can_batch(struct stripe_head *sh) 749static bool stripe_can_batch(struct stripe_head *sh)
750{ 750{
751 return test_bit(STRIPE_BATCH_READY, &sh->state) && 751 return test_bit(STRIPE_BATCH_READY, &sh->state) &&
752 !test_bit(STRIPE_BITMAP_PENDING, &sh->state) &&
752 is_full_stripe_write(sh); 753 is_full_stripe_write(sh);
753} 754}
754 755
@@ -2996,14 +2997,32 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx,
2996 pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n", 2997 pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
2997 (unsigned long long)(*bip)->bi_iter.bi_sector, 2998 (unsigned long long)(*bip)->bi_iter.bi_sector,
2998 (unsigned long long)sh->sector, dd_idx); 2999 (unsigned long long)sh->sector, dd_idx);
2999 spin_unlock_irq(&sh->stripe_lock);
3000 3000
3001 if (conf->mddev->bitmap && firstwrite) { 3001 if (conf->mddev->bitmap && firstwrite) {
3002 /* Cannot hold spinlock over bitmap_startwrite,
3003 * but must ensure this isn't added to a batch until
3004 * we have added to the bitmap and set bm_seq.
3005 * So set STRIPE_BITMAP_PENDING to prevent
3006 * batching.
3007 * If multiple add_stripe_bio() calls race here they
3008 * much all set STRIPE_BITMAP_PENDING. So only the first one
3009 * to complete "bitmap_startwrite" gets to set
3010 * STRIPE_BIT_DELAY. This is important as once a stripe
3011 * is added to a batch, STRIPE_BIT_DELAY cannot be changed
3012 * any more.
3013 */
3014 set_bit(STRIPE_BITMAP_PENDING, &sh->state);
3015 spin_unlock_irq(&sh->stripe_lock);
3002 bitmap_startwrite(conf->mddev->bitmap, sh->sector, 3016 bitmap_startwrite(conf->mddev->bitmap, sh->sector,
3003 STRIPE_SECTORS, 0); 3017 STRIPE_SECTORS, 0);
3004 sh->bm_seq = conf->seq_flush+1; 3018 spin_lock_irq(&sh->stripe_lock);
3005 set_bit(STRIPE_BIT_DELAY, &sh->state); 3019 clear_bit(STRIPE_BITMAP_PENDING, &sh->state);
3020 if (!sh->batch_head) {
3021 sh->bm_seq = conf->seq_flush+1;
3022 set_bit(STRIPE_BIT_DELAY, &sh->state);
3023 }
3006 } 3024 }
3025 spin_unlock_irq(&sh->stripe_lock);
3007 3026
3008 if (stripe_can_batch(sh)) 3027 if (stripe_can_batch(sh))
3009 stripe_add_to_batch_list(conf, sh); 3028 stripe_add_to_batch_list(conf, sh);
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 7dc0dd86074b..01cdb9f3a0c4 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -337,6 +337,9 @@ enum {
337 STRIPE_ON_RELEASE_LIST, 337 STRIPE_ON_RELEASE_LIST,
338 STRIPE_BATCH_READY, 338 STRIPE_BATCH_READY,
339 STRIPE_BATCH_ERR, 339 STRIPE_BATCH_ERR,
340 STRIPE_BITMAP_PENDING, /* Being added to bitmap, don't add
341 * to batch yet.
342 */
340}; 343};
341 344
342#define STRIPE_EXPAND_SYNC_FLAG \ 345#define STRIPE_EXPAND_SYNC_FLAG \