From nobody Sat Feb 7 05:32:29 2026 Received: from dggsgout12.his.huawei.com (dggsgout12.his.huawei.com [45.249.212.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A67BB19258E; Wed, 31 Dec 2025 07:18:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165503; cv=none; b=Jzb2RwujIQ+XHpjBh1Cjmcb0xbM5+P716dVde7mEnJbQYwWTvy41gVLFq/+IXCYBwITU/WGBr//z0H3KnkOJWpqC0tDxulvVyc3SW0GPSW/IiUfNj826O0K2IwbSGUkpXDhqiRzhAqMFaT69+nfxTtivWv3AVwOI2l7GTFDBaIs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165503; c=relaxed/simple; bh=ThK0u+K9PzIHd43MFCfhIvDzPPDCEJWJpIdu/T32+p0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=O/XOQnrZjqAODSrvakKif5PlMwL2UTkZVZD+I2EXbevIjJw07uAWs163jYPRiKhO59tbbX6J4wZM6sfIJbVVvBRktZttdtcnCeep8mk81jxC80Zr6O6CTyZRUrGuh5amaMgNSfQWRKmSYZqn/4AAmmtWA4Tj3hKodpo8JeZGNuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.177]) by dggsgout12.his.huawei.com (SkyGuard) with ESMTPS id 4dh1WH28rtzKHMcy; Wed, 31 Dec 2025 15:17:47 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 7D08340596; Wed, 31 Dec 2025 15:18:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.50.87.129]) by APP4 (Coremail) with SMTP id gCh0CgCX+PgvzlRpTtVyCA--.62349S5; Wed, 31 Dec 2025 15:18:17 +0800 (CST) From: Zheng Qixing To: song@kernel.org, yukuai@fnnas.com Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, houtao1@huawei.com, zhengqixing@huawei.com, linan122@h-partners.com Subject: [RFC PATCH 1/5] md: add helpers for requested sync action Date: Wed, 31 Dec 2025 15:09:48 +0800 Message-Id: <20251231070952.1233903-2-zhengqixing@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> References: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgCX+PgvzlRpTtVyCA--.62349S5 X-Coremail-Antispam: 1UD129KBjvJXoW3XFy7JFWxCFy7ur1DCF48Zwb_yoW7Ww4Dpa yft3Z0kr4UXFWfXFWxta4DAaySvr1IqrZ7trW7W34kJFn3KrsYkFy5W3ZrJr95ta4kZF45 Xa4DGF43ZFy3uw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBjb4IE77IF4wAFF20E14v26ryj6rWUM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUGw A2048vs2IY020Ec7CjxVAFwI0_JFI_Gr1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMc Ij6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVW8Jr0_Cr1UMcvjeVCFs4IE7xkE bVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwI xGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480 Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7 IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k2 6cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxV AFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07UKg4fUUUUU= X-CM-SenderInfo: x2kh0wptl0x03j6k3tpzhluzxrxghudrp/ Content-Type: text/plain; charset="utf-8" From: Zheng Qixing Add helpers for handling requested sync action. In handle_requested_sync_action(), add mutual exclusivity checks between check/repair operations. This prevents the scenario where one operation is requested, but before MD_RECOVERY_RUNNING is set, another operation is requested, resulting in neither an EBUSY return nor proper execution of the second operation. Signed-off-by: Zheng Qixing --- drivers/md/md.c | 87 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 5df2220b1bd1..ccaa2e6fe079 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -665,6 +665,59 @@ void mddev_put(struct mddev *mddev) spin_unlock(&all_mddevs_lock); } =20 +static int __handle_requested_sync_action(struct mddev *mddev, + enum sync_action action) +{ + switch (action) { + case ACTION_CHECK: + set_bit(MD_RECOVERY_CHECK, &mddev->recovery); + fallthrough; + case ACTION_REPAIR: + set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + set_bit(MD_RECOVERY_SYNC, &mddev->recovery); + return 0; + default: + return -EINVAL; + } +} + +static int handle_requested_sync_action(struct mddev *mddev, + enum sync_action action) +{ + if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) + return -EBUSY; + return __handle_requested_sync_action(mddev, action); +} + +static enum sync_action __get_recovery_sync_action(struct mddev *mddev) +{ + if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) + return ACTION_CHECK; + if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) + return ACTION_REPAIR; + return ACTION_RESYNC; +} + +static enum sync_action get_recovery_sync_action(struct mddev *mddev) +{ + return __get_recovery_sync_action(mddev); +} + +static void init_recovery_position(struct mddev *mddev) +{ + mddev->resync_min =3D 0; +} + +static void set_requested_position(struct mddev *mddev, sector_t value) +{ + mddev->resync_min =3D value; +} + +static sector_t get_requested_position(struct mddev *mddev) +{ + return mddev->resync_min; +} + static void md_safemode_timeout(struct timer_list *t); static void md_start_sync(struct work_struct *ws); =20 @@ -781,7 +834,7 @@ int mddev_init(struct mddev *mddev) mddev->reshape_position =3D MaxSector; mddev->reshape_backwards =3D 0; mddev->last_sync_action =3D ACTION_IDLE; - mddev->resync_min =3D 0; + init_recovery_position(mddev); mddev->resync_max =3D MaxSector; mddev->level =3D LEVEL_NONE; =20 @@ -5101,17 +5154,9 @@ enum sync_action md_sync_action(struct mddev *mddev) if (test_bit(MD_RECOVERY_RECOVER, &recovery)) return ACTION_RECOVER; =20 - if (test_bit(MD_RECOVERY_SYNC, &recovery)) { - /* - * MD_RECOVERY_CHECK must be paired with - * MD_RECOVERY_REQUESTED. - */ - if (test_bit(MD_RECOVERY_CHECK, &recovery)) - return ACTION_CHECK; - if (test_bit(MD_RECOVERY_REQUESTED, &recovery)) - return ACTION_REPAIR; - return ACTION_RESYNC; - } + /* MD_RECOVERY_CHECK must be paired with MD_RECOVERY_REQUESTED. */ + if (test_bit(MD_RECOVERY_SYNC, &recovery)) + return get_recovery_sync_action(mddev); =20 /* * MD_RECOVERY_NEEDED or MD_RECOVERY_RUNNING is set, however, no @@ -5300,11 +5345,10 @@ action_store(struct mddev *mddev, const char *page,= size_t len) set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); break; case ACTION_CHECK: - set_bit(MD_RECOVERY_CHECK, &mddev->recovery); - fallthrough; case ACTION_REPAIR: - set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); - set_bit(MD_RECOVERY_SYNC, &mddev->recovery); + ret =3D handle_requested_sync_action(mddev, action); + if (ret) + goto out; fallthrough; case ACTION_RESYNC: case ACTION_IDLE: @@ -6783,7 +6827,7 @@ static void md_clean(struct mddev *mddev) mddev->dev_sectors =3D 0; mddev->raid_disks =3D 0; mddev->resync_offset =3D 0; - mddev->resync_min =3D 0; + init_recovery_position(mddev); mddev->resync_max =3D MaxSector; mddev->reshape_position =3D MaxSector; /* we still need mddev->external in export_rdev, do not clear it yet */ @@ -9370,7 +9414,7 @@ static sector_t md_sync_position(struct mddev *mddev,= enum sync_action action) switch (action) { case ACTION_CHECK: case ACTION_REPAIR: - return mddev->resync_min; + return get_requested_position(mddev); case ACTION_RESYNC: if (!mddev->bitmap) return mddev->resync_offset; @@ -9795,10 +9839,11 @@ void md_do_sync(struct md_thread *thread) if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* We completed so min/max setting can be forgotten if used. */ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) - mddev->resync_min =3D 0; + set_requested_position(mddev, 0); mddev->resync_max =3D MaxSector; - } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) - mddev->resync_min =3D mddev->curr_resync_completed; + } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { + set_requested_position(mddev, mddev->curr_resync_completed); + } set_bit(MD_RECOVERY_DONE, &mddev->recovery); mddev->curr_resync =3D MD_RESYNC_NONE; spin_unlock(&mddev->lock); --=20 2.39.2 From nobody Sat Feb 7 05:32:29 2026 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 865A2312809; Wed, 31 Dec 2025 07:18:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165506; cv=none; b=dE7+UwvZrlqYDb1QDqD3IRMtbcua22YEHYn4FYimCUUirqb/e5k6EL3nky+ExTq/Laa8p3KTzGiIKqKLLziRzId/8fS+YEi26HnrKjWCn8bW3y/y2NLUWfsdA/U4vrhQdrJsTAdwpLD6kEl2G7qlFPFRHfyfXSongRyvclPpKO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165506; c=relaxed/simple; bh=wD8FHpHqkX5jNbiYy0DINKIaJwKn7zGymIepGLy+GOs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=o9S9/lMYhN9jp5cSUJSg+6EL2dm1+oihZFY4y7HAU/+FW8K5VSc1iLZSyJ10p9TjnsA8SgfqbB0dK33ZjEkkmFyL4zatB3Nfl2U0PJIJUyrzTBrieh7IOLf3BN1LkijMhDZjLwOs0Fo/FU6v8jfEAkIdlH0TYZET7KSgbP+fl+4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.170]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4dh1Vv3Q97zYQtpK; Wed, 31 Dec 2025 15:17:27 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 82C9E4056C; Wed, 31 Dec 2025 15:18:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.50.87.129]) by APP4 (Coremail) with SMTP id gCh0CgCX+PgvzlRpTtVyCA--.62349S6; Wed, 31 Dec 2025 15:18:17 +0800 (CST) From: Zheng Qixing To: song@kernel.org, yukuai@fnnas.com Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, houtao1@huawei.com, zhengqixing@huawei.com, linan122@h-partners.com Subject: [RFC PATCH 2/5] md: clear stale sync flags when frozen before sync starts Date: Wed, 31 Dec 2025 15:09:49 +0800 Message-Id: <20251231070952.1233903-3-zhengqixing@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> References: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgCX+PgvzlRpTtVyCA--.62349S6 X-Coremail-Antispam: 1UD129KBjvdXoW7GFyfCF43GF4ftr4fCw17ZFb_yoWDXwcEkF WUA34xWr409FWjgr1qv3WYgry5JFn3WF17WF4Sv3yrZasrur1xGrnYy3W5uw4UZws0kr9x K3yDG3W3trs7KjkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUIcSsGvfJTRUUUbf8YFVCjjxCrM7AC8VAFwI0_Wr0E3s1l1xkIjI8I6I8E6xAIw20E Y4v20xvaj40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r15M2 8IrcIa0xkI8VCY1x0267AKxVW8JVW5JwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK 021l84ACjcxK6xIIjxv20xvE14v26F1j6w1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r 4UJVWxJr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_ GcCE3s1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx 0E2Ix0cI8IcVAFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r4UJVWxJr1lOx8S6xCaFVCjc4AY 6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkF7I0En4kS14v26r1q6r43MxAIw28IcxkI7VAKI4 8JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xv wVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjx v20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20E Y4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267 AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU82LvtUUUUU== X-CM-SenderInfo: x2kh0wptl0x03j6k3tpzhluzxrxghudrp/ Content-Type: text/plain; charset="utf-8" From: Zheng Qixing In md_check_recovery(), add clearing of all sync flags when sync is not running. This fixes the issue where a sync operation is requested, then 'frozen' is executed before MD_RECOVERY_RUNNING is set, leaving stale operation flags that cause subsequent operations to fail with EBUSY. Signed-off-by: Zheng Qixing --- drivers/md/md.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index ccaa2e6fe079..52e09a9a9288 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -10336,6 +10336,9 @@ void md_check_recovery(struct mddev *mddev) queue_work(md_misc_wq, &mddev->sync_work); } else { clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery); + clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); + clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); wake_up(&resync_wait); } =20 --=20 2.39.2 From nobody Sat Feb 7 05:32:29 2026 Received: from dggsgout11.his.huawei.com (dggsgout11.his.huawei.com [45.249.212.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F54831281E; Wed, 31 Dec 2025 07:18:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165507; cv=none; b=d4JqW5nUuh9HuFJQSzogf5hgj5fAWXsdU4XH9iAL8Y3mTSrTWLmzZed0WNGLq22x5zImYICQcuVL5tUNKUI+kz+ZBN/sOmCaiWB8pLvZnW3H7+zJS6CLLE5xEL0p63Hzh0UTr2NgTtmbILkA/e1x7UzjcD93oEtJrQmor6w9FMo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165507; c=relaxed/simple; bh=kuTuoLRmx5kcg7dEJWeHlNg35pF688C2AAva8VDTaqM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NoBU1f0JCdoxZj/0VJFZ62Y6vC0orQXPZ/R3lMEzTjg1ihDDIfUiJwWIluT9cCqd8VAWmoBjt6t7NaFwHEFPoQBzdT/fsubgBsXNbHPmQKZqbEQhD8tGgL3H8DMf9ibaOr4GMDEnd7NtcF479GlsZ1qEGIRODq1YmC+WpIgskFA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=none smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.198]) by dggsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4dh1Vv46k1zYQtpK; Wed, 31 Dec 2025 15:17:27 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id 9CB1940576; Wed, 31 Dec 2025 15:18:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.50.87.129]) by APP4 (Coremail) with SMTP id gCh0CgCX+PgvzlRpTtVyCA--.62349S7; Wed, 31 Dec 2025 15:18:17 +0800 (CST) From: Zheng Qixing To: song@kernel.org, yukuai@fnnas.com Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, houtao1@huawei.com, zhengqixing@huawei.com, linan122@h-partners.com Subject: [RFC PATCH 3/5] md: simplify sync action print in status_resync Date: Wed, 31 Dec 2025 15:09:50 +0800 Message-Id: <20251231070952.1233903-4-zhengqixing@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> References: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgCX+PgvzlRpTtVyCA--.62349S7 X-Coremail-Antispam: 1UD129KBjvJXoW7ZF43Wr1rCr43JFyfuFWrAFb_yoW8Wr1kpF WfAF98urWkJFyfJ3y7t348ZFWrGF1Ut347AF9xu3y5ZF1Sgas5KFyq9a1UXryDGr9Yqan8 Xa4kGw45uFyjkw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBjb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUWw A2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMc Ij6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVW8Jr0_Cr1UMcvjeVCFs4IE7xkE bVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20xvY0x0EwI xGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480 Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7 IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k2 6cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxV AFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07Upc_-UUUUU= X-CM-SenderInfo: x2kh0wptl0x03j6k3tpzhluzxrxghudrp/ Content-Type: text/plain; charset="utf-8" From: Zheng Qixing No functional change, just code cleanup to make it easier to add new sync actions later. Signed-off-by: Zheng Qixing --- drivers/md/md.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 52e09a9a9288..9eeab5258189 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8684,6 +8684,8 @@ static int status_resync(struct seq_file *seq, struct= mddev *mddev) sector_t rt, curr_mark_cnt, resync_mark_cnt; int scale, recovery_active; unsigned int per_milli; + enum sync_action action; + const char *sync_action_name; =20 if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) @@ -8765,13 +8767,13 @@ static int status_resync(struct seq_file *seq, stru= ct mddev *mddev) seq_printf(seq, "."); seq_printf(seq, "] "); } - seq_printf(seq, " %s =3D%3u.%u%% (%llu/%llu)", - (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)? - "reshape" : - (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)? - "check" : - (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? - "resync" : "recovery"))), + + action =3D md_sync_action(mddev); + if (action =3D=3D ACTION_RECOVER) + sync_action_name =3D "recovery"; + else + sync_action_name =3D md_sync_action_name(action); + seq_printf(seq, " %s =3D%3u.%u%% (%llu/%llu)", sync_action_name, per_milli/10, per_milli % 10, (unsigned long long) resync/2, (unsigned long long) max_sectors/2); --=20 2.39.2 From nobody Sat Feb 7 05:32:29 2026 Received: from dggsgout12.his.huawei.com (dggsgout12.his.huawei.com [45.249.212.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A68821E3DDE; Wed, 31 Dec 2025 07:18:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165502; cv=none; b=CkZHNrqhTSKMO5BL0w7lbj7TqGa539EIil2RZV/ELb+qWBc/Mqoox9Zlei47f0nNsJndDjopkFLIRktElycEFgIPTM81JtaxRxfEpUTJImCToDXixg4l+1Kkymh6sR4C+Wc36rtgRX7Nf/4FTNz026EJOkL6w8ynheEzH1GuBlM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165502; c=relaxed/simple; bh=5fhhdDqGvZE6TNpB2GUAOlc5+/XdCqYefr6aCqA7TFQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=IkUI9j86Yuo6IuOLW6SXsVEPIAcRRrIQSiUcsPlfSx1DCvtYes+vk3UZk6RZsjA9uJeaxuoEkXQ18uS0AA9JJ+ssYWB1YHg/nVLyPy/2OZwKGAhU30I3YwpuLfjAqdYr6sGdEKwwsELsedRY6wgtx5ge8xQ3IeyX1nZaR/caRsI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.170]) by dggsgout12.his.huawei.com (SkyGuard) with ESMTPS id 4dh1WH3chKzKHMcr; Wed, 31 Dec 2025 15:17:47 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id AEA994056B; Wed, 31 Dec 2025 15:18:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.50.87.129]) by APP4 (Coremail) with SMTP id gCh0CgCX+PgvzlRpTtVyCA--.62349S8; Wed, 31 Dec 2025 15:18:17 +0800 (CST) From: Zheng Qixing To: song@kernel.org, yukuai@fnnas.com Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, houtao1@huawei.com, zhengqixing@huawei.com, linan122@h-partners.com Subject: [RFC PATCH 4/5] md: introduce MAX_RAID_DISKS macro to replace magic number Date: Wed, 31 Dec 2025 15:09:51 +0800 Message-Id: <20251231070952.1233903-5-zhengqixing@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> References: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgCX+PgvzlRpTtVyCA--.62349S8 X-Coremail-Antispam: 1UD129KBjvJXoW7trWUtry7WF1fWrWkZFW8JFb_yoW8WrW3pa 97WF9xuw1rZw4UKw1kXrykuFy5Zw13KrWDKrWa939avF90yr15uFZ8Ga4DJr95WF95ZF12 vrs0gw45W348Kr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBFb4IE77IF4wAFF20E14v26rWj6s0DM7CY07I20VC2zVCF04k2 6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI8067AKxVWUAV Cq3wA2048vs2IY020Ec7CjxVAFwI0_Xr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0 rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267 AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E 14v26rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7 xfMcIj6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVW8Jr0_Cr1UMcvjeVCFs4IE 7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x0262kKe7AKxVWUtVW8ZwCF04k20xvY0x 0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E 7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcV C0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF 04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7 CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07UJKsUUUUUU= X-CM-SenderInfo: x2kh0wptl0x03j6k3tpzhluzxrxghudrp/ Content-Type: text/plain; charset="utf-8" From: Zheng Qixing Define MAX_RAID_DISKS macro for the maximum number of RAID disks. No functional change. Signed-off-by: Zheng Qixing --- drivers/md/md.c | 4 ++-- drivers/md/md.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 9eeab5258189..d2f136706f6c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1888,7 +1888,7 @@ static int super_1_load(struct md_rdev *rdev, struct = md_rdev *refdev, int minor_ =20 if (sb->magic !=3D cpu_to_le32(MD_SB_MAGIC) || sb->major_version !=3D cpu_to_le32(1) || - le32_to_cpu(sb->max_dev) > (4096-256)/2 || + le32_to_cpu(sb->max_dev) > MAX_RAID_DISKS || le64_to_cpu(sb->super_offset) !=3D rdev->sb_start || (le32_to_cpu(sb->feature_map) & ~MD_FEATURE_ALL) !=3D 0) return -EINVAL; @@ -2065,7 +2065,7 @@ static int super_1_validate(struct mddev *mddev, stru= ct md_rdev *freshest, struc mddev->resync_offset =3D le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); =20 - mddev->max_disks =3D (4096-256)/2; + mddev->max_disks =3D MAX_RAID_DISKS; =20 if (!mddev->logical_block_size) mddev->logical_block_size =3D le32_to_cpu(sb->logical_block_size); diff --git a/drivers/md/md.h b/drivers/md/md.h index a083f37374d0..6a4af4a1959c 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -22,6 +22,7 @@ #include =20 #define MaxSector (~(sector_t)0) +#define MAX_RAID_DISKS ((4096-256)/2) =20 enum md_submodule_type { MD_PERSONALITY =3D 0, --=20 2.39.2 From nobody Sat Feb 7 05:32:29 2026 Received: from dggsgout12.his.huawei.com (dggsgout12.his.huawei.com [45.249.212.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A681D1CEAC2; Wed, 31 Dec 2025 07:18:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165502; cv=none; b=j+glU2orAHvPabK6dKl3Hd2JNro+pzF7WAFVrb1cZVA4vrJM3gFn/vAGFM9ppV+639xSIJSl3AgXiLiJKpFDvPNfRZLCURI1o+gDE1JgvNxgt42pOIlwxC7cKLxawf5ZKHMYg268nPlbK6MWOS4uPmEogEDgNrzaYdqu2t5omWs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767165502; c=relaxed/simple; bh=xvMkvv1CfrPnQY0YUvVPwv7e8oiHKIigX08Y0r5/5to=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b1MRiRQWWLpclPyGtqz3eBQUQYIvP9hjw6xSCM2vdkR31QZ/ajtCbAz0TsMPD09/ChsICb+MlfRZLYKjjsMIhR0/vb+7A+HOXNj8+FU2P3drWdKKVW3GLH/UVtirgAoYIkChOTPDtrvS1oL4yiKOVVhhwrkBwb29X+Xg3XmG8uU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com; spf=pass smtp.mailfrom=huaweicloud.com; arc=none smtp.client-ip=45.249.212.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=huaweicloud.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huaweicloud.com Received: from mail.maildlp.com (unknown [172.19.163.170]) by dggsgout12.his.huawei.com (SkyGuard) with ESMTPS id 4dh1WH47lWzKHMcr; Wed, 31 Dec 2025 15:17:47 +0800 (CST) Received: from mail02.huawei.com (unknown [10.116.40.128]) by mail.maildlp.com (Postfix) with ESMTP id C14C24056C; Wed, 31 Dec 2025 15:18:17 +0800 (CST) Received: from huaweicloud.com (unknown [10.50.87.129]) by APP4 (Coremail) with SMTP id gCh0CgCX+PgvzlRpTtVyCA--.62349S9; Wed, 31 Dec 2025 15:18:17 +0800 (CST) From: Zheng Qixing To: song@kernel.org, yukuai@fnnas.com Cc: linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, yi.zhang@huawei.com, yangerkun@huawei.com, houtao1@huawei.com, zhengqixing@huawei.com, linan122@h-partners.com Subject: [RFC PATCH 5/5] md/raid1: introduce rectify action to repair badblocks Date: Wed, 31 Dec 2025 15:09:52 +0800 Message-Id: <20251231070952.1233903-6-zhengqixing@huaweicloud.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> References: <20251231070952.1233903-1-zhengqixing@huaweicloud.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: gCh0CgCX+PgvzlRpTtVyCA--.62349S9 X-Coremail-Antispam: 1UD129KBjvAXoW3ZF1fCry3urWxKF13Kw17KFg_yoW8CFWxJo Z7Cw129F1rJr1furyftwnxtF4fuan8J34fAw1rurZ0kr12gw4Ygw17GrW3ZryaqrsI9rWU X3sFqr1IvFWfZr48n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYA7kC6x804xWl14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK 8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF 0E3s1l82xGYIkIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vE j48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxV AFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x02 67AKxVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG6I 80ewAv7VC0I7IYx2IY67AKxVWUXVWUAwAv7VC2z280aVAFwI0_Gr1j6F4UJwAm72CE4IkC 6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lc7CjxVAaw2AFwI0_Jw0_GFyl42xK82IYc2 Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s02 6x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0x vE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU11v3UUUUUU== X-CM-SenderInfo: x2kh0wptl0x03j6k3tpzhluzxrxghudrp/ Content-Type: text/plain; charset="utf-8" From: Zheng Qixing Add support for repairing known badblocks in RAID1. When disks have known badblocks (shown in sysfs bad_blocks), data can be read from other healthy disks in the array and written to repair the badblock areas and clear it in bad_blocks. echo rectify > sync_action can trigger this action. Signed-off-by: Zheng Qixing --- drivers/md/md.c | 80 ++++++++++-- drivers/md/md.h | 16 +++ drivers/md/raid1.c | 308 ++++++++++++++++++++++++++++++++++++++++++++- drivers/md/raid1.h | 1 + 4 files changed, 394 insertions(+), 11 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index d2f136706f6c..f5844cfb78fc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -74,6 +74,7 @@ static const char *action_name[NR_SYNC_ACTIONS] =3D { [ACTION_RECOVER] =3D "recover", [ACTION_CHECK] =3D "check", [ACTION_REPAIR] =3D "repair", + [ACTION_RECTIFY] =3D "rectify", [ACTION_RESHAPE] =3D "reshape", [ACTION_FROZEN] =3D "frozen", [ACTION_IDLE] =3D "idle", @@ -665,6 +666,29 @@ void mddev_put(struct mddev *mddev) spin_unlock(&all_mddevs_lock); } =20 +static int raid1_badblocks_precheck(struct mddev *mddev) +{ + struct md_rdev *rdev; + int valid_disks =3D 0; + int ret =3D -EINVAL; + + if (mddev->level !=3D 1) { + pr_err("md/raid1:%s requires raid1 array\n", mdname(mddev)); + return -EINVAL; + } + + rdev_for_each(rdev, mddev) { + if (rdev->raid_disk < 0 || + test_bit(Faulty, &rdev->flags)) + continue; + valid_disks++; + } + if (valid_disks >=3D 2) + ret =3D 0; + + return ret; +} + static int __handle_requested_sync_action(struct mddev *mddev, enum sync_action action) { @@ -684,9 +708,23 @@ static int __handle_requested_sync_action(struct mddev= *mddev, static int handle_requested_sync_action(struct mddev *mddev, enum sync_action action) { + int ret; + if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) return -EBUSY; - return __handle_requested_sync_action(mddev, action); + + switch (action) { + case ACTION_RECTIFY: + ret =3D raid1_badblocks_precheck(mddev); + if (ret) + return ret; + set_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery); + set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + set_bit(MD_RECOVERY_SYNC, &mddev->recovery); + return 0; + default: + return __handle_requested_sync_action(mddev, action); + } } =20 static enum sync_action __get_recovery_sync_action(struct mddev *mddev) @@ -700,21 +738,34 @@ static enum sync_action __get_recovery_sync_action(st= ruct mddev *mddev) =20 static enum sync_action get_recovery_sync_action(struct mddev *mddev) { + if (test_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery)) + return ACTION_RECTIFY; return __get_recovery_sync_action(mddev); } =20 static void init_recovery_position(struct mddev *mddev) { mddev->resync_min =3D 0; + mddev->rectify_min =3D 0; +} + +static inline void clear_badblock_md_flags(struct mddev *mddev) +{ + clear_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery); } =20 static void set_requested_position(struct mddev *mddev, sector_t value) { - mddev->resync_min =3D value; + if (test_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery)) + mddev->rectify_min =3D value; + else + mddev->resync_min =3D value; } =20 static sector_t get_requested_position(struct mddev *mddev) { + if (test_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery)) + return mddev->rectify_min; return mddev->resync_min; } =20 @@ -5154,7 +5205,10 @@ enum sync_action md_sync_action(struct mddev *mddev) if (test_bit(MD_RECOVERY_RECOVER, &recovery)) return ACTION_RECOVER; =20 - /* MD_RECOVERY_CHECK must be paired with MD_RECOVERY_REQUESTED. */ + /* + * MD_RECOVERY_CHECK/MD_RECOVERY_BADBLOCKS_RECTIFY must be + * paired with MD_RECOVERY_REQUESTED. + */ if (test_bit(MD_RECOVERY_SYNC, &recovery)) return get_recovery_sync_action(mddev); =20 @@ -5319,6 +5373,7 @@ action_store(struct mddev *mddev, const char *page, s= ize_t len) break; case ACTION_RESHAPE: case ACTION_RECOVER: + case ACTION_RECTIFY: case ACTION_CHECK: case ACTION_REPAIR: case ACTION_RESYNC: @@ -5344,6 +5399,7 @@ action_store(struct mddev *mddev, const char *page, s= ize_t len) clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); break; + case ACTION_RECTIFY: case ACTION_CHECK: case ACTION_REPAIR: ret =3D handle_requested_sync_action(mddev, action); @@ -9362,6 +9418,7 @@ static sector_t md_sync_max_sectors(struct mddev *mdd= ev, { switch (action) { case ACTION_RESYNC: + case ACTION_RECTIFY: case ACTION_CHECK: case ACTION_REPAIR: atomic64_set(&mddev->resync_mismatches, 0); @@ -9414,6 +9471,7 @@ static sector_t md_sync_position(struct mddev *mddev,= enum sync_action action) struct md_rdev *rdev; =20 switch (action) { + case ACTION_RECTIFY: case ACTION_CHECK: case ACTION_REPAIR: return get_requested_position(mddev); @@ -10039,6 +10097,7 @@ static bool md_choose_sync_action(struct mddev *mdd= ev, int *spares) clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + clear_badblock_md_flags(mddev); =20 /* Start new recovery. */ set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); @@ -10096,10 +10155,14 @@ static void md_start_sync(struct work_struct *ws) if (spares && md_bitmap_enabled(mddev, true)) mddev->bitmap_ops->write_all(mddev); =20 - name =3D test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) ? - "reshape" : "resync"; - rcu_assign_pointer(mddev->sync_thread, - md_register_thread(md_do_sync, mddev, name)); + if (!is_badblocks_recovery_requested(mddev) || + !raid1_badblocks_precheck(mddev)) { + name =3D test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) ? + "reshape" : "resync"; + rcu_assign_pointer(mddev->sync_thread, + md_register_thread(md_do_sync, mddev, name)); + } + if (!mddev->sync_thread) { pr_warn("%s: could not start resync thread...\n", mdname(mddev)); @@ -10127,6 +10190,7 @@ static void md_start_sync(struct work_struct *ws) clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery); + clear_badblock_md_flags(mddev); mddev_unlock(mddev); /* * md_start_sync was triggered by MD_RECOVERY_NEEDED, so we should @@ -10341,6 +10405,7 @@ void md_check_recovery(struct mddev *mddev) clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); + clear_badblock_md_flags(mddev); wake_up(&resync_wait); } =20 @@ -10391,6 +10456,7 @@ void md_reap_sync_thread(struct mddev *mddev) clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); + clear_badblock_md_flags(mddev); clear_bit(MD_RECOVERY_LAZY_RECOVER, &mddev->recovery); /* * We call mddev->cluster_ops->update_size here because sync_size could diff --git a/drivers/md/md.h b/drivers/md/md.h index 6a4af4a1959c..58f320b19bba 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -98,6 +98,13 @@ enum sync_action { * are inconsistent data, */ ACTION_REPAIR, + /* + * Represent by MD_RECOVERY_SYNC | MD_RECOVERY_REQUESTED | + * MD_RECOVERY_BADBLOCKS_RECTIFY, start when user echo "rectify" + * to sysfs api sync_action, used to repair the badblocks acked + * in bad table; + */ + ACTION_RECTIFY, /* * Represent by MD_RECOVERY_RESHAPE, start when new member disk is added * to the conf, notice that this is different from spares or @@ -524,6 +531,7 @@ struct mddev { sector_t resync_offset; sector_t resync_min; /* user requested sync * starts here */ + sector_t rectify_min; sector_t resync_max; /* resync should pause * when it gets here */ =20 @@ -664,6 +672,8 @@ enum recovery_flags { MD_RESYNCING_REMOTE, /* raid456 lazy initial recover */ MD_RECOVERY_LAZY_RECOVER, + /* try to repair acked badblocks*/ + MD_RECOVERY_BADBLOCKS_RECTIFY, }; =20 enum md_ro_state { @@ -1016,6 +1026,12 @@ static inline void mddev_unlock_and_resume(struct md= dev *mddev) mddev_resume(mddev); } =20 +static inline bool is_badblocks_recovery_requested(struct mddev *mddev) +{ + return test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && + test_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery); +} + struct mdu_array_info_s; struct mdu_disk_info_s; =20 diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 00120c86c443..f304161bc0ce 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -176,7 +176,8 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *d= ata) * If this is a user-requested check/repair, allocate * RESYNC_PAGES for each bio. */ - if (test_bit(MD_RECOVERY_REQUESTED, &conf->mddev->recovery)) + if (test_bit(MD_RECOVERY_REQUESTED, &conf->mddev->recovery) && + !is_badblocks_recovery_requested(conf->mddev)) need_pages =3D conf->raid_disks * 2; else need_pages =3D 1; @@ -2380,6 +2381,301 @@ static void sync_request_write(struct mddev *mddev,= struct r1bio *r1_bio) put_sync_write_buf(r1_bio); } =20 +static void end_rectify_read(struct bio *bio) +{ + struct r1bio *r1_bio =3D get_resync_r1bio(bio); + struct r1conf *conf =3D r1_bio->mddev->private; + struct md_rdev *rdev; + struct bio *next_bio; + bool all_fail =3D true; + int i; + + update_head_pos(r1_bio->read_disk, r1_bio); + + if (!bio->bi_status) { + set_bit(R1BIO_Uptodate, &r1_bio->state); + goto out; + } + + for (i =3D r1_bio->read_disk + 1; i < conf->raid_disks; i++) { + rdev =3D conf->mirrors[i].rdev; + if (!rdev || test_bit(Faulty, &rdev->flags)) + continue; + + next_bio =3D r1_bio->bios[i]; + if (next_bio->bi_end_io =3D=3D end_rectify_read) { + next_bio->bi_opf &=3D ~MD_FAILFAST; + r1_bio->read_disk =3D i; + all_fail =3D false; + break; + } + } + + if (unlikely(all_fail)) { + md_done_sync(r1_bio->mddev, r1_bio->sectors); + md_sync_error(r1_bio->mddev); + put_buf(r1_bio); + return; + } +out: + reschedule_retry(r1_bio); +} + +static void end_rectify_write(struct bio *bio) +{ + struct r1bio *r1_bio =3D get_resync_r1bio(bio); + + if (atomic_dec_and_test(&r1_bio->remaining)) { + /* + * Rectify only attempts to clear acked bad + * blocks, and it does not set bad blocks in + * cases of R1BIO_WriteError. + * Here we reuse R1BIO_MadeGood flag, which + * does not guarantee that all write I/Os + * actually succeeded. + */ + set_bit(R1BIO_MadeGood, &r1_bio->state); + reschedule_retry(r1_bio); + } +} + +static void submit_rectify_read(struct r1bio *r1_bio) +{ + struct bio *bio; + + bio =3D r1_bio->bios[r1_bio->read_disk]; + bio->bi_opf &=3D ~MD_FAILFAST; + bio->bi_status =3D 0; + submit_bio_noacct(bio); +} + +static void rectify_request_write(struct mddev *mddev, struct r1bio *r1_bi= o) +{ + struct r1conf *conf =3D mddev->private; + struct bio *wbio =3D NULL; + int wcnt =3D 0; + int i; + + if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) { + submit_rectify_read(r1_bio); + return; + } + + atomic_set(&r1_bio->remaining, 0); + for (i =3D 0; i < conf->raid_disks; i++) { + wbio =3D r1_bio->bios[i]; + if (wbio->bi_end_io =3D=3D end_rectify_write) { + atomic_inc(&r1_bio->remaining); + wcnt++; + submit_bio_noacct(wbio); + } + } + + if (unlikely(!wcnt)) { + md_done_sync(r1_bio->mddev, r1_bio->sectors); + put_buf(r1_bio); + } +} + +static void handle_rectify_write_finished(struct r1conf *conf, struct r1bi= o *r1_bio) +{ + struct md_rdev *rdev; + struct bio *bio; + int i; + + for (i =3D 0; i < conf->raid_disks; i++) { + rdev =3D conf->mirrors[i].rdev; + bio =3D r1_bio->bios[i]; + if (bio->bi_end_io =3D=3D NULL) + continue; + + if (!bio->bi_status && bio->bi_end_io =3D=3D end_rectify_write && + test_bit(R1BIO_MadeGood, &r1_bio->state)) { + rdev_clear_badblocks(rdev, r1_bio->sector, + r1_bio->sectors, 0); + } + } + + md_done_sync(r1_bio->mddev, r1_bio->sectors); + put_buf(r1_bio); +} + +static void handle_sync_write(struct mddev *mddev, struct r1bio *r1_bio) +{ + if (test_bit(R1BIO_BadBlocksRectify, &r1_bio->state)) + rectify_request_write(mddev, r1_bio); + else + sync_request_write(mddev, r1_bio); +} + +static void __handle_sync_write_finished(struct r1conf *conf, struct r1bio= *r1_bio); +static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *= r1_bio) +{ + if (test_bit(R1BIO_BadBlocksRectify, &r1_bio->state)) + handle_rectify_write_finished(conf, r1_bio); + else + __handle_sync_write_finished(conf, r1_bio); +} + +static sector_t get_badblocks_sync_sectors(struct mddev *mddev, sector_t s= ector_nr, + int *skipped, unsigned long *bad_disks) +{ + struct r1conf *conf =3D mddev->private; + sector_t nr_sectors =3D mddev->dev_sectors - sector_nr; + bool all_faulty =3D true; + struct md_rdev *rdev; + bool good =3D false; + int i; + + *skipped =3D 0; + for (i =3D 0; i < conf->raid_disks; i++) { + sector_t first_bad; + sector_t bad_sectors; + + rdev =3D conf->mirrors[i].rdev; + if (!rdev || test_bit(Faulty, &rdev->flags)) + continue; + + all_faulty =3D false; + if (is_badblock(rdev, sector_nr, nr_sectors, &first_bad, &bad_sectors)) { + if (first_bad <=3D sector_nr) { + set_bit(i, bad_disks); + nr_sectors =3D min(nr_sectors, first_bad + bad_sectors - sector_nr); + } else { + good =3D true; + nr_sectors =3D min(nr_sectors, first_bad - sector_nr); + } + } else { + good =3D true; + } + } + + if (all_faulty) { + *skipped =3D 1; + return 0; + } + + if (!good || !bitmap_weight(bad_disks, conf->raid_disks)) + *skipped =3D 1; + + /* make sure nr_sectors won't go across barrier unit boundary */ + return align_to_barrier_unit_end(sector_nr, nr_sectors); +} + +static sector_t get_next_sync_sector(struct mddev *mddev, sector_t sector_= nr, + int *skipped, unsigned long *bad_disks) +{ + sector_t nr_sectors; + + nr_sectors =3D get_badblocks_sync_sectors(mddev, sector_nr, + skipped, bad_disks); + if (!(*skipped) && nr_sectors > RESYNC_PAGES * (PAGE_SIZE >> 9)) + nr_sectors =3D RESYNC_PAGES * (PAGE_SIZE >> 9); + return nr_sectors; +} + +static struct r1bio *raid1_alloc_init_r1buf(struct r1conf *conf); +static struct r1bio *init_sync_badblocks_r1bio(struct mddev *mddev, + sector_t sector_nr, + sector_t nr_sectors, + unsigned long *bad_disks) +{ + struct r1conf *conf =3D mddev->private; + struct r1bio *r1_bio; + struct md_rdev *rdev; + int page_idx =3D 0; + struct bio *bio; + int i; + + r1_bio =3D raid1_alloc_init_r1buf(conf); + r1_bio->mddev =3D mddev; + r1_bio->sector =3D sector_nr; + r1_bio->sectors =3D nr_sectors; + r1_bio->state =3D 0; + r1_bio->read_disk =3D -1; + set_bit(R1BIO_IsSync, &r1_bio->state); + set_bit(R1BIO_BadBlocksRectify, &r1_bio->state); + + for (i =3D 0; i < conf->raid_disks; i++) { + rdev =3D conf->mirrors[i].rdev; + if (!rdev || test_bit(Faulty, &rdev->flags)) + continue; + + if (r1_bio->read_disk < 0 && !test_bit(i, bad_disks)) + r1_bio->read_disk =3D i; + + bio =3D r1_bio->bios[i]; + if (test_bit(i, bad_disks)) { + bio->bi_opf =3D REQ_OP_WRITE; + bio->bi_end_io =3D end_rectify_write; + } else { + bio->bi_opf =3D REQ_OP_READ; + bio->bi_end_io =3D end_rectify_read; + } + + atomic_inc(&rdev->nr_pending); + bio->bi_iter.bi_sector =3D sector_nr + rdev->data_offset; + bio_set_dev(bio, rdev->bdev); + if (test_bit(FailFast, &rdev->flags)) + bio->bi_opf |=3D MD_FAILFAST; + } + + if (unlikely(r1_bio->read_disk < 0)) { + put_buf(r1_bio); + return NULL; + } + + while (nr_sectors > 0 && page_idx < RESYNC_PAGES) { + int len =3D nr_sectors << 9 < PAGE_SIZE ? + nr_sectors << 9 : PAGE_SIZE; + struct resync_pages *rp; + + for (i =3D 0; i < conf->raid_disks; i++) { + bio =3D r1_bio->bios[i]; + rp =3D get_resync_pages(bio); + __bio_add_page(bio, resync_fetch_page(rp, page_idx), len, 0); + } + + nr_sectors -=3D len >> 9; + page_idx++; + } + + return r1_bio; +} + +static sector_t __badblocks_rectify(struct mddev *mddev, sector_t sector_n= r, + sector_t nr_sectors, + unsigned long *bad_disks) +{ + struct r1bio *r1_bio; + + r1_bio =3D init_sync_badblocks_r1bio(mddev, sector_nr, + nr_sectors, bad_disks); + if (!r1_bio) + return 0; + + submit_rectify_read(r1_bio); + return nr_sectors; +} + +static sector_t do_sync_badblocks_rectify(struct mddev *mddev, + sector_t sector_nr, int *skipped) +{ + DECLARE_BITMAP(bad_disks, MAX_RAID_DISKS); + struct r1conf *conf =3D mddev->private; + sector_t nr_sectors; + + bitmap_zero(bad_disks, MAX_RAID_DISKS); + nr_sectors =3D get_next_sync_sector(mddev, sector_nr, skipped, bad_disks); + + if (*skipped) { + lower_barrier(conf, sector_nr); + return nr_sectors; + } + + return __badblocks_rectify(mddev, sector_nr, nr_sectors, bad_disks); +} + /* * This is a kernel thread which: * @@ -2554,7 +2850,7 @@ static bool narrow_write_error(struct r1bio *r1_bio, = int i) return ok; } =20 -static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *= r1_bio) +static void __handle_sync_write_finished(struct r1conf *conf, struct r1bio= *r1_bio) { int m; int s =3D r1_bio->sectors; @@ -2728,7 +3024,7 @@ static void raid1d(struct md_thread *thread) test_bit(R1BIO_WriteError, &r1_bio->state)) handle_sync_write_finished(conf, r1_bio); else - sync_request_write(mddev, r1_bio); + handle_sync_write(mddev, r1_bio); } else if (test_bit(R1BIO_MadeGood, &r1_bio->state) || test_bit(R1BIO_WriteError, &r1_bio->state)) handle_write_finished(conf, r1_bio); @@ -2837,7 +3133,8 @@ static sector_t raid1_sync_request(struct mddev *mdde= v, sector_t sector_nr, /* before building a request, check if we can skip these blocks.. * This call the bitmap_start_sync doesn't actually record anything */ - if (!md_bitmap_start_sync(mddev, sector_nr, &sync_blocks, true) && + if (!is_badblocks_recovery_requested(mddev) && + !md_bitmap_start_sync(mddev, sector_nr, &sync_blocks, true) && !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)= ) { /* We can skip this block, and probably several more */ *skipped =3D 1; @@ -2863,6 +3160,9 @@ static sector_t raid1_sync_request(struct mddev *mdde= v, sector_t sector_nr, if (raise_barrier(conf, sector_nr)) return 0; =20 + if (is_badblocks_recovery_requested(mddev)) + return do_sync_badblocks_rectify(mddev, sector_nr, skipped); + r1_bio =3D raid1_alloc_init_r1buf(conf); =20 /* diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index c98d43a7ae99..6ca8bf808d69 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -184,6 +184,7 @@ enum r1bio_state { R1BIO_MadeGood, R1BIO_WriteError, R1BIO_FailFast, + R1BIO_BadBlocksRectify, }; =20 static inline int sector_to_idx(sector_t sector) --=20 2.39.2