md: close a livelock window in handle_parity_checks5

If a failure is detected after a parity check operation has been initiated,
but before it completes handle_parity_checks5 will never quiesce operations on
the stripe.

Explicitly handle this case by "canceling" the parity check, i.e. clear the
STRIPE_OP_CHECK flags and queue the stripe on the handle list again to refresh
any non-uptodate blocks.

Kernel versions >= 2.6.23 are susceptible.

Cc: <stable@kernel.org>
Cc: NeilBrown <neilb@suse.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Dan Williams and committed by Linus Torvalds bd2ab670 231bc2a2

+31 -24
+31 -24
drivers/md/raid5.c
··· 2348 static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh, 2349 struct stripe_head_state *s, int disks) 2350 { 2351 - set_bit(STRIPE_HANDLE, &sh->state); 2352 - /* Take one of the following actions: 2353 - * 1/ start a check parity operation if (uptodate == disks) 2354 - * 2/ finish a check parity operation and act on the result 2355 - * 3/ skip to the writeback section if we previously 2356 - * initiated a recovery operation 2357 - */ 2358 - if (s->failed == 0 && 2359 - !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) { 2360 - if (!test_and_set_bit(STRIPE_OP_CHECK, &sh->ops.pending)) { 2361 - BUG_ON(s->uptodate != disks); 2362 - clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags); 2363 - sh->ops.count++; 2364 - s->uptodate--; 2365 - } else if ( 2366 - test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) { 2367 - clear_bit(STRIPE_OP_CHECK, &sh->ops.ack); 2368 - clear_bit(STRIPE_OP_CHECK, &sh->ops.pending); 2369 2370 if (sh->ops.zero_sum_result == 0) 2371 /* parity is correct (on disc, 2372 * not in buffer any more) ··· 2381 s->uptodate++; 2382 } 2383 } 2384 - } 2385 } 2386 2387 /* check if we can clear a parity disk reconstruct */ ··· 2395 clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending); 2396 } 2397 2398 - /* Wait for check parity and compute block operations to complete 2399 - * before write-back 2400 */ 2401 - if (!test_bit(STRIPE_INSYNC, &sh->state) && 2402 - !test_bit(STRIPE_OP_CHECK, &sh->ops.pending) && 2403 - !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) { 2404 struct r5dev *dev; 2405 /* either failed parity check, or recovery is happening */ 2406 if (s->failed == 0)
··· 2348 static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh, 2349 struct stripe_head_state *s, int disks) 2350 { 2351 + int canceled_check = 0; 2352 2353 + set_bit(STRIPE_HANDLE, &sh->state); 2354 + 2355 + /* complete a check operation */ 2356 + if (test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) { 2357 + clear_bit(STRIPE_OP_CHECK, &sh->ops.ack); 2358 + clear_bit(STRIPE_OP_CHECK, &sh->ops.pending); 2359 + if (s->failed == 0) { 2360 if (sh->ops.zero_sum_result == 0) 2361 /* parity is correct (on disc, 2362 * not in buffer any more) ··· 2391 s->uptodate++; 2392 } 2393 } 2394 + } else 2395 + canceled_check = 1; /* STRIPE_INSYNC is not set */ 2396 } 2397 2398 /* check if we can clear a parity disk reconstruct */ ··· 2404 clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending); 2405 } 2406 2407 + /* start a new check operation if there are no failures, the stripe is 2408 + * not insync, and a repair is not in flight 2409 */ 2410 + if (s->failed == 0 && 2411 + !test_bit(STRIPE_INSYNC, &sh->state) && 2412 + !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) { 2413 + if (!test_and_set_bit(STRIPE_OP_CHECK, &sh->ops.pending)) { 2414 + BUG_ON(s->uptodate != disks); 2415 + clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags); 2416 + sh->ops.count++; 2417 + s->uptodate--; 2418 + } 2419 + } 2420 + 2421 + /* Wait for check parity and compute block operations to complete 2422 + * before write-back. If a failure occurred while the check operation 2423 + * was in flight we need to cycle this stripe through handle_stripe 2424 + * since the parity block may not be uptodate 2425 + */ 2426 + if (!canceled_check && !test_bit(STRIPE_INSYNC, &sh->state) && 2427 + !test_bit(STRIPE_OP_CHECK, &sh->ops.pending) && 2428 + !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) { 2429 struct r5dev *dev; 2430 /* either failed parity check, or recovery is happening */ 2431 if (s->failed == 0)