From patchwork Mon Dec 8 21:57:46 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuri Tikhonov X-Patchwork-Id: 12862 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id A478CDE4C5 for ; Tue, 9 Dec 2008 09:10:14 +1100 (EST) X-Original-To: linuxppc-dev@ozlabs.org Delivered-To: linuxppc-dev@ozlabs.org Received: from ocean.emcraft.com (ocean.emcraft.com [213.221.7.182]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 72854DE57A for ; Tue, 9 Dec 2008 09:08:11 +1100 (EST) Received: from [172.17.0.11] (helo=iron.emcraft.com) by ocean.emcraft.com with esmtp (Exim 4.43) id 1L9oGC-00072a-W0; Tue, 09 Dec 2008 01:07:25 +0300 From: Yuri Tikhonov To: linux-raid@vger.kernel.org Subject: [PATCH 08/11] md: asynchronous handle_parity_check6 Date: Tue, 9 Dec 2008 00:57:46 +0300 User-Agent: KMail/1.9.4 MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200812090057.46788.yur@emcraft.com> Cc: linuxppc-dev@ozlabs.org, dan.j.williams@intel.com, wd@denx.de, dzu@denx.de, yanok@emcraft.com X-BeenThere: linuxppc-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org This patch introduces the state machine for handling the RAID-6 parities check and repair functionality. Signed-off-by: Yuri Tikhonov Signed-off-by: Ilya Yanok --- drivers/md/raid5.c | 163 +++++++++++++++++++++++++++++++++++----------------- 1 files changed, 110 insertions(+), 53 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f0b47bd..91e5438 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2621,91 +2621,148 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh, struct r6_state *r6s, struct page *tmp_page, int disks) { - int update_p = 0, update_q = 0; - struct r5dev *dev; + int i; + struct r5dev *devs[2] = {NULL, NULL}; int pd_idx = sh->pd_idx; int qd_idx = r6s->qd_idx; set_bit(STRIPE_HANDLE, &sh->state); BUG_ON(s->failed > 2); - BUG_ON(s->uptodate < disks); + /* Want to check and possibly repair P and Q. * However there could be one 'failed' device, in which * case we can only check one of them, possibly using the * other to generate missing data */ - /* If !tmp_page, we cannot do the calculations, - * but as we have set STRIPE_HANDLE, we will soon be called - * by stripe_handle with a tmp_page - just wait until then. - */ - if (tmp_page) { + switch (sh->check_state) { + case check_state_idle: + /* start a new check operation if there are < 2 failures */ if (s->failed == r6s->q_failed) { /* The only possible failed device holds 'Q', so it * makes sense to check P (If anything else were failed, * we would have used P to recreate it). */ - compute_block_1(sh, pd_idx, 1); - if (!page_is_zero(sh->dev[pd_idx].page)) { - compute_block_1(sh, pd_idx, 0); - update_p = 1; - } + sh->check_state = check_state_run; + set_bit(STRIPE_OP_CHECK_PP, &s->ops_request); + clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); + s->uptodate--; } if (!r6s->q_failed && s->failed < 2) { /* q is not failed, and we didn't use it to generate * anything, so it makes sense to check it */ - memcpy(page_address(tmp_page), - page_address(sh->dev[qd_idx].page), - STRIPE_SIZE); - compute_parity6(sh, UPDATE_PARITY); - if (memcmp(page_address(tmp_page), - page_address(sh->dev[qd_idx].page), - STRIPE_SIZE) != 0) { - clear_bit(STRIPE_INSYNC, &sh->state); - update_q = 1; - } + sh->check_state = check_state_run; + set_bit(STRIPE_OP_CHECK_QP, &s->ops_request); + clear_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); + s->uptodate--; } - if (update_p || update_q) { - conf->mddev->resync_mismatches += STRIPE_SECTORS; - if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) - /* don't try to repair!! */ - update_p = update_q = 0; + if (sh->check_state == check_state_run) { + break; } - /* now write out any block on a failed drive, - * or P or Q if they need it - */ + /* we have 2-disk failure */ + BUG_ON(s->failed != 2); + devs[0] = &sh->dev[r6s->failed_num[0]]; + devs[1] = &sh->dev[r6s->failed_num[1]]; + /* fall through */ + case check_state_compute_result: + sh->check_state = check_state_idle; - if (s->failed == 2) { - dev = &sh->dev[r6s->failed_num[1]]; - s->locked++; - set_bit(R5_LOCKED, &dev->flags); - set_bit(R5_Wantwrite, &dev->flags); + BUG_ON((devs[0] && !devs[1]) || + (!devs[0] && devs[1])); + + BUG_ON(s->uptodate < (disks - 1)); + + if (!devs[0]) { + if (s->failed >= 1) + devs[0] = &sh->dev[r6s->failed_num[0]]; + else + devs[0] = &sh->dev[pd_idx]; } - if (s->failed >= 1) { - dev = &sh->dev[r6s->failed_num[0]]; - s->locked++; - set_bit(R5_LOCKED, &dev->flags); - set_bit(R5_Wantwrite, &dev->flags); + if (!devs[1]) { + if (s->failed >= 2) + devs[1] = &sh->dev[r6s->failed_num[1]]; + else + devs[1] = &sh->dev[qd_idx]; } - if (update_p) { - dev = &sh->dev[pd_idx]; - s->locked++; - set_bit(R5_LOCKED, &dev->flags); - set_bit(R5_Wantwrite, &dev->flags); - } - if (update_q) { - dev = &sh->dev[qd_idx]; - s->locked++; - set_bit(R5_LOCKED, &dev->flags); - set_bit(R5_Wantwrite, &dev->flags); + BUG_ON(!test_bit(R5_UPTODATE, &devs[0]->flags) && + !test_bit(R5_UPTODATE, &devs[1]->flags)); + + /* check that a write has not made the stripe insync */ + if (test_bit(STRIPE_INSYNC, &sh->state)) + break; + + for (i=0; i < 2; i++) { + if (test_bit(R5_UPTODATE, &devs[i]->flags)) { + s->locked++; + set_bit(R5_LOCKED, &devs[i]->flags); + set_bit(R5_Wantwrite, &devs[i]->flags); + } } - clear_bit(STRIPE_DEGRADED, &sh->state); + clear_bit(STRIPE_DEGRADED, &sh->state); set_bit(STRIPE_INSYNC, &sh->state); + break; + case check_state_run: + break; /* we will be called again upon completion */ + case check_state_check_result: + sh->check_state = check_state_idle; + + /* if a failure occurred during the check operation, leave + * STRIPE_INSYNC not set and let the stripe be handled again + */ + if (s->failed > 1) { + break; + } + + /* handle a successful check operation, if parity is correct + * we are done. Otherwise update the mismatch count and repair + * parity if !MD_RECOVERY_CHECK + */ + if (sh->ops.zero_sum_result == 0 && + sh->ops.zero_qsum_result == 0) { + /* both parities are correct */ + if (!s->failed) { + set_bit(STRIPE_INSYNC, &sh->state); + } else { + sh->check_state = check_state_compute_result; + } + } else { + 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 { + sh->check_state = check_state_compute_run; + set_bit(STRIPE_COMPUTE_RUN, &sh->state); + set_bit(STRIPE_OP_COMPUTE_BLK, &s->ops_request); + if (sh->ops.zero_sum_result) { + set_bit(R5_Wantcompute, + &sh->dev[pd_idx].flags); + sh->ops.target = pd_idx; + s->uptodate++; + } else + sh->ops.target = -1; + if (sh->ops.zero_qsum_result) { + set_bit(R5_Wantcompute, + &sh->dev[qd_idx].flags); + sh->ops.target2 = qd_idx; + s->uptodate++; + } else + sh->ops.target2 = -1; + } + } + break; + case check_state_compute_run: + break; + default: + printk(KERN_ERR "%s: unknown check_state: %d sector: %llu\n", + __func__, sh->check_state, + (unsigned long long) sh->sector); + BUG(); } }