From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout11.his.huawei.com (canpmsgout11.his.huawei.com [113.46.200.226]) (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 822DC2C1584 for ; Tue, 1 Sep 2026 13:12:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.226 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268383; cv=none; b=bn9/DOEZUGUfuaqJTJxgDD/IisixcPzuymxu0bMHcWq2R9W2+NV46jQBkaUcgLXyPck2ZZsPhmPHL1q1vuUhqJOrfLjheYqLHdJATD5Ub0CpcPn/VHjUMD6lAuE4Kw8Tt6neb31Eqw7T/zFGlZL9qHVv4cGEQG/FNtsKe5Kaw4E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268383; c=relaxed/simple; bh=a4e2Ye41TqPia6GPTouAiPqNZkYjdM1BOHCVEVc9014=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hzm99fB/TdTtshPd3erX/N5/5XvLb6mJZ3ZwW0y6QAFSkhjZtUACSUoo1mRE5cax8vfR9iFcFQr3NrjqMReH5iFDoppyKgQfvPYbp51RgmiY/Qy3ErMX+rLtyDkWqDqi96+yRqUyYSE9ZvA9Y8xSDtaQPIq/gIf9gcF7ieq7HSg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=sLIQWxtr; arc=none smtp.client-ip=113.46.200.226 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="sLIQWxtr" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=9NpBB7CEIjqjyGCb4SVckgVeutjU9azjoaZgEVa947o=; b=sLIQWxtrS8w5ERuoFDXmbubInkswYa662b4wJY61Zn7xeDFflLoibLq4MWzVHCe0KOiu45zz/ WsF0/wDXGz+6Irxls6bqJzT51YJ9VpzdmO28F/hdacMD9/6HUBU+B/lIjOaXLBS1rXND9jmd36W gmNkFosl91edLNaX6LjQcZk= Received: from mail.maildlp.com (unknown [172.19.163.15]) by canpmsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bq63dBzKm5m; Tue, 1 Sep 2026 21:01:59 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id 01D1440586; Tue, 1 Sep 2026 21:12:53 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:52 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 1/8] jffs2: wbuf: clear wbuf on recovery failure paths Date: Tue, 1 Sep 2026 21:05:42 +0800 Message-ID: <20260901130549.1761342-2-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" Write verification was introduced by commit a6bc432e296d ("[JFFS2] Add support for write-buffer verification.") to detect transport or program-time corruption. When verification fails, jffs2_wbuf_recover() attempts to recover the data: it first calls jffs2_block_refile() to mark the old eraseblock's remaining space as REF_OBSOLETE, then rewrites the old block's data along with the new data still in the wbuf to a new block. However, when the recovery write verification also fails, the function returns without clearing c->wbuf_len, leaving the wbuf still pointing to the refiled old block, which leads to two kinds of bugs. Both cases below are illustrated with a filesystem of erasesize=3D16KB and wbuf_pagesize=3D512B. Case 1: BUG_ON in jffs2_link_node_ref(): User: Two 1KB writes ref0: [A+0, A+1092) (ri:68B + data:1024B) ref1: [A+1092, A+2184) User: append 1KB write ... jffs2_write_dnode jffs2_flash_writev c->wbuf_ofs =3D A+2048, c->wbuf_len =3D 512 __jffs2_flush_wbuf mtd_write -> 0-to-1 bit flip jffs2_verify_write -> verify failed jffs2_wbuf_recover jffs2_block_refile c->nextblock =3D NULL jffs2_link_node_ref -> mark A remaining ref2: [A+2184, A+16384) space REF_OBSOLETE, jeb_A->free_size =3D 0 jffs2_reserve_space_gc jffs2_do_reserve_space jffs2_find_nextblock c->nextblock =3D B start =3D A+1092, end =3D A+2184 end - start >=3D c->wbuf_pagesize -> recover data in A mtd_write jffs2_verify_write -> verify also failed return -> c->wbuf_ofs =3D A+2048 c->wbuf_len =3D 512 retry jffs2_flash_writev if (SECTOR_ADDR(to) !=3D SECTOR_ADDR(c->wbuf_ofs)) -> SECTOR(to) =3D B -> SECTOR(c->wbuf_ofs) =3D A __jffs2_flush_wbuf(c, PAD_NOACCOUNT) -> flush residual wbuf data wbuf_jeb =3D A -> c->wbuf_ofs still points to refiled old block mtd_write -> succeeds via NAND AND jffs2_verify_write -> passed if (pad) jffs2_link_node_ref ref_offset(ref) =3D c->wbuf_ofs + c->wbuf_len =3D A+2560 jeb_A->offset =3D A c->sector_size =3D 16384 jeb_A->free_size =3D 0 ref_offset(ref) !=3D jeb_A->offset + c->sector_size - jeb_A->free_size -> BUG Case 2: deadlock in jffs2_flush_wbuf_pad(): User: 1KB write A_ref0: [A+0, A+1092) (ri:68B + data:1024B) User: append 1K write ... jffs2_write_dnode jffs2_flash_writev c->wbuf_ofs =3D A+1024, c->wbuf_len =3D 512 __jffs2_flush_wbuf mtd_write -> bit flip jffs2_verify_write -> verify failed jffs2_wbuf_recover jffs2_block_refile c->nextblock =3D NULL jffs2_link_node_ref -> mark A remaining A_ref1: [A+1092, A+16384) space as REF_OBSOLETE jffs2_reserve_space_gc jffs2_do_reserve_space jffs2_find_nextblock c->nextblock =3D B start =3D A, end =3D A+1092 end - start >=3D c->wbuf_pagesize -> recover data in A mtd_write jffs2_verify_write -> verify also failed jffs2_add_physical_node_ref -> mark written area in B_ref0: [B+0, B+1536) B as REF_OBSOLETE return -> c->wbuf_ofs =3D A+1024 c->wbuf_len =3D 512 retry jffs2_flash_writev down_write(&c->wbuf_sem) if (SECTOR_ADDR(to) !=3D SECTOR_ADDR(c->wbuf_ofs)) -> SECTOR(to) =3D B -> SECTOR(c->wbuf_ofs) =3D A __jffs2_flush_wbuf(c, PAD_NOACCOUNT) -> flush residual wbuf data wbuf_jeb =3D A -> c->wbuf_ofs still points to refiled old block mtd_write -> bit flip jffs2_verify_write -> verify failed jffs2_wbuf_recover jffs2_block_refile c->nextblock !=3D jeb -> jeb =3D A, nextblock = =3D B jffs2_link_node_ref -> append zero-length ref A_ref2: [A+16384, A+16384) marked REF_OBSOLETE after the existing one end =3D jeb_A->last_node -> inflates to eraseblock tail start =3D A, end =3D A+16384 jffs2_reserve_space_gc minsize =3D end - start =3D 16384 jffs2_do_reserve_space jeb =3D c->nextblock -> points to B jeb_B->free_size =3D 16384 - 1536 minsize > jeb_B->free_size -> first recovery's OBSOLETE ref reduced free_size jffs2_wbuf_dirty(c) jffs2_flush_wbuf_pad(c) down_write(&c->wbuf_sem) -> already held, deadlock Fix this by setting c->wbuf_len =3D 0 when jffs2_verify_write fails in recovery path, and also in the jffs2_reserve_space_gc() and jffs2_prealloc_raw_node_refs() failure paths, ensuring subsequent flushes will not attempt writes on refiled blocks. Signed-off-by: zhouminqiang --- fs/jffs2/wbuf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 3b7803c75d58..61e3dbd4cd7b 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -390,6 +390,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) if (ret) { pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n= "); kfree(buf); + c->wbuf_len =3D 0; return; } =20 @@ -400,6 +401,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) if (ret) { pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensue= s.\n"); kfree(buf); + c->wbuf_len =3D 0; return; } =20 @@ -431,12 +433,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *= c) =20 if (ret || retlen !=3D towrite || jffs2_verify_write(c, rewrite_buf, ofs= )) { /* Argh. We tried. Really we did. */ - pr_crit("Recovery of wbuf failed due to a second write error\n"); + pr_crit("Recovery of wbuf failed due to a second write error. Data loss= ensues.\n"); kfree(buf); =20 if (retlen) jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, = first_raw), NULL); =20 + c->wbuf_len =3D 0; return; } pr_notice("Recovery of wbuf succeeded to %08x\n", ofs); --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout07.his.huawei.com (canpmsgout07.his.huawei.com [113.46.200.222]) (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 85CA547D935 for ; Tue, 1 Sep 2026 13:13:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.222 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268394; cv=none; b=FYMBOSlpYreGV0J3/OXyjYMNXPKlUWdHAU7V8OeBFoxmEz2FiG2XPLY4J8JWy8Ii7XXLS9H3oIieF4/hBI+YrZcUdtp6nSmK0rv4rAvDkoRSp9cM12PsjlcB4oCIQRWBNuNH3rfClMoaMePwZQtmRS184F2RxV32HCu2y2upRMs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268394; c=relaxed/simple; bh=aANne2xVIIgeYErCp5qy2ZJ/ZpCJrJGBduXkMLr+O30=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WbC89OR0jOnruLRjj0sVslkqpMSvWFdTFOOX6eksHP4fgtCO1trL1VP98kJnLKpwoewdso42lsoPNni5w2VVF3+t1QIrc8tHhzPJKPRlnAHaIy5URGGFdVOMqoKIwSjAbYjL819yvYUn9ATL0IRTIiieaTSU6BmMLkODofuVCeE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=AjShkyBI; arc=none smtp.client-ip=113.46.200.222 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="AjShkyBI" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=uoYKoPZ7YKPmsCHG/kXIjc+wB00oulf3PAI6t9L7dXc=; b=AjShkyBICAQG93Xx24uO5WkxiKPbiNgccEYEo+cH2GjESgyKEM//MZ278+F6XzwOlEUJ34IXR gGLmLMCdZY+TwaKIQcratPL0uQrHHNhh3oTLFnFNjRlq5slRg6HK0rXoLect9UvacjQfXAPOIG/ AW3dbypsROzmFphzCRweR1I= Received: from mail.maildlp.com (unknown [172.19.163.214]) by canpmsgout07.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bw237xzLlXZ; Tue, 1 Sep 2026 21:02:04 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id C14E04057C; Tue, 1 Sep 2026 21:12:53 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:52 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 2/8] jffs2: wbuf: fix space accounting in recovery secondary write failure Date: Tue, 1 Sep 2026 21:05:43 +0800 Message-ID: <20260901130549.1761342-3-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" In jffs2_wbuf_recover(), when the recovery write to the new erase block also fails, the code marks the already-written portion as REF_OBSOLETE via jffs2_add_physical_node_ref(). However, the length passed is ref_totlen(c, jeb, first_raw), which is the length of a single node on the old block, not retlen which is the actual number of bytes written to the new block. When the recovery buffer contains multiple nodes, ref_totlen only accounts for the first node's length, which can be much smaller than retlen. This under-deducts free_size, causing subsequent allocations to land on already-programmed NAND pages and silently corrupt data. When first_raw is the only node in the recovery range, ref_totlen equals the full unaligned data size and exceeds the page-aligned retlen, over-deducting free_size and wasting space. Use retlen so the new block's free_size accurately reflects which NAND pages have been programmed. Signed-off-by: zhouminqiang --- fs/jffs2/wbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 61e3dbd4cd7b..360a291d9fd5 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -437,7 +437,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) kfree(buf); =20 if (retlen) - jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, = first_raw), NULL); + jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, retlen, NULL); =20 c->wbuf_len =3D 0; return; --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout06.his.huawei.com (canpmsgout06.his.huawei.com [113.46.200.221]) (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 A5E45318EC5 for ; Tue, 1 Sep 2026 13:12:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.221 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268381; cv=none; b=K0Ssv2zlLiF8IiKgpQroPxTg6Vq4W0VWOk8MheChpI2/5HmggbW5S7JZZlAT33lj2ZIVDjTVMxkPDcB4gHGG9e5VLFGjftwDf2kOJPrd7AFhkPySx9aqiSkFSXYOmI+ILA0TWfHLdRHX0Pj62LkdOeFdZSCPi+iWCrkip5cZcM0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268381; c=relaxed/simple; bh=3i8+GPtQo+cyyRNTGughUp3lfIjFcuB3hn/X86lNkas=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jV1Q2zf6mUYBJGzAJkxwzdG7KC0oAUYQM7xbD+7zaEm6gzGZEg+IFpWUVfspjcYlkraKl/11jTni+zsWw4Ay3eEpq6mVy7z+hQuyaKx7Qxah+7pzlMbyT/PtKwxxsFRQWj0oncq2aD5chnp4s1KNHICFfU5Javw1M/vWBSpGo94= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=oqdtTUz1; arc=none smtp.client-ip=113.46.200.221 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="oqdtTUz1" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=XttkQrGGxgVvdqaU8oqPJsj1rOoam2GxZi/pM1qFyT4=; b=oqdtTUz137cwCvq0Vima4V9QcWzM4sStSL8ZtpjXR8tPlPAwKkGSMw/X2mcn8CYGdD1RMM1EU 0zBr7kXbFBEZNkx7360byyUndc2bPGLy9WXrEM88bvSKaENFLj7zly0SL4WVixAWzB+1+7mQTOJ zMAr1SQGMXcfEmia1jBeVwQ= Received: from mail.maildlp.com (unknown [172.19.162.144]) by canpmsgout06.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bz1Nx9zRhRG; Tue, 1 Sep 2026 21:02:07 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id 92A1240538; Tue, 1 Sep 2026 21:12:54 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:53 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 3/8] jffs2: replace per-superblock verify buffer with per-write buffer Date: Tue, 1 Sep 2026 21:05:44 +0800 Message-ID: <20260901130549.1761342-4-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" Subsequent patches will extend write verification to additional write paths that may execute concurrently. A shared per-superblock buffer would require a coarse lock to serialize all verification, hurting concurrency. To avoid this contention, remove the wbuf_verify field from jffs2_sb_info, along with the scattered kmalloc/kfree of wbuf_verify in jffs2_nand_flash_setup, jffs2_dataflash_setup, jffs2_nor_wbuf_flash_setup and their corresponding cleanup functions. Instead, allocate a temporary buffer inside jffs2_verify_write(), giving each invocation its own buffer and eliminating the shared state. Signed-off-by: zhouminqiang --- fs/jffs2/jffs2_fs_sb.h | 3 --- fs/jffs2/wbuf.c | 61 ++++++++++++++++-------------------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 5a7091746f68..8a75870d3fc8 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -124,9 +124,6 @@ struct jffs2_sb_info { =20 uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - unsigned char *wbuf_verify; /* read-back buffer for verification */ -#endif #ifdef CONFIG_JFFS2_FS_WRITEBUFFER unsigned char *wbuf; /* Write-behind buffer for NAND flash */ uint32_t wbuf_ofs; diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 360a291d9fd5..31fef7466d04 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -233,19 +233,31 @@ static int jffs2_verify_write(struct jffs2_sb_info *c= , unsigned char *buf, int ret; size_t retlen; char *eccstr; + void *verify_buf; + + verify_buf =3D kmalloc(c->wbuf_pagesize, GFP_NOFS); + if (!verify_buf) { + pr_warn("%s(): verify buffer allocation failed, skipping verification\n", + __func__); + return 0; + } + + ret =3D mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, verify_buf); =20 - ret =3D mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); if (ret && ret !=3D -EUCLEAN && ret !=3D -EBADMSG) { pr_warn("%s(): Read back of page at %08x failed: %d\n", __func__, c->wbuf_ofs, ret); - return ret; + goto out_free; } else if (retlen !=3D c->wbuf_pagesize) { pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n", __func__, ofs, retlen, c->wbuf_pagesize); - return -EIO; + ret =3D -EIO; + goto out_free; + } + if (!memcmp(buf, verify_buf, c->wbuf_pagesize)) { + ret =3D 0; + goto out_free; } - if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) - return 0; =20 if (ret =3D=3D -EUCLEAN) eccstr =3D "corrected"; @@ -261,9 +273,14 @@ static int jffs2_verify_write(struct jffs2_sb_info *c,= unsigned char *buf, =20 pr_warn("Read back:\n"); print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, - c->wbuf_verify, c->wbuf_pagesize, 0); + verify_buf, c->wbuf_pagesize, 0); =20 + kfree(verify_buf); return -EIO; + +out_free: + kfree(verify_buf); + return ret; } #else #define jffs2_verify_write(c,b,o) (0) @@ -1217,22 +1234,11 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) return -ENOMEM; } =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - c->wbuf_verify =3D kmalloc(c->wbuf_pagesize, GFP_KERNEL); - if (!c->wbuf_verify) { - kfree(c->oobbuf); - kfree(c->wbuf); - return -ENOMEM; - } -#endif return 0; } =20 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) { -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - kfree(c->wbuf_verify); -#endif kfree(c->wbuf); kfree(c->oobbuf); } @@ -1272,14 +1278,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { if (!c->wbuf) return -ENOMEM; =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - c->wbuf_verify =3D kmalloc(c->wbuf_pagesize, GFP_KERNEL); - if (!c->wbuf_verify) { - kfree(c->wbuf); - return -ENOMEM; - } -#endif - pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); =20 @@ -1287,9 +1285,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { } =20 void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - kfree(c->wbuf_verify); -#endif kfree(c->wbuf); } =20 @@ -1309,20 +1304,10 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info= *c) { if (!c->wbuf) return -ENOMEM; =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - c->wbuf_verify =3D kmalloc(c->wbuf_pagesize, GFP_KERNEL); - if (!c->wbuf_verify) { - kfree(c->wbuf); - return -ENOMEM; - } -#endif return 0; } =20 void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY - kfree(c->wbuf_verify); -#endif kfree(c->wbuf); } =20 --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout05.his.huawei.com (canpmsgout05.his.huawei.com [113.46.200.220]) (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 5AE0F43B3C6 for ; Tue, 1 Sep 2026 13:13:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268387; cv=none; b=dFgsSJUyWCgKObReJWBMvLfByKtDmeKCTp7BxWxCxyuffNpAQ5gXPS9U+R0hxHnil2i9C/O+iWc6xJwNHmvihgNl3cRQjcjLx0ybfrFIwCzxJgEqbUoPc6lr2atHq6n/iq9+ZoBAJ7bvpVooP3j3yQBU/fyaVNk8nlJiNjQ5OyA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268387; c=relaxed/simple; bh=iNqxe/r7fiqJ2VBxlQ1rU5aib66jR8Y5kgHb72GIMg8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cyYGpRGbu45qt7UWzFc8YthQDdw+cPdUpLI61lvGKCopa03fZ2Sd66oMDM1cv6a4s4lKBziNHnDghbh1MsmJg5lQ9Wt4LOiOIi6iy+zrLiNZFh7AjuyRSuOvW+I4tIfl5PUNWMGsrEHWgdiJ7KEftvKj/3GIfGljNIHnG0CjU6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=RJmnf4s+; arc=none smtp.client-ip=113.46.200.220 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="RJmnf4s+" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=ej8iF7xfPiEfPTnmPieqHemFhNoLZwi/7BQqcltv+jE=; b=RJmnf4s+dPHuguplmT7bWvDjoxvpH03+nzp6N/xE6ESgtpZreEhp8PHAG+KQ0CLfHf0V1rMHa H5LH2FpSZqjG/UjeoaBZilyVQbcjpZfC67nb2RtE81J9n5ANqwBlvsXQIMcb71kWoIFjzDFT7W4 70k60Ji/5qVZ92dLYSamBpM= Received: from mail.maildlp.com (unknown [172.19.162.144]) by canpmsgout05.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bQ4C6rz12LF7; Tue, 1 Sep 2026 21:01:38 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id 6458940538; Tue, 1 Sep 2026 21:12:55 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:54 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 4/8] jffs2: write verify: add byte-by-byte comparison on mismatch Date: Tue, 1 Sep 2026 21:05:45 +0800 Message-ID: <20260901130549.1761342-5-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" jffs2_verify_write() uses memcmp() to compare the write buffer against data read back from flash. On mismatch, the current code dumps the entire source and read-back data, which will become impractical once the verify path is extended to NOR flash where a single write can span PAGE_SIZE. Add a byte-by-byte comparison after the memcmp() mismatch path to locate the exact mismatch offset, reporting the first differing offset and dumping up to 128 bytes of both the source and read-back data. memcmp() remains on the hotpath for successful writes, and the byte-by-byte loop only runs when an error is actually detected. Signed-off-by: zhouminqiang --- fs/jffs2/wbuf.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 31fef7466d04..a4cf1915b2bd 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -231,7 +231,7 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, = unsigned char *buf, uint32_t ofs) { int ret; - size_t retlen; + size_t retlen, i; char *eccstr; void *verify_buf; =20 @@ -246,10 +246,10 @@ static int jffs2_verify_write(struct jffs2_sb_info *c= , unsigned char *buf, =20 if (ret && ret !=3D -EUCLEAN && ret !=3D -EBADMSG) { pr_warn("%s(): Read back of page at %08x failed: %d\n", - __func__, c->wbuf_ofs, ret); + __func__, ofs, ret); goto out_free; } else if (retlen !=3D c->wbuf_pagesize) { - pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n", + pr_warn("%s(): Read back of page at %08x gave short read: %zu not %d\n", __func__, ofs, retlen, c->wbuf_pagesize); ret =3D -EIO; goto out_free; @@ -259,24 +259,34 @@ static int jffs2_verify_write(struct jffs2_sb_info *c= , unsigned char *buf, goto out_free; } =20 - if (ret =3D=3D -EUCLEAN) - eccstr =3D "corrected"; - else if (ret =3D=3D -EBADMSG) - eccstr =3D "correction failed"; - else - eccstr =3D "OK or unused"; + for (i =3D 0; i < c->wbuf_pagesize; i++) { + uint8_t c1 =3D ((uint8_t *)buf)[i]; + uint8_t c2 =3D ((uint8_t *)verify_buf)[i]; + int dump_len; =20 - pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n", - eccstr, c->wbuf_ofs); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, - c->wbuf, c->wbuf_pagesize, 0); + if (c1 =3D=3D c2) + continue; =20 - pr_warn("Read back:\n"); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, - verify_buf, c->wbuf_pagesize, 0); + if (ret =3D=3D -EUCLEAN) + eccstr =3D "corrected"; + else if (ret =3D=3D -EBADMSG) + eccstr =3D "correction failed"; + else + eccstr =3D "OK or unused"; =20 - kfree(verify_buf); - return -EIO; + dump_len =3D min_t(int, 128, c->wbuf_pagesize - i); + pr_warn("Write verify error (ECC %s) at %08x (+%zu/%d). Wrote:\n", + eccstr, ofs, i, c->wbuf_pagesize); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + buf + i, dump_len, 0); + + pr_warn("Read back:\n"); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + verify_buf + i, dump_len, 0); + + ret =3D -EIO; + goto out_free; + } =20 out_free: kfree(verify_buf); --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout07.his.huawei.com (canpmsgout07.his.huawei.com [113.46.200.222]) (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 0E5D6432E60 for ; Tue, 1 Sep 2026 13:13:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.222 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268386; cv=none; b=D5xsE9lzAoSIarGwkzD/BEDToGiMM7PY+dCyEi8hNmAY5ZDoSWs399PHiiyPFrMe3HiyXY7rIRkO2SS4unqf8SsuOUS1UsimeFnB8FgZmo9FdfPkxJl6OmnAFBNXzkISNzrbkKgO6MzRbT9jV9MGX0A0ERLrtZftRk8JfYXmhDs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268386; c=relaxed/simple; bh=QocJW4PaqHHakdd+qROhTYnbfrG4Viou2yuy2V3V+wk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jimsmeFh+eRV+1EVBtYL+bC8GPWg2smsLWC1tX50DHgYb/B6HNc8BcdftFGRMnSj6w12G92KfnwAV/lmdBmwbcPMe8eZgtRFxblTgOhurc4SYA3pbG5Wl3c5GhEEoKaLHYnuaB7MsKvBu9girCY5fo0uIVo3hDAYrJ4aauY9QMI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=SnOUKHK7; arc=none smtp.client-ip=113.46.200.222 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="SnOUKHK7" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=jmt8bfKaSGroqiOHkxuJ59AWSDBasbhKv+fimUwo2ec=; b=SnOUKHK7srA5XzCvNruBLQJ8WsP61zC6VrSs0oTk/y2cy3kcOHaattF4xdIGxjEUtJdOgROK7 Je098/rXxtn4d8hc7wUdoJJ2NqX+573LFF4DDb7ttqU+D5QlKy46ZAWoHROcH9r1MfCejaz/rTt owHk9qEkMapLh42wTEIs6a4= Received: from mail.maildlp.com (unknown [172.19.163.200]) by canpmsgout07.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5by4lbJzLlXZ; Tue, 1 Sep 2026 21:02:06 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id 280A940563; Tue, 1 Sep 2026 21:12:56 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:55 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 5/8] jffs2: add write verification to direct page writes in flash_writev Date: Tue, 1 Sep 2026 21:05:46 +0800 Message-ID: <20260901130549.1761342-6-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" jffs2_flash_writev() performs writes in three phases: phase 1 fills the write buffer and flushes it when full, phase 2 writes full pages directly via mtd_write() bypassing the buffer, and phase 3 fills the remaining data into the write buffer. Phases 1 and 3 both invoke __jffs2_flush_wbuf() when the buffer is full, which includes write-back verification when CONFIG_JFFS2_FS_WBUF_VERIFY is enabled. However phase 2, which handles the bulk of the write data, calls mtd_write() directly without any verification. Phase 2 direct writes may span multiple wbuf_pagesize pages. Extend jffs2_verify_write() with a len parameter to specify the data length to verify, and add the verification call after the phase 2 mtd_write() to cover this gap. Also add __GFP_NOWARN to the kmalloc in jffs2_verify_write() to suppress high-order allocation warnings when verifying summary writes on large-erasesize NAND. Signed-off-by: zhouminqiang --- fs/jffs2/wbuf.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index a4cf1915b2bd..715cdb8df427 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -228,38 +228,38 @@ static struct jffs2_raw_node_ref **jffs2_incore_repla= ce_raw(struct jffs2_sb_info =20 #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, - uint32_t ofs) + uint32_t ofs, size_t len) { int ret; size_t retlen, i; char *eccstr; void *verify_buf; =20 - verify_buf =3D kmalloc(c->wbuf_pagesize, GFP_NOFS); + verify_buf =3D kmalloc(len, GFP_NOFS | __GFP_NOWARN); if (!verify_buf) { pr_warn("%s(): verify buffer allocation failed, skipping verification\n", __func__); return 0; } =20 - ret =3D mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, verify_buf); + ret =3D mtd_read(c->mtd, ofs, len, &retlen, verify_buf); =20 if (ret && ret !=3D -EUCLEAN && ret !=3D -EBADMSG) { pr_warn("%s(): Read back of page at %08x failed: %d\n", __func__, ofs, ret); goto out_free; - } else if (retlen !=3D c->wbuf_pagesize) { - pr_warn("%s(): Read back of page at %08x gave short read: %zu not %d\n", - __func__, ofs, retlen, c->wbuf_pagesize); + } else if (retlen !=3D len) { + pr_warn("%s(): Read back of page at %08x gave short read: %zu not %zu\n", + __func__, ofs, retlen, len); ret =3D -EIO; goto out_free; } - if (!memcmp(buf, verify_buf, c->wbuf_pagesize)) { + if (!memcmp(buf, verify_buf, len)) { ret =3D 0; goto out_free; } =20 - for (i =3D 0; i < c->wbuf_pagesize; i++) { + for (i =3D 0; i < len; i++) { uint8_t c1 =3D ((uint8_t *)buf)[i]; uint8_t c2 =3D ((uint8_t *)verify_buf)[i]; int dump_len; @@ -274,9 +274,9 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, = unsigned char *buf, else eccstr =3D "OK or unused"; =20 - dump_len =3D min_t(int, 128, c->wbuf_pagesize - i); - pr_warn("Write verify error (ECC %s) at %08x (+%zu/%d). Wrote:\n", - eccstr, ofs, i, c->wbuf_pagesize); + dump_len =3D min_t(int, 128, len - i); + pr_warn("Write verify error (ECC %s) at %08x (+%zu/%zu). Wrote:\n", + eccstr, ofs, i, len); print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, buf + i, dump_len, 0); =20 @@ -293,7 +293,7 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, = unsigned char *buf, return ret; } #else -#define jffs2_verify_write(c,b,o) (0) +#define jffs2_verify_write(c,b,o,l) (0) #endif =20 /* Recover from failure to write wbuf. Recover the nodes up to the @@ -458,7 +458,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ret =3D mtd_write(c->mtd, ofs, towrite, &retlen, rewrite_buf); =20 - if (ret || retlen !=3D towrite || jffs2_verify_write(c, rewrite_buf, ofs= )) { + if (ret || retlen !=3D towrite || jffs2_verify_write(c, rewrite_buf, ofs= , towrite)) { /* Argh. We tried. Really we did. */ pr_crit("Recovery of wbuf failed due to a second write error. Data loss= ensues.\n"); kfree(buf); @@ -676,7 +676,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c,= int pad) retlen, c->wbuf_pagesize); ret =3D -EIO; goto wfail; - } else if ((ret =3D jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { + } + + ret =3D jffs2_verify_write(c, c->wbuf, c->wbuf_ofs, c->wbuf_pagesize); + if (ret) { wfail: jffs2_wbuf_recover(c); =20 @@ -908,6 +911,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const = struct kvec *invecs, if (ret < 0 || wbuf_retlen !=3D PAGE_DIV(vlen)) goto outfile; =20 + ret =3D jffs2_verify_write(c, v, outvec_to, PAGE_DIV(vlen)); + if (ret) + goto outfile; + vlen -=3D wbuf_retlen; outvec_to +=3D wbuf_retlen; c->wbuf_ofs =3D outvec_to; --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout10.his.huawei.com (canpmsgout10.his.huawei.com [113.46.200.225]) (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 B6306472060 for ; Tue, 1 Sep 2026 13:13:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.225 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268388; cv=none; b=PJdTqNG6pvBjm1SXSMXhL66wQlrDrZLlfrDQPFN40vcZxQnZzxxhg7gy0pKcW4+K5tKot4ct8C8GUDnT7zGS5j4GaKQadtSJOJP7OKw4UZjah1MmqNtHFemaJirZhRKjM9+GAw6diYQihLZIulqutzGzXKQD/xv30/RvRmoJ7sM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268388; c=relaxed/simple; bh=V2I4VJIW4GlWIHM+E9DUkW0CdGmsO1iZxtACunF1rF4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SWEYly1ytg9r/tySKRN4lt21WhxLtfTIx6g/akiicW2UJWUgNpTmDl09h02FsWmaJaBbjRBAE8r6dCFHcNjPsrtF3XBAAKABNY5fBbx3B3QOjDGsWYzh5kJ+KiL9e/WLC7lMprCFQxXfryz1gIZUsDq41INC2KOUTyyriZb0214= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=eIlbKWtn; arc=none smtp.client-ip=113.46.200.225 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="eIlbKWtn" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=q58oogwAHgi+xqY8dzrkWg6Up18ARsMRaiqitS6a078=; b=eIlbKWtn8AbAoPWKGOn+mioNg9f+NFHoQWCg2KFBRS9lRBhDKXQ3GccuLdSgEzV3tKozOa70F 3QyZ4S4cNuQ/+t9zva3+E92ikpmB8DEmAfBgHpK0MwmGN1qvccTSAis/ge2mLC09/i0dTNA3SZ0 J+wCDhprsZeLIqH7WyR8KPY= Received: from mail.maildlp.com (unknown [172.19.163.200]) by canpmsgout10.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bz2JFBz1K98V; Tue, 1 Sep 2026 21:02:07 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id EE49E40563; Tue, 1 Sep 2026 21:12:56 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:56 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 6/8] jffs2: add write verification to NOR direct write paths Date: Tue, 1 Sep 2026 21:05:47 +0800 Message-ID: <20260901130549.1761342-7-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" NOR Flash and other non-writebuffered devices write directly through jffs2_flash_direct_writev() and jffs2_flash_direct_write() without any write-back verification. If mtd_write() succeeds but the readable medium differs from JFFS2's source buffer, a later node CRC failure cannot distinguish transport/program-time corruption from post-commit media damage. Move jffs2_verify_write() from wbuf.c to writev.c so it can be shared by both writebuffered and direct write paths. Add jffs2_verify_writev() to iterate over kvec entries and verify each one individually. In both direct write functions, add mtd_write() return value and retlen checks, and invoke verification after a successful complete write. In jffs2_flash_direct_writev(), move the mtd_writev() call before jffs2_sum_add_kvec() so that *retlen is always set by the MTD layer first. The original ordering let jffs2_sum_add_kvec() return early on error without ever touching *retlen, leaving the caller's retlen check to read an uninitialized value. Keep the same order in jffs2_flash_direct_write(). Signed-off-by: zhouminqiang --- fs/jffs2/os-linux.h | 11 ++++ fs/jffs2/wbuf.c | 70 ------------------------- fs/jffs2/writev.c | 121 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 71 deletions(-) diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 86ab014a349c..e73ef643fd97 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -192,6 +192,17 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c,= const struct kvec *vecs, int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t l= en, size_t *retlen, const u_char *buf); =20 +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +int jffs2_verify_write(struct jffs2_sb_info *c, const unsigned char *buf, + uint32_t ofs, size_t len); +int jffs2_verify_writev(struct jffs2_sb_info *c, + const struct kvec *vecs, + unsigned long count, loff_t to); +#else +#define jffs2_verify_write(c, b, o, l) (0) +#define jffs2_verify_writev(c, v, cnt, t) (0) +#endif + #endif /* __JFFS2_OS_LINUX_H__ */ =20 =20 diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 715cdb8df427..a44f3f94da0d 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -226,76 +226,6 @@ static struct jffs2_raw_node_ref **jffs2_incore_replac= e_raw(struct jffs2_sb_info return NULL; } =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY -static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, - uint32_t ofs, size_t len) -{ - int ret; - size_t retlen, i; - char *eccstr; - void *verify_buf; - - verify_buf =3D kmalloc(len, GFP_NOFS | __GFP_NOWARN); - if (!verify_buf) { - pr_warn("%s(): verify buffer allocation failed, skipping verification\n", - __func__); - return 0; - } - - ret =3D mtd_read(c->mtd, ofs, len, &retlen, verify_buf); - - if (ret && ret !=3D -EUCLEAN && ret !=3D -EBADMSG) { - pr_warn("%s(): Read back of page at %08x failed: %d\n", - __func__, ofs, ret); - goto out_free; - } else if (retlen !=3D len) { - pr_warn("%s(): Read back of page at %08x gave short read: %zu not %zu\n", - __func__, ofs, retlen, len); - ret =3D -EIO; - goto out_free; - } - if (!memcmp(buf, verify_buf, len)) { - ret =3D 0; - goto out_free; - } - - for (i =3D 0; i < len; i++) { - uint8_t c1 =3D ((uint8_t *)buf)[i]; - uint8_t c2 =3D ((uint8_t *)verify_buf)[i]; - int dump_len; - - if (c1 =3D=3D c2) - continue; - - if (ret =3D=3D -EUCLEAN) - eccstr =3D "corrected"; - else if (ret =3D=3D -EBADMSG) - eccstr =3D "correction failed"; - else - eccstr =3D "OK or unused"; - - dump_len =3D min_t(int, 128, len - i); - pr_warn("Write verify error (ECC %s) at %08x (+%zu/%zu). Wrote:\n", - eccstr, ofs, i, len); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, - buf + i, dump_len, 0); - - pr_warn("Read back:\n"); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, - verify_buf + i, dump_len, 0); - - ret =3D -EIO; - goto out_free; - } - -out_free: - kfree(verify_buf); - return ret; -} -#else -#define jffs2_verify_write(c,b,o,l) (0) -#endif - /* Recover from failure to write wbuf. Recover the nodes up to the * wbuf, not the one which we were starting to try to write. */ =20 diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index a1bda9dab3f8..e96f10566fe1 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -10,12 +10,121 @@ */ =20 #include +#include #include #include "nodelist.h" =20 +#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +int jffs2_verify_write(struct jffs2_sb_info *c, const unsigned char *buf, + uint32_t ofs, size_t len) +{ + int ret; + size_t retlen, i; + char *eccstr; + void *verify_buf; + + verify_buf =3D kmalloc(len, GFP_NOFS | __GFP_NOWARN); + if (!verify_buf) { + pr_warn("%s(): verify buffer allocation failed, skipping verification\n", + __func__); + return 0; + } + + ret =3D mtd_read(c->mtd, ofs, len, &retlen, verify_buf); + + if (ret && ret !=3D -EUCLEAN && ret !=3D -EBADMSG) { + pr_warn("%s(): Read back of page at %08x failed: %d\n", + __func__, ofs, ret); + goto out_free; + } else if (retlen !=3D len) { + pr_warn("%s(): Read back of page at %08x gave short read: %zu not %zu\n", + __func__, ofs, retlen, len); + ret =3D -EIO; + goto out_free; + } + if (!memcmp(buf, verify_buf, len)) { + ret =3D 0; + goto out_free; + } + + for (i =3D 0; i < len; i++) { + uint8_t c1 =3D ((uint8_t *)buf)[i]; + uint8_t c2 =3D ((uint8_t *)verify_buf)[i]; + int dump_len; + + if (c1 =3D=3D c2) + continue; + + if (ret =3D=3D -EUCLEAN) + eccstr =3D "corrected"; + else if (ret =3D=3D -EBADMSG) + eccstr =3D "correction failed"; + else + eccstr =3D "OK or unused"; + + dump_len =3D min_t(int, 128, len - i); + pr_warn("Write verify error (ECC %s) at %08x (+%zu/%zu). Wrote:\n", + eccstr, ofs, i, len); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + buf + i, dump_len, 0); + + pr_warn("Read back:\n"); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, + verify_buf + i, dump_len, 0); + + ret =3D -EIO; + goto out_free; + } + +out_free: + kfree(verify_buf); + return ret; +} + +int jffs2_verify_writev(struct jffs2_sb_info *c, + const struct kvec *vecs, + unsigned long count, loff_t to) +{ + loff_t ofs =3D to; + unsigned long i; + int ret; + + for (i =3D 0; i < count; i++) { + if (!vecs[i].iov_len) + continue; + ret =3D jffs2_verify_write(c, vecs[i].iov_base, ofs, + vecs[i].iov_len); + if (ret) + return ret; + ofs +=3D vecs[i].iov_len; + } + return 0; +} +#endif /* CONFIG_JFFS2_FS_WBUF_VERIFY */ + int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *= vecs, unsigned long count, loff_t to, size_t *retlen) { + int ret; + + ret =3D mtd_writev(c->mtd, vecs, count, to, retlen); + + if (ret) { + pr_warn("%s(): Write failed with %d\n", __func__, ret); + } else { + size_t totlen =3D 0; + unsigned long i; + + for (i =3D 0; i < count; i++) + totlen +=3D vecs[i].iov_len; + if (*retlen !=3D totlen) { + pr_warn("%s(): Write was short: %zu instead of %zu\n", + __func__, *retlen, totlen); + ret =3D -EIO; + } else + ret =3D jffs2_verify_writev(c, vecs, count, to); + } + if (!jffs2_is_writebuffered(c)) { if (jffs2_sum_active()) { int res; @@ -26,15 +135,25 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c,= const struct kvec *vecs, } } =20 - return mtd_writev(c->mtd, vecs, count, to, retlen); + return ret; } =20 int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t l= en, size_t *retlen, const u_char *buf) { int ret; + ret =3D mtd_write(c->mtd, ofs, len, retlen, buf); =20 + if (ret) { + pr_warn("%s(): Write failed with %d\n", __func__, ret); + } else if (*retlen !=3D len) { + pr_warn("%s(): Write was short: %zu instead of %zu\n", + __func__, *retlen, len); + ret =3D -EIO; + } else + ret =3D jffs2_verify_write(c, buf, ofs, len); + if (jffs2_sum_active()) { struct kvec vecs[1]; int res; --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout11.his.huawei.com (canpmsgout11.his.huawei.com [113.46.200.226]) (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 D0F5B3E7621 for ; Tue, 1 Sep 2026 13:13:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.226 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268384; cv=none; b=SusPoMzy8kgqYl7C0AR4INb0V7qbPTHbZ5Jz2HPkVLxp9UfjAaHwC742rf4P/Scu3ca28p1CNJlYN/Tczxxoo473pLo7CC/cPBMtNEQqIDR1ByByxGBfhbC1GvCa8cTgxzDBzSEo0EteA9DALUYikf5sNNTZRENdsuqV3ziAajc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268384; c=relaxed/simple; bh=FfqEzXsVGq49c/TJHdPK/03eSLl0ACDbIo8n6QQmtMs=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hOX0f1KLz5iqtm2sB293wXjWevpbzf04AjELOwrifr1jvad30GY5PcpgqMmXulOU7MOrxe9xYo6HPt1T78tSq50S6vsXlaFKClXrZGR5j1k2ZQu/wJl+YLOauijHt+8F3Rhw+1VzxrxzCrjjXtR87suZagkyc4N1iIDjyxDb2bA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=IsEw0X1K; arc=none smtp.client-ip=113.46.200.226 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="IsEw0X1K" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=1JEhCrccgKhsR14hPcyf244QYWCHBNgM8yXo5NjlLBM=; b=IsEw0X1KvMgG8jdq7CVBk3Eq7ZZ6S2kfBZgx1qZD4PAQPscuOThF5aW2Cx2Oxe3b0Ie7KRDC0 /rWHpASBW5sZp9uc4JfQfUQjYSgkWXjxYIgaLz4NMJFBDlOyHo3a1VEJ5tgDabauIyF7WhUz3Nc PpVYjoqnyaWPyg2QS8laHT4= Received: from mail.maildlp.com (unknown [172.19.163.214]) by canpmsgout11.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bw436LzKm5m; Tue, 1 Sep 2026 21:02:04 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id B40D34057C; Tue, 1 Sep 2026 21:12:57 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:56 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 7/8] jffs2: rename CONFIG_JFFS2_FS_WBUF_VERIFY to CONFIG_JFFS2_FS_WRITE_VERIFY Date: Tue, 1 Sep 2026 21:05:48 +0800 Message-ID: <20260901130549.1761342-8-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" Write verification now covers all write paths including NOR direct writes and write-buffer direct page writes, not just the write-buffer flush path. The Kconfig option also no longer depends on CONFIG_JFFS2_FS_WRITEBUFFER. Rename the option from CONFIG_JFFS2_FS_WBUF_VERIFY to CONFIG_JFFS2_FS_WRITE_VERIFY to reflect its broader scope and independence from the write-buffer configuration. Update defconfig files that explicitly enabled the old symbol to use the new name, so that platforms which previously relied on this verification continue to have it enabled. Signed-off-by: zhouminqiang --- arch/arm/configs/keystone_defconfig | 2 +- arch/arm/configs/lpc32xx_defconfig | 2 +- arch/arm/configs/pxa3xx_defconfig | 2 +- arch/arm/configs/pxa_defconfig | 2 +- arch/powerpc/configs/44x/fsp2_defconfig | 2 +- fs/jffs2/Kconfig | 23 ++++++++++++++++++----- fs/jffs2/os-linux.h | 2 +- fs/jffs2/writev.c | 4 ++-- 8 files changed, 26 insertions(+), 13 deletions(-) diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keyston= e_defconfig index b0cadd878152..d485b8b0b91d 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -212,7 +212,7 @@ CONFIG_VFAT_FS=3Dy CONFIG_NTFS_FS=3Dy CONFIG_TMPFS=3Dy CONFIG_JFFS2_FS=3Dy -CONFIG_JFFS2_FS_WBUF_VERIFY=3Dy +CONFIG_JFFS2_FS_WRITE_VERIFY=3Dy CONFIG_UBIFS_FS=3Dy CONFIG_CRAMFS=3Dy CONFIG_NFS_FS=3Dy diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_= defconfig index b9e2e603cd95..dd0c6db641be 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -164,7 +164,7 @@ CONFIG_MSDOS_FS=3Dy CONFIG_VFAT_FS=3Dy CONFIG_TMPFS=3Dy CONFIG_JFFS2_FS=3Dy -CONFIG_JFFS2_FS_WBUF_VERIFY=3Dy +CONFIG_JFFS2_FS_WRITE_VERIFY=3Dy CONFIG_UBIFS_FS=3Dy CONFIG_CRAMFS=3Dy CONFIG_NFS_FS=3Dy diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_de= fconfig index fb272e3a2337..f2121269f7c8 100644 --- a/arch/arm/configs/pxa3xx_defconfig +++ b/arch/arm/configs/pxa3xx_defconfig @@ -84,7 +84,7 @@ CONFIG_LEDS_TRIGGER_BACKLIGHT=3Dm CONFIG_LEDS_TRIGGER_GPIO=3Dm CONFIG_LEDS_TRIGGER_DEFAULT_ON=3Dm CONFIG_JFFS2_FS=3Dy -CONFIG_JFFS2_FS_WBUF_VERIFY=3Dy +CONFIG_JFFS2_FS_WRITE_VERIFY=3Dy CONFIG_JFFS2_COMPRESSION_OPTIONS=3Dy CONFIG_JFFS2_LZO=3Dy CONFIG_JFFS2_RUBIN=3Dy diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index 66cc149c5ca4..e05cbebb0d8b 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -596,7 +596,7 @@ CONFIG_TMPFS_POSIX_ACL=3Dy CONFIG_CONFIGFS_FS=3Dy CONFIG_JFFS2_FS=3Dm CONFIG_JFFS2_FS_DEBUG=3D1 -CONFIG_JFFS2_FS_WBUF_VERIFY=3Dy +CONFIG_JFFS2_FS_WRITE_VERIFY=3Dy CONFIG_JFFS2_SUMMARY=3Dy CONFIG_JFFS2_FS_XATTR=3Dy CONFIG_JFFS2_COMPRESSION_OPTIONS=3Dy diff --git a/arch/powerpc/configs/44x/fsp2_defconfig b/arch/powerpc/configs= /44x/fsp2_defconfig index b8b21fa15a07..e626dcb98d34 100644 --- a/arch/powerpc/configs/44x/fsp2_defconfig +++ b/arch/powerpc/configs/44x/fsp2_defconfig @@ -97,7 +97,7 @@ CONFIG_EXT4_FS_SECURITY=3Dy CONFIG_PROC_KCORE=3Dy CONFIG_TMPFS=3Dy CONFIG_JFFS2_FS=3Dy -CONFIG_JFFS2_FS_WBUF_VERIFY=3Dy +CONFIG_JFFS2_FS_WRITE_VERIFY=3Dy CONFIG_JFFS2_SUMMARY=3Dy CONFIG_JFFS2_FS_XATTR=3Dy CONFIG_CRAMFS=3Dy diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig index 560187d61562..556025a5d438 100644 --- a/fs/jffs2/Kconfig +++ b/fs/jffs2/Kconfig @@ -42,13 +42,26 @@ config JFFS2_FS_WRITEBUFFER - NOR flash with transparent ECC - DataFlash =20 -config JFFS2_FS_WBUF_VERIFY - bool "Verify JFFS2 write-buffer reads" - depends on JFFS2_FS_WRITEBUFFER +config JFFS2_FS_WRITE_VERIFY + bool "Verify JFFS2 writes" + depends on JFFS2_FS default n help - This causes JFFS2 to read back every page written through the - write-buffer, and check for errors. + Read back data immediately after flash writes and compare it + with the in-memory image that was written. This covers both + write-buffer flushes and direct writes to non-writebuffered + devices. + + This may catch corruption introduced after node CRCs are + calculated but before/while data is transferred to the flash + controller (e.g. RAM or DMA), where mtd_write() may succeed + while the medium does not match what JFFS2 intended. + + Without an immediate read-back, a later node CRC failure cannot + tell transport/program-time corruption from post-commit media + damage. + + If unsure, say 'N'. =20 config JFFS2_SUMMARY bool "JFFS2 summary support" diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index e73ef643fd97..65604a6f8148 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -192,7 +192,7 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, = const struct kvec *vecs, int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t l= en, size_t *retlen, const u_char *buf); =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +#ifdef CONFIG_JFFS2_FS_WRITE_VERIFY int jffs2_verify_write(struct jffs2_sb_info *c, const unsigned char *buf, uint32_t ofs, size_t len); int jffs2_verify_writev(struct jffs2_sb_info *c, diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index e96f10566fe1..604a14bb5710 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -14,7 +14,7 @@ #include #include "nodelist.h" =20 -#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +#ifdef CONFIG_JFFS2_FS_WRITE_VERIFY int jffs2_verify_write(struct jffs2_sb_info *c, const unsigned char *buf, uint32_t ofs, size_t len) { @@ -100,7 +100,7 @@ int jffs2_verify_writev(struct jffs2_sb_info *c, } return 0; } -#endif /* CONFIG_JFFS2_FS_WBUF_VERIFY */ +#endif /* CONFIG_JFFS2_FS_WRITE_VERIFY */ =20 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *= vecs, unsigned long count, loff_t to, size_t *retlen) --=20 2.52.0 From nobody Sat Sep 26 12:28:43 2026 Received: from canpmsgout04.his.huawei.com (canpmsgout04.his.huawei.com [113.46.200.219]) (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 3C4D0471260 for ; Tue, 1 Sep 2026 13:13:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.219 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268390; cv=none; b=to72A1fIPdlulro0eRcH4CpX4ig76Gqh361flPGDe+/tjcLTKNq+hLN1mY4PtwvuO/PqCwIDPX+IAC0nczgJoBtJbr3/PSBy0kboChJvyiwEcsGS6dvLR5O2hnvlHoIuznlZ+1q2XiTuBf3ta3arNoWg2Z3vnBzVQH6/ORnU10c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788268390; c=relaxed/simple; bh=2AmiSUiKl+6GpuUekKJXB/hMo25EauFgDVt8IIftU7g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QOlGqrANIWcR5c89GjRVbkdtylCO19P4jHnZ9MwwTeJ8lJtcaHPbryP4kFXifyJilx7gOHEW1L5E5AAyZNXZV0mbJN3g/c+NWv6UMMPGEDpQdaQVI9RpdK1y1Lgq4mq3Y+mKqYEzqkua9C28CCVaP0RTv5+lLl1zN2ozgZJFvs4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=xTyBELc/; arc=none smtp.client-ip=113.46.200.219 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="xTyBELc/" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=bLJ7so2eQ04eUxA7uRgkuQiNgLyO0A/w5Eo0GY7ooL8=; b=xTyBELc/cInYBPOUaTwt3ILOfZ8Pf1/HI1d647R/Wj1c7mrsUsFgGo6dMICOPm6/A2FvA1OPa OLpDQ8pLDW77LCeJ/wMWwQZwTA8vs7oqYp02u/NAFMCA1JTKhXa+1DFZkbttwNYqEJRvMcS+5Dk X8P9UZhgp21LbdrV9BHtios= Received: from mail.maildlp.com (unknown [172.19.162.197]) by canpmsgout04.his.huawei.com (SkyGuard) with ESMTPS id 4hZ5bz1vPzz1prLc; Tue, 1 Sep 2026 21:02:07 +0800 (CST) Received: from dggpemr100018.china.huawei.com (unknown [7.185.36.64]) by mail.maildlp.com (Postfix) with ESMTPS id 7E33440579; Tue, 1 Sep 2026 21:12:58 +0800 (CST) Received: from huawei.com (10.50.85.155) by dggpemr100018.china.huawei.com (7.185.36.64) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Tue, 1 Sep 2026 21:12:57 +0800 From: zhouminqiang To: , , , , , CC: , , , , , , Subject: [PATCH v3 8/8] jffs2: add runtime toggle for write verification Date: Tue, 1 Sep 2026 21:05:49 +0800 Message-ID: <20260901130549.1761342-9-zhouminqiang2@huawei.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260901130549.1761342-1-zhouminqiang2@huawei.com> References: <20260901130549.1761342-1-zhouminqiang2@huawei.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-ClientProxiedBy: kwepems100002.china.huawei.com (7.221.188.206) To dggpemr100018.china.huawei.com (7.185.36.64) Content-Type: text/plain; charset="utf-8" Write verification is a diagnostic facility that adds read-back overhead to every write. In production, this overhead is undesirable unless fault isolation is required. Add a module parameter jffs2.write_verify (bool, 0644) that defaults to off when CONFIG_JFFS2_FS_WRITE_VERIFY is enabled. The verification entry checks READ_ONCE(jffs2_write_verify) and returns immediately when disabled, avoiding any overhead. The parameter can be toggled at runtime via /sys/module/jffs2/parameters/write_verify or set at boot/modprobe time. Signed-off-by: zhouminqiang --- fs/jffs2/Kconfig | 8 ++++++++ fs/jffs2/writev.c | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig index 556025a5d438..03dadbd003cd 100644 --- a/fs/jffs2/Kconfig +++ b/fs/jffs2/Kconfig @@ -61,6 +61,14 @@ config JFFS2_FS_WRITE_VERIFY tell transport/program-time corruption from post-commit media damage. =20 + Verification defaults to off when this option is selected and can + be enabled at runtime via sysfs: + + /sys/module/jffs2/parameters/write_verify + + Write 0 to disable, 1 to enable. Boot/modprobe parameter + jffs2.write_verify=3D0|1 is also supported. + If unsure, say 'N'. =20 config JFFS2_SUMMARY diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index 604a14bb5710..342c413be95c 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -9,12 +9,32 @@ * */ =20 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include +#include #include #include #include "nodelist.h" =20 #ifdef CONFIG_JFFS2_FS_WRITE_VERIFY +/* + * Optional read-back after writes. + * + * Catch cases where data is corrupted after node CRCs are calculated but + * before it is correctly programmed -- e.g. in RAM or during DMA/bus + * transfer to the flash controller -- so mtd_write() succeeds while the + * medium does not match the in-memory image. + * + * Runtime toggle: /sys/module/jffs2/parameters/write_verify + * (also boot/modprobe: jffs2.write_verify=3D0|1) + */ +static bool jffs2_write_verify; +module_param_named(write_verify, jffs2_write_verify, bool, 0644); +MODULE_PARM_DESC(write_verify, + "Verify flash writes by reading back (default: N)"); + + int jffs2_verify_write(struct jffs2_sb_info *c, const unsigned char *buf, uint32_t ofs, size_t len) { @@ -23,6 +43,9 @@ int jffs2_verify_write(struct jffs2_sb_info *c, const uns= igned char *buf, char *eccstr; void *verify_buf; =20 + if (!READ_ONCE(jffs2_write_verify)) + return 0; + verify_buf =3D kmalloc(len, GFP_NOFS | __GFP_NOWARN); if (!verify_buf) { pr_warn("%s(): verify buffer allocation failed, skipping verification\n", --=20 2.52.0