diff options
author | NeilBrown <neilb@suse.de> | 2015-05-26 18:43:45 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-05-27 21:34:40 -0400 |
commit | d0852df543e5aa7db34c1ad26d053782bcbf48f1 (patch) | |
tree | 0276829b09beb6d16a4349afe2c75b3eaed80d47 | |
parent | 2b6b24574256c05be145936f1493aec74c6904e5 (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.c | 25 | ||||
-rw-r--r-- | drivers/md/raid5.h | 3 |
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) | |||
749 | static bool stripe_can_batch(struct stripe_head *sh) | 749 | static 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 \ |