diff options
| author | shli@kernel.org <shli@kernel.org> | 2014-12-14 20:57:04 -0500 |
|---|---|---|
| committer | NeilBrown <neilb@suse.de> | 2015-04-21 18:00:41 -0400 |
| commit | dabc4ec6ba72418ebca6bf1884f344bba40c8709 (patch) | |
| tree | 7860792d9a7b5043c043eea983d218591bbe06f5 /drivers/md | |
| parent | 72ac733015bbdc0356ba3e92c52137a265910a91 (diff) | |
raid5: handle expansion/resync case with stripe batching
expansion/resync can grab a stripe when the stripe is in batch list. Since all
stripes in batch list must be in the same state, we can't allow some stripes
run into expansion/resync. So we delay expansion/resync for stripe in batch
list.
Signed-off-by: Shaohua Li <shli@fusionio.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
| -rw-r--r-- | drivers/md/raid5.c | 24 | ||||
| -rw-r--r-- | drivers/md/raid5.h | 5 |
2 files changed, 21 insertions, 8 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 54f3cb312b42..3ae097d50b51 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -3440,8 +3440,10 @@ unhash: | |||
| 3440 | struct stripe_head, batch_list); | 3440 | struct stripe_head, batch_list); |
| 3441 | list_del_init(&sh->batch_list); | 3441 | list_del_init(&sh->batch_list); |
| 3442 | 3442 | ||
| 3443 | sh->state = head_sh->state & (~((1 << STRIPE_ACTIVE) | | 3443 | set_mask_bits(&sh->state, ~STRIPE_EXPAND_SYNC_FLAG, |
| 3444 | (1 << STRIPE_PREREAD_ACTIVE))); | 3444 | head_sh->state & ~((1 << STRIPE_ACTIVE) | |
| 3445 | (1 << STRIPE_PREREAD_ACTIVE) | | ||
| 3446 | STRIPE_EXPAND_SYNC_FLAG)); | ||
| 3445 | sh->check_state = head_sh->check_state; | 3447 | sh->check_state = head_sh->check_state; |
| 3446 | sh->reconstruct_state = head_sh->reconstruct_state; | 3448 | sh->reconstruct_state = head_sh->reconstruct_state; |
| 3447 | for (i = 0; i < sh->disks; i++) { | 3449 | for (i = 0; i < sh->disks; i++) { |
| @@ -3453,6 +3455,8 @@ unhash: | |||
| 3453 | spin_lock_irq(&sh->stripe_lock); | 3455 | spin_lock_irq(&sh->stripe_lock); |
| 3454 | sh->batch_head = NULL; | 3456 | sh->batch_head = NULL; |
| 3455 | spin_unlock_irq(&sh->stripe_lock); | 3457 | spin_unlock_irq(&sh->stripe_lock); |
| 3458 | if (sh->state & STRIPE_EXPAND_SYNC_FLAG) | ||
| 3459 | set_bit(STRIPE_HANDLE, &sh->state); | ||
| 3456 | release_stripe(sh); | 3460 | release_stripe(sh); |
| 3457 | } | 3461 | } |
| 3458 | 3462 | ||
| @@ -3460,6 +3464,8 @@ unhash: | |||
| 3460 | head_sh->batch_head = NULL; | 3464 | head_sh->batch_head = NULL; |
| 3461 | spin_unlock_irq(&head_sh->stripe_lock); | 3465 | spin_unlock_irq(&head_sh->stripe_lock); |
| 3462 | wake_up_nr(&conf->wait_for_overlap, wakeup_nr); | 3466 | wake_up_nr(&conf->wait_for_overlap, wakeup_nr); |
| 3467 | if (head_sh->state & STRIPE_EXPAND_SYNC_FLAG) | ||
| 3468 | set_bit(STRIPE_HANDLE, &head_sh->state); | ||
| 3463 | } | 3469 | } |
| 3464 | 3470 | ||
| 3465 | static void handle_stripe_dirtying(struct r5conf *conf, | 3471 | static void handle_stripe_dirtying(struct r5conf *conf, |
| @@ -3927,8 +3933,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) | |||
| 3927 | 3933 | ||
| 3928 | memset(s, 0, sizeof(*s)); | 3934 | memset(s, 0, sizeof(*s)); |
| 3929 | 3935 | ||
| 3930 | s->expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state); | 3936 | s->expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state) && !sh->batch_head; |
| 3931 | s->expanded = test_bit(STRIPE_EXPAND_READY, &sh->state); | 3937 | s->expanded = test_bit(STRIPE_EXPAND_READY, &sh->state) && !sh->batch_head; |
| 3932 | s->failed_num[0] = -1; | 3938 | s->failed_num[0] = -1; |
| 3933 | s->failed_num[1] = -1; | 3939 | s->failed_num[1] = -1; |
| 3934 | 3940 | ||
| @@ -4150,9 +4156,11 @@ static void check_break_stripe_batch_list(struct stripe_head *sh) | |||
| 4150 | struct stripe_head, batch_list); | 4156 | struct stripe_head, batch_list); |
| 4151 | list_del_init(&sh->batch_list); | 4157 | list_del_init(&sh->batch_list); |
| 4152 | 4158 | ||
| 4153 | sh->state = head_sh->state & ~((1 << STRIPE_ACTIVE) | | 4159 | set_mask_bits(&sh->state, ~STRIPE_EXPAND_SYNC_FLAG, |
| 4154 | (1 << STRIPE_PREREAD_ACTIVE) | | 4160 | head_sh->state & ~((1 << STRIPE_ACTIVE) | |
| 4155 | (1 << STRIPE_DEGRADED)); | 4161 | (1 << STRIPE_PREREAD_ACTIVE) | |
| 4162 | (1 << STRIPE_DEGRADED) | | ||
| 4163 | STRIPE_EXPAND_SYNC_FLAG)); | ||
| 4156 | sh->check_state = head_sh->check_state; | 4164 | sh->check_state = head_sh->check_state; |
| 4157 | sh->reconstruct_state = head_sh->reconstruct_state; | 4165 | sh->reconstruct_state = head_sh->reconstruct_state; |
| 4158 | for (i = 0; i < sh->disks; i++) | 4166 | for (i = 0; i < sh->disks; i++) |
| @@ -4194,7 +4202,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
| 4194 | 4202 | ||
| 4195 | check_break_stripe_batch_list(sh); | 4203 | check_break_stripe_batch_list(sh); |
| 4196 | 4204 | ||
| 4197 | if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) { | 4205 | if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state) && !sh->batch_head) { |
| 4198 | spin_lock(&sh->stripe_lock); | 4206 | spin_lock(&sh->stripe_lock); |
| 4199 | /* Cannot process 'sync' concurrently with 'discard' */ | 4207 | /* Cannot process 'sync' concurrently with 'discard' */ |
| 4200 | if (!test_bit(STRIPE_DISCARD, &sh->state) && | 4208 | if (!test_bit(STRIPE_DISCARD, &sh->state) && |
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index cf3562e99440..ee65ed844d3f 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h | |||
| @@ -339,6 +339,11 @@ enum { | |||
| 339 | STRIPE_BATCH_ERR, | 339 | STRIPE_BATCH_ERR, |
| 340 | }; | 340 | }; |
| 341 | 341 | ||
| 342 | #define STRIPE_EXPAND_SYNC_FLAG \ | ||
| 343 | ((1 << STRIPE_EXPAND_SOURCE) |\ | ||
| 344 | (1 << STRIPE_EXPAND_READY) |\ | ||
| 345 | (1 << STRIPE_EXPANDING) |\ | ||
| 346 | (1 << STRIPE_SYNC_REQUESTED)) | ||
| 342 | /* | 347 | /* |
| 343 | * Operation request flags | 348 | * Operation request flags |
| 344 | */ | 349 | */ |
