Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp2354895pxb; Mon, 20 Sep 2021 19:54:55 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw1+uOcjo/5e3Dhv0aEwkBSbWCrSdamVR2BDxTrRX07nT+1zUdUoabBofyYeuozVI8KGSmP X-Received: by 2002:a05:6402:17c8:: with SMTP id s8mr32912242edy.130.1632192895663; Mon, 20 Sep 2021 19:54:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632192895; cv=none; d=google.com; s=arc-20160816; b=Wz3jg2Q4FjjL5W7Pb7OrmmSu1C/jsW+r2Faeeh+Jlm6AJRzTiqZYh2YvauiPYvewrj YDaQ1qgZXIcl/NwZtYRe0phBSOirLfGPAETo0w5Lm+U4ou8o+viy+WSNI303bdNepOZM jROn+x9IGAK9FTJmtcgGbxn16DnAy5KAZOixvMNHrPCUdpcEH/s2tjHoKnqNfzA8znZk lPw6jrD4unO4N5hEiyPwOEcxZifcf/p4SAfkTnMdMZ80OH8mrjGmInEWoDdEBJFdg9L6 1kfVN00HZXcrKvxg+xGEKnzCazNqjlHHlVzrb8LEqnO6tOP6K8HI5s8PcuOzIqPtAzx8 jSxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=KSUNtEqhWgGSjlyf9xVi416QYqULUGducEUq2lC7K+k=; b=KiyAhKpoaNZVRAQokExfvb6If+h0u48NKg0Iz53KMlwg73ZOfOC74a2yeWYj2Wmb5g RM0K1MkR2ZT26sjAT8e0FNBCgGtIKkg7XXnIwsYVfeou3DoW0+HqSp2nopoTjprWjzl3 Q3MYSGp8lB2voqFn8sY/19/q6QSovp8d3HFfppycVe3wIMGsx5JjBWhq0mPAVT7vWc0P LlujLFfcVX8zowtYYawYj99qOgEKd1dhee42vI7YUlRpl8X5bLoVpwM2wqsROICDoMVS OS8bet+uMrjJSoFwguK1mTFHJu+lYLm1V+D/10Ml/C/+h0tSvvGNMrr1aD/vcYdEHcsu amyQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Qi5Ndgk9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q8si16710731edj.90.2021.09.20.19.54.31; Mon, 20 Sep 2021 19:54:55 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Qi5Ndgk9; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355055AbhITS6V (ORCPT + 99 others); Mon, 20 Sep 2021 14:58:21 -0400 Received: from mail.kernel.org ([198.145.29.99]:59874 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1384657AbhITSsd (ORCPT ); Mon, 20 Sep 2021 14:48:33 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id B6F2363368; Mon, 20 Sep 2021 17:34:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632159257; bh=Gxqs7vcnkyg6slCKZ4aPq89mbLPunvfhing9PV39mbY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Qi5Ndgk9OP5eMpg4KGIaDBjh35gRmzqkJDf1wgwVWQMixCF+srWGIlhiL6tvJ3HxQ bncFvXIZbQKnuy1CGQfjEqxwzIW74P5LMn9hbWi5ODa1mPFRg4BIx+tZjwwSYh7QD6 Y2r6WW0mZLwXtiX8MfP5p+gAP3PJic1wyG2blZIA= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Zhihao Cheng , Miquel Raynal , Sasha Levin Subject: [PATCH 5.14 131/168] mtd: mtdconcat: Judge callback existence based on the master Date: Mon, 20 Sep 2021 18:44:29 +0200 Message-Id: <20210920163925.973187656@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210920163921.633181900@linuxfoundation.org> References: <20210920163921.633181900@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Zhihao Cheng [ Upstream commit f9e109a209a8e01e16f37e1252304f1eb3908be4 ] Since commit 46b5889cc2c5("mtd: implement proper partition handling") applied, mtd partition device won't hold some callback functions, such as _block_isbad, _block_markbad, etc. Besides, function mtd_block_isbad() will get mtd device's master mtd device, then invokes master mtd device's callback function. So, following process may result mtd_block_isbad() always return 0, even though mtd device has bad blocks: 1. Split a mtd device into 3 partitions: PA, PB, PC [ Each mtd partition device won't has callback function _block_isbad(). ] 2. Concatenate PA and PB as a new mtd device PN [ mtd_concat_create() finds out each subdev has no callback function _block_isbad(), so PN won't be assigned callback function concat_block_isbad(). ] Then, mtd_block_isbad() checks "!master->_block_isbad" is true, will always return 0. Reproducer: // reproduce.c static int __init init_diy_module(void) { struct mtd_info *mtd[2]; struct mtd_info *mtd_combine = NULL; mtd[0] = get_mtd_device_nm("NAND simulator partition 0"); if (!mtd[0]) { pr_err("cannot find mtd1\n"); return -EINVAL; } mtd[1] = get_mtd_device_nm("NAND simulator partition 1"); if (!mtd[1]) { pr_err("cannot find mtd2\n"); return -EINVAL; } put_mtd_device(mtd[0]); put_mtd_device(mtd[1]); mtd_combine = mtd_concat_create(mtd, 2, "Combine mtd"); if (mtd_combine == NULL) { pr_err("combine failed\n"); return -EINVAL; } mtd_device_register(mtd_combine, NULL, 0); pr_info("Combine success\n"); return 0; } 1. ID="0x20,0xac,0x00,0x15" 2. modprobe nandsim id_bytes=$ID parts=50,100 badblocks=100 3. insmod reproduce.ko 4. flash_erase /dev/mtd3 0 0 libmtd: error!: MEMERASE64 ioctl failed for eraseblock 100 (mtd3) error 5 (Input/output error) // Should be "flash_erase: Skipping bad block at 00c80000" Fixes: 46b5889cc2c54bac ("mtd: implement proper partition handling") Signed-off-by: Zhihao Cheng Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210817114857.2784825-2-chengzhihao1@huawei.com Signed-off-by: Sasha Levin --- drivers/mtd/mtdconcat.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 6e4d0017c0bd..af51eee6b5e8 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -641,6 +641,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c int i; size_t size; struct mtd_concat *concat; + struct mtd_info *subdev_master = NULL; uint32_t max_erasesize, curr_erasesize; int num_erase_region; int max_writebufsize = 0; @@ -679,17 +680,19 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; - if (subdev[0]->_writev) + + subdev_master = mtd_get_master(subdev[0]); + if (subdev_master->_writev) concat->mtd._writev = concat_writev; - if (subdev[0]->_read_oob) + if (subdev_master->_read_oob) concat->mtd._read_oob = concat_read_oob; - if (subdev[0]->_write_oob) + if (subdev_master->_write_oob) concat->mtd._write_oob = concat_write_oob; - if (subdev[0]->_block_isbad) + if (subdev_master->_block_isbad) concat->mtd._block_isbad = concat_block_isbad; - if (subdev[0]->_block_markbad) + if (subdev_master->_block_markbad) concat->mtd._block_markbad = concat_block_markbad; - if (subdev[0]->_panic_write) + if (subdev_master->_panic_write) concat->mtd._panic_write = concat_panic_write; concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -721,14 +724,22 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c subdev[i]->flags & MTD_WRITEABLE; } + subdev_master = mtd_get_master(subdev[i]); concat->mtd.size += subdev[i]->size; concat->mtd.ecc_stats.badblocks += subdev[i]->ecc_stats.badblocks; if (concat->mtd.writesize != subdev[i]->writesize || concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || - !concat->mtd._read_oob != !subdev[i]->_read_oob || - !concat->mtd._write_oob != !subdev[i]->_write_oob) { + !concat->mtd._read_oob != !subdev_master->_read_oob || + !concat->mtd._write_oob != !subdev_master->_write_oob) { + /* + * Check against subdev[i] for data members, because + * subdev's attributes may be different from master + * mtd device. Check against subdev's master mtd + * device for callbacks, because the existence of + * subdev's callbacks is decided by master mtd device. + */ kfree(concat); printk("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); -- 2.30.2