From: Dan Williams <dan.j.williams@xxxxxxxxx> Enable handle_stripe5 to pass off check parity operations to raid5_do_soft_block_ops formerly handled by compute_parity5. Changelog: * removed handle_check_operations5. All logic moved into handle_stripe5 so that we do not need to go through the initiation logic to end the operation. * clear the uptodate bit on the parity block * hold off check operations if a parity dependent operation is in flight like a write Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/md/raid5.c | 60 ++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e39d248..24ed4d8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2121,35 +2121,59 @@ #endif locked += handle_write_operations5(sh, rcw); } - /* maybe we need to check and possibly fix the parity for this stripe - * Any reads will already have been scheduled, so we just see if enough data - * is available + /* 1/ Maybe we need to check and possibly fix the parity for this stripe. + * Any reads will already have been scheduled, so we just see if enough data + * is available. + * 2/ Hold off parity checks while parity dependent operations are in flight + * (RCW and RMW are protected by 'locked') */ - if (syncing && locked == 0 && - !test_bit(STRIPE_INSYNC, &sh->state)) { + if ((syncing && locked == 0 && + !test_bit(STRIPE_INSYNC, &sh->state)) || + test_bit(STRIPE_OP_CHECK, &sh->state)) { + set_bit(STRIPE_HANDLE, &sh->state); + /* Take one of the following actions: + * 1/ start a check parity operation if (uptodate == disks) + * 2/ finish a check parity operation and act on the result + */ if (failed == 0) { - BUG_ON(uptodate != disks); - compute_parity5(sh, CHECK_PARITY); - uptodate--; - if (page_is_zero(sh->dev[sh->pd_idx].page)) { - /* parity is correct (on disc, not in buffer any more) */ - set_bit(STRIPE_INSYNC, &sh->state); - } else { - conf->mddev->resync_mismatches += STRIPE_SECTORS; - if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) - /* don't try to repair!! */ + if (!test_bit(STRIPE_OP_CHECK, &sh->state)) { + BUG_ON(uptodate != disks); + set_bit(STRIPE_OP_CHECK, &sh->state); + set_bit(STRIPE_OP_CHECK_Gen, &sh->ops.state); + clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags); + sh->ops.pending++; + uptodate--; + } else if (test_and_clear_bit(STRIPE_OP_CHECK_Done, &sh->ops.state)) { + clear_bit(STRIPE_OP_CHECK, &sh->state); + + if (test_and_clear_bit(STRIPE_OP_CHECK_IsZero, + &sh->ops.state)) + /* parity is correct (on disc, not in buffer any more) */ set_bit(STRIPE_INSYNC, &sh->state); else { - compute_block(sh, sh->pd_idx); - uptodate++; + conf->mddev->resync_mismatches += STRIPE_SECTORS; + if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) + /* don't try to repair!! */ + set_bit(STRIPE_INSYNC, &sh->state); + else { + compute_block(sh, sh->pd_idx); + uptodate++; + } } } } - if (!test_bit(STRIPE_INSYNC, &sh->state)) { + + /* Wait for check parity operations to complete + * before write-back + */ + if (!test_bit(STRIPE_INSYNC, &sh->state) && + !test_bit(STRIPE_OP_CHECK, &sh->state)) { + /* either failed parity check, or recovery is happening */ if (failed==0) failed_num = sh->pd_idx; + dev = &sh->dev[failed_num]; BUG_ON(!test_bit(R5_UPTODATE, &dev->flags)); BUG_ON(uptodate != disks); - 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