From patchwork Mon Oct 11 11:52:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 1539274 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=0q+sqgba; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=geanix.com header.i=@geanix.com header.a=rsa-sha256 header.s=first header.b=VWT4H8p9; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4HScf52tPkz9sPB for ; Mon, 11 Oct 2021 22:54:21 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=WsL9SbEcxygvt8q/8h4FF5n8zjvwSawivSPzSmt/hBk=; b=0q+sqgbaZsrHyr 6IwhQzwEzCEisJ3NvyQTT9ucCgoLXTPwj7Wf1fHBMeZGvCenoQXkGVzcwHg1mFe9on9OXq7QOVIWC JcDm2h7jMuWw3Z4p35T89sdfndWwvxr7vb62DPJOC0/V7P+6Td6DMRtYKLXXvjm48m2sLUr377VHk M+GizYAVYlOH6xE1BPk+X+Oo8jAOLjdarEDiZCme1+4Oalldq6V660DOrX7M6SPPXjbWrfe3F+KAK RRIBFSy1rx2tZzQVhagUafWPQEVL38is2PGx2XiW42lAopmTR5M/cHLHK8krkEODPsj847D03mPTT xooOcbSFIJVbzu0JOIVQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtsC-009Do1-Af; Mon, 11 Oct 2021 11:53:40 +0000 Received: from first.geanix.com ([116.203.34.67]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtrr-009DgZ-12 for linux-mtd@lists.infradead.org; Mon, 11 Oct 2021 11:53:21 +0000 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id D7CF0C3DAF; Mon, 11 Oct 2021 11:53:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1633953194; bh=0zDQiRwHm1wvs57rK5lMS4f3kyKcpKi3AIaDDdl1PjM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=VWT4H8p9lBVJzwQnLZ0kd+GEl7lZa0te8Jx3RUIWlIqEiYs5jHwtnOLkTPX7mcHm3 6KQae7DQBfyFhaoWVELWx2AOY1AIxM3HgsW49FCwsZgsrtDxe8xwD3X+J61HzlpkoE H7w36ZNpbaPE5mYQubrt+37xo9J+zKSxmEe9PGxpaqwt/ZGSgcFXPaze6sHjU/mqRu Hg9zoiySXhNxgOZJ9MSg5ZdQbKDKrkuu1/0qcEfPb9oPyCmsWagd8JajbIV3I0gOYi 7JGwPOmDOxbSvZtD/8OSWSZAnDEyxdK/BWXrbTyztvY5mlqoLIJnjU5DLxUOiODKjs 2vRQAeUbipcAQ== From: Sean Nyekjaer To: Boris Brezillon Cc: Sean Nyekjaer , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Boris Brezillon , linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/3] mtd: core: protect access to MTD devices while in suspend Date: Mon, 11 Oct 2021 13:52:51 +0200 Message-Id: <20211011115253.38497-2-sean@geanix.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011115253.38497-1-sean@geanix.com> References: <20211011115253.38497-1-sean@geanix.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3.1 required=4.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED autolearn=disabled version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 13e2a5895688 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211011_045319_437673_E876584F X-CRM114-Status: GOOD ( 22.15 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Prevent accessing the devices while in a suspended state. Also prevent suspending a device which is still currently in use. Commit 013e6292aaf5 ("mtd: rawnand: Simplify the locking") allows the rawnand layer to return errors rather than waiting in a blocking wait. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Prevent accessing the devices while in a suspended state. Also prevent suspending a device which is still currently in use. Commit 013e6292aaf5 ("mtd: rawnand: Simplify the locking") allows the rawnand layer to return errors rather than waiting in a blocking wait. Tested on a iMX6ULL. Fixes: 013e6292aaf5 ("mtd: rawnand: Simplify the locking") Suggested-by: Boris Brezillon Signed-off-by: Sean Nyekjaer Reported-by: kernel test robot --- drivers/mtd/mtdcore.c | 133 +++++++++++++++++++++++++++++++++++----- include/linux/mtd/mtd.h | 109 +++++++++++++++++++++++++++----- 2 files changed, 211 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c8fd7f758938..51be9b46ef54 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -777,6 +777,8 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd) INIT_LIST_HEAD(&mtd->partitions); mutex_init(&mtd->master.partitions_lock); mutex_init(&mtd->master.chrdev_lock); + init_waitqueue_head(&mtd->master.resume_wq); + init_rwsem(&mtd->master.suspend_lock); } static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user) @@ -1257,6 +1259,8 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) ledtrig_mtd_activity(); + mtd_start_access(mtd); + if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) { adjinstr.addr = (loff_t)mtd_div_by_eb(instr->addr, mtd) * master->erasesize; @@ -1278,6 +1282,8 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) } } + mtd_end_access(mtd); + return ret; } EXPORT_SYMBOL_GPL(mtd_erase); @@ -1289,6 +1295,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys) { struct mtd_info *master = mtd_get_master(mtd); + int ret; *retlen = 0; *virt = NULL; @@ -1301,8 +1308,12 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, if (!len) return 0; + mtd_start_access(mtd); from = mtd_get_master_ofs(mtd, from); - return master->_point(master, from, len, retlen, virt, phys); + ret = master->_point(master, from, len, retlen, virt, phys); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_point); @@ -1310,6 +1321,7 @@ EXPORT_SYMBOL_GPL(mtd_point); int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_unpoint) return -EOPNOTSUPP; @@ -1317,7 +1329,12 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) return -EINVAL; if (!len) return 0; - return master->_unpoint(master, mtd_get_master_ofs(mtd, from), len); + + mtd_start_access(mtd); + ret = master->_unpoint(master, mtd_get_master_ofs(mtd, from), len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_unpoint); @@ -1372,6 +1389,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, }; int ret; + /* mtd_read_oob handles mtd access protection */ ret = mtd_read_oob(mtd, from, &ops); *retlen = ops.retlen; @@ -1388,6 +1406,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, }; int ret; + /* mtd_write_oob handles mtd access protection */ ret = mtd_write_oob(mtd, to, &ops); *retlen = ops.retlen; @@ -1406,6 +1425,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct mtd_info *master = mtd_get_master(mtd); + int ret; *retlen = 0; if (!master->_panic_write) @@ -1419,8 +1439,12 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, if (!master->oops_panic_write) master->oops_panic_write = true; - return master->_panic_write(master, mtd_get_master_ofs(mtd, to), len, - retlen, buf); + mtd_start_access(mtd); + ret = master->_panic_write(master, mtd_get_master_ofs(mtd, to), len, + retlen, buf); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_panic_write); @@ -1566,6 +1590,8 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ledtrig_mtd_activity(); + mtd_start_access(mtd); + /* Check the validity of a potential fallback on mtd->_read */ if (!master->_read_oob && (!master->_read || ops->oobbuf)) return -EOPNOTSUPP; @@ -1576,7 +1602,7 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ret_code = mtd_read_oob_std(mtd, from, ops); mtd_update_ecc_stats(mtd, master, &old_stats); - + mtd_end_access(mtd); /* * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics * similar to mtd->_read(), returning a non-negative integer @@ -1597,6 +1623,8 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_info *master = mtd_get_master(mtd); int ret; + mtd_start_access(mtd); + ops->retlen = ops->oobretlen = 0; if (!(mtd->flags & MTD_WRITEABLE)) @@ -1615,7 +1643,10 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to, if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) return mtd_io_emulated_slc(mtd, to, false, ops); - return mtd_write_oob_std(mtd, to, ops); + ret = mtd_write_oob_std(mtd, to, ops); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_write_oob); @@ -1992,12 +2023,18 @@ int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_get_fact_prot_info) return -EOPNOTSUPP; if (!len) return 0; - return master->_get_fact_prot_info(master, len, retlen, buf); + + mtd_start_access(mtd); + ret = master->_get_fact_prot_info(master, len, retlen, buf); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info); @@ -2005,13 +2042,19 @@ int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_info *master = mtd_get_master(mtd); + int ret; *retlen = 0; if (!master->_read_fact_prot_reg) return -EOPNOTSUPP; if (!len) return 0; - return master->_read_fact_prot_reg(master, from, len, retlen, buf); + + mtd_start_access(mtd); + ret = master->_read_fact_prot_reg(master, from, len, retlen, buf); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg); @@ -2019,12 +2062,18 @@ int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_get_user_prot_info) return -EOPNOTSUPP; if (!len) return 0; - return master->_get_user_prot_info(master, len, retlen, buf); + + mtd_start_access(mtd); + ret = master->_get_user_prot_info(master, len, retlen, buf); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_get_user_prot_info); @@ -2032,13 +2081,19 @@ int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_info *master = mtd_get_master(mtd); + int ret; *retlen = 0; if (!master->_read_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0; - return master->_read_user_prot_reg(master, from, len, retlen, buf); + + mtd_start_access(mtd); + ret = master->_read_user_prot_reg(master, from, len, retlen, buf); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg); @@ -2053,7 +2108,11 @@ int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, return -EOPNOTSUPP; if (!len) return 0; + + mtd_start_access(mtd); ret = master->_write_user_prot_reg(master, to, len, retlen, buf); + mtd_end_access(mtd); + if (ret) return ret; @@ -2068,24 +2127,36 @@ EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg); int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_lock_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0; - return master->_lock_user_prot_reg(master, from, len); + + mtd_start_access(mtd); + ret = master->_lock_user_prot_reg(master, from, len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg); int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_erase_user_prot_reg) return -EOPNOTSUPP; if (!len) return 0; - return master->_erase_user_prot_reg(master, from, len); + + mtd_start_access(mtd); + ret = master->_erase_user_prot_reg(master, from, len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_erase_user_prot_reg); @@ -2093,6 +2164,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_user_prot_reg); int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_lock) return -EOPNOTSUPP; @@ -2106,13 +2178,18 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize; } - return master->_lock(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_start_access(mtd); + ret = master->_lock(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_lock); int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_unlock) return -EOPNOTSUPP; @@ -2126,13 +2203,18 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize; } - return master->_unlock(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_start_access(mtd); + ret = master->_unlock(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_unlock); int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_is_locked) return -EOPNOTSUPP; @@ -2146,13 +2228,18 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) len = (u64)mtd_div_by_eb(len, mtd) * master->erasesize; } - return master->_is_locked(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_start_access(mtd); + ret = master->_is_locked(master, mtd_get_master_ofs(mtd, ofs), len); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_is_locked); int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (ofs < 0 || ofs >= mtd->size) return -EINVAL; @@ -2162,13 +2249,18 @@ int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs) if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize; - return master->_block_isreserved(master, mtd_get_master_ofs(mtd, ofs)); + mtd_start_access(mtd); + ret = master->_block_isreserved(master, mtd_get_master_ofs(mtd, ofs)); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_block_isreserved); int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (ofs < 0 || ofs >= mtd->size) return -EINVAL; @@ -2178,7 +2270,11 @@ int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize; - return master->_block_isbad(master, mtd_get_master_ofs(mtd, ofs)); + mtd_start_access(mtd); + ret = master->_block_isbad(master, mtd_get_master_ofs(mtd, ofs)); + mtd_end_access(mtd); + + return ret; } EXPORT_SYMBOL_GPL(mtd_block_isbad); @@ -2197,7 +2293,10 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) ofs = (loff_t)mtd_div_by_eb(ofs, mtd) * master->erasesize; + mtd_start_access(mtd); ret = master->_block_markbad(master, mtd_get_master_ofs(mtd, ofs)); + mtd_end_access(mtd); + if (ret) return ret; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 88227044fc86..7765d1fcfc8b 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -231,6 +231,8 @@ struct mtd_master { struct mutex partitions_lock; struct mutex chrdev_lock; unsigned int suspended : 1; + wait_queue_head_t resume_wq; + struct rw_semaphore suspend_lock; }; struct mtd_info { @@ -476,10 +478,49 @@ static inline u32 mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops) return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; } +static inline void mtd_start_access(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + + /* + * Don't take the suspend_lock on devices that don't + * implement the suspend hook. Otherwise, lockdep will + * complain about nested locks when trying to suspend MTD + * partitions or MTD devices created by gluebi which are + * backed by real devices. + */ + if (!master->_suspend) + return; + + /* + * Wait until the device is resumed. Should we have a + * non-blocking mode here? + */ + while (1) { + down_read(&master->master.suspend_lock); + if (!master->master.suspended) + return; + + up_read(&master->master.suspend_lock); + wait_event(master->master.resume_wq, master->master.suspended == 0); + } +} + +static inline void mtd_end_access(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + + if (!master->_suspend) + return; + + up_read(&master->master.suspend_lock); +} + static inline int mtd_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_info *master = mtd_get_master(mtd); + int ret; if (!master->_max_bad_blocks) return -ENOTSUPP; @@ -487,8 +528,12 @@ static inline int mtd_max_bad_blocks(struct mtd_info *mtd, if (mtd->size < (len + ofs) || ofs < 0) return -EINVAL; - return master->_max_bad_blocks(master, mtd_get_master_ofs(mtd, ofs), - len); + mtd_start_access(mtd); + ret = master->_max_bad_blocks(master, mtd_get_master_ofs(mtd, ofs), + len); + mtd_end_access(mtd); + + return ret; } int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, @@ -543,33 +588,69 @@ int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs); int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs); int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs); +static inline int __mtd_suspend(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + int ret = 0; + + if (!master->_suspend) + return ret; + + if (!master->master.suspended) { + ret = master->_suspend(master); + if (!ret) + master->master.suspended = 1; + } + + return ret; +} + static inline int mtd_suspend(struct mtd_info *mtd) { struct mtd_info *master = mtd_get_master(mtd); - int ret; + int ret = 0; - if (master->master.suspended) - return 0; + if (!master->_suspend) + return ret; - ret = master->_suspend ? master->_suspend(master) : 0; - if (ret) + down_write(&master->master.suspend_lock); + ret = __mtd_suspend(mtd); + up_write(&master->master.suspend_lock); + + return ret; +} + +static inline int __mtd_resume(struct mtd_info *mtd) +{ + struct mtd_info *master = mtd_get_master(mtd); + int ret = 0; + + if (!master->_suspend) return ret; - master->master.suspended = 1; - return 0; + if (master->master.suspended) { + if (master->_resume) + master->_resume(master); + + master->master.suspended = 0; + ret = 1; + } + + return ret; } static inline void mtd_resume(struct mtd_info *mtd) { struct mtd_info *master = mtd_get_master(mtd); - if (!master->master.suspended) + if (!master->_suspend) return; - if (master->_resume) - master->_resume(master); - - master->master.suspended = 0; + down_write(&master->master.suspend_lock); + /* If MTD dev has been resumed, wake up all waiters. */ + if (__mtd_resume(mtd)) + wake_up_all(&master->master.resume_wq); + up_write(&master->master.suspend_lock); } static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) From patchwork Mon Oct 11 11:52:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 1539276 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=nfkgYOXQ; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=geanix.com header.i=@geanix.com header.a=rsa-sha256 header.s=first header.b=PXIV1kRs; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4HScg36YW9z9sPB for ; Mon, 11 Oct 2021 22:55:11 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=4+IkycxS+ZwK3uPZ0Bmr5Nc+MdVy7ekxSiWuNXYcDdo=; b=nfkgYOXQXtwcFl X4uynGgZDX0Xsc1TgkKY7BKEMUymj1PL86ONT4FThdEFpWVe5ZJ+PonxTxaVXeTJ6x2WHFEWv+KOu ruR7JoJiAedw0ylZhkjrllj33jM0SfelAotLcgexkUG/sm8NAsecQePUX0K2R2H01duucSvDbGwlA PiQ31q/O9lWGxY1dwtpZ21rLovUK85A48fweyhyU2OMmvj55oDiEKfQxvwytqkF/UxFKR0TZfoRKo Y85Ec5i2gisHQ3Lm0uAK1LVJ8roP+WIZvqAMsQvhR7WZt0DtnwnVbbdLHS5VFA5wQboEKp3iPsp7s PnC6FBWgkNFQSeoMSv5w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtst-009Dz4-Mr; Mon, 11 Oct 2021 11:54:23 +0000 Received: from first.geanix.com ([116.203.34.67]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtrs-009Dgr-4V for linux-mtd@lists.infradead.org; Mon, 11 Oct 2021 11:53:22 +0000 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id D5E38C3DB0; Mon, 11 Oct 2021 11:53:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1633953196; bh=cGWPCXk1Wny7/Ezf/s8a4wUpVvPCYTV59Za745o2o5Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=PXIV1kRs62TAbqB3Hv5gZjcK9DOzR4zxBK7Exqx9pX7kUsntW251jH5df48zGELXc roWqVcZpGjDftgVxEw9i5DvcUem+xiUjBMP7CaS5O44tbMtnkhkVluoOjPdKkyDPC/ kGiqi9D066xMTXdOt5dM2sAX5Y9KA535o3kDnf+rp1MUtD/TA0wBSGIRlurLjIIlF/ JwjbyMjAQyuoBDVbhTn1jn1pW93CRcisWdtZFj3r9BpqecYS+ScOx5dMxGwItjdh1R xWT2ZxZINAwxPVsqfN5Mfbr1wzn6PVJ+hGThOvGUgU6UkIb22if+pMzI5jA4couo1P DwsFOk8APXQ2A== From: Sean Nyekjaer To: Boris Brezillon Cc: Sean Nyekjaer , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Boris Brezillon , linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/3] mtd: rawnand: remove suspended check Date: Mon, 11 Oct 2021 13:52:52 +0200 Message-Id: <20211011115253.38497-3-sean@geanix.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011115253.38497-1-sean@geanix.com> References: <20211011115253.38497-1-sean@geanix.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3.1 required=4.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED autolearn=disabled version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 13e2a5895688 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211011_045320_530390_37C14B8D X-CRM114-Status: GOOD ( 21.88 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Access is protected in upper MTD layer when MTD devices are suspended. Fixes: 013e6292aaf5 ("mtd: rawnand: Simplify the locking") Reviewed-by: Miquel Raynal Signed-off-by: Sean Nyekjaer --- drivers/mtd/nand/raw/nand_base.c | [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Access is protected in upper MTD layer when MTD devices are suspended. Fixes: 013e6292aaf5 ("mtd: rawnand: Simplify the locking") Reviewed-by: Miquel Raynal Signed-off-by: Sean Nyekjaer --- drivers/mtd/nand/raw/nand_base.c | 52 ++++++++------------------------ include/linux/mtd/rawnand.h | 5 +-- 2 files changed, 14 insertions(+), 43 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 3d6c6e880520..aa2874ae3c4a 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -332,19 +332,11 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) * @chip: NAND chip structure * * Lock the device and its controller for exclusive access - * - * Return: -EBUSY if the chip has been suspended, 0 otherwise */ -static int nand_get_device(struct nand_chip *chip) +static void nand_get_device(struct nand_chip *chip) { mutex_lock(&chip->lock); - if (chip->suspended) { - mutex_unlock(&chip->lock); - return -EBUSY; - } mutex_lock(&chip->controller->lock); - - return 0; } /** @@ -573,10 +565,7 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ - ret = nand_get_device(chip); - if (ret) - return ret; - + nand_get_device(chip); ret = nand_markbad_bbm(chip, ofs); nand_release_device(chip); } @@ -3756,9 +3745,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->mode != MTD_OPS_RAW) return -ENOTSUPP; - ret = nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); if (!ops->datbuf) ret = nand_do_read_oob(chip, from, ops); @@ -4345,13 +4332,11 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct nand_chip *chip = mtd_to_nand(mtd); - int ret; + int ret = 0; ops->retlen = 0; - ret = nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4410,10 +4395,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, if (nand_region_is_secured(chip, instr->addr, instr->len)) return -EIO; - /* Grab the lock and see if the device is available */ - ret = nand_get_device(chip); - if (ret) - return ret; + /* Grab the lock */ + nand_get_device(chip); /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -4499,8 +4482,8 @@ static void nand_sync(struct mtd_info *mtd) pr_debug("%s: called\n", __func__); - /* Grab the lock and see if the device is available */ - WARN_ON(nand_get_device(chip)); + /* Grab the lock */ + nand_get_device(chip); /* Release it and go back */ nand_release_device(chip); } @@ -4517,9 +4500,7 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) int ret; /* Select the NAND device */ - ret = nand_get_device(chip); - if (ret) - return ret; + nand_get_device(chip); nand_select_target(chip, chipnr); @@ -4565,8 +4546,6 @@ static int nand_suspend(struct mtd_info *mtd) mutex_lock(&chip->lock); if (chip->ops.suspend) ret = chip->ops.suspend(chip); - if (!ret) - chip->suspended = 1; mutex_unlock(&chip->lock); return ret; @@ -4580,15 +4559,10 @@ static void nand_resume(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); + mutex_lock(&chip->lock); - if (chip->suspended) { - if (chip->ops.resume) - chip->ops.resume(chip); - chip->suspended = 0; - } else { - pr_err("%s called for a chip which is not in suspended state\n", - __func__); - } + if (chip->ops.resume) + chip->ops.resume(chip); mutex_unlock(&chip->lock); } diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index b2f9dd3cbd69..1198a6548912 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1237,9 +1237,7 @@ struct nand_secure_region { * @pagecache.page: Page number currently in the cache. -1 means no page is * currently cached * @buf_align: Minimum buffer alignment required by a platform - * @lock: Lock protecting the suspended field. Also used to serialize accesses - * to the NAND device - * @suspended: Set to 1 when the device is suspended, 0 when it's not + * @lock: Lock to serialize accesses to the NAND device * @cur_cs: Currently selected target. -1 means no target selected, otherwise we * should always have cur_cs >= 0 && cur_cs < nanddev_ntargets(). * NAND Controller drivers should not modify this value, but they're @@ -1293,7 +1291,6 @@ struct nand_chip { /* Internals */ struct mutex lock; - unsigned int suspended : 1; int cur_cs; int read_retries; struct nand_secure_region *secure_regions; From patchwork Mon Oct 11 11:52:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Nyekjaer X-Patchwork-Id: 1539275 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=mSg6r08n; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=geanix.com header.i=@geanix.com header.a=rsa-sha256 header.s=first header.b=cLbnL/2o; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4HScfR2gB5z9sPB for ; Mon, 11 Oct 2021 22:54:39 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=C1YWpOD05D431iGXVJ+goEmOiiKWB3NiLqdSr5JuOCY=; b=mSg6r08ncR06LE j2fp6unmKcYpOSVRRE/Evk6C8DxnjjcAbO5L8Ef0YEJOk4e+MwTwcDD76MKD16SWMwKL8Da/eUu0h SdBbkwlMDf72leHJGUAHFyeAn8pZC0G+ry/u+I660kzngDw8IYyRtzxVi/y1OX5ImA2x1N9r+iyR5 OLhaa/CQGQxhdVEH9gd1J8rDVrI0dqQdHJ4JOcETdjisKBoDjucKmUUhT8CvsfIJTsOiRUorNeaRd Fl7w5SAvk04dazKa5ZTilreMf2l51SvHc2vnG/HZwlxhpsJuRenFqlGu5yJxR1k3QfHbiirSvzpaD NNyGX66VCNSJ9uGP+pBQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtsV-009DsX-LP; Mon, 11 Oct 2021 11:53:59 +0000 Received: from first.geanix.com ([116.203.34.67]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZtrr-009DhE-CX for linux-mtd@lists.infradead.org; Mon, 11 Oct 2021 11:53:22 +0000 Received: from zen.. (unknown [185.17.218.86]) by first.geanix.com (Postfix) with ESMTPSA id 1407DC3DB1; Mon, 11 Oct 2021 11:53:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=geanix.com; s=first; t=1633953197; bh=34RYAExQV2GpY9VYCNMKcw7k5EiKJcu+XcF5wGblsM4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=cLbnL/2oqSJXV6k+rEsBn8xJ6hh2Uy0h9AV9bhlXm1qH4AVfcRSAwGvYc1YbKpZ9f GzxqKaLnTvcKgrnZasC/r54GYgLLJw5lk26xT/SzqdPUEDK649rqdbLu+R3JYUMgbX +1tjer7lxABiiU8+xKDkE3QKxaY3INCKEPQmpclczGta4CsMidBH+7Jx+SamO5MSZV 6ZUYirx6U3cwvs1dUFU/xGXC2avs2hq8iUhXhsiZzfLXowdb3vr4RsYLhG6F6i+Vug Tdl4G4HBuhPY01882a2GJJZeI5uz9obr9uwFpzrhGioz/0Ld5bXFjrRugPFySy8Rqp Qu8CydY3xxLpw== From: Sean Nyekjaer To: Boris Brezillon Cc: Sean Nyekjaer , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Boris Brezillon , linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/3] mtd: mtdconcat: add suspend lock handling Date: Mon, 11 Oct 2021 13:52:53 +0200 Message-Id: <20211011115253.38497-4-sean@geanix.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011115253.38497-1-sean@geanix.com> References: <20211011115253.38497-1-sean@geanix.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3.1 required=4.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_BLOCKED autolearn=disabled version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 13e2a5895688 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211011_045319_608698_B6310FB8 X-CRM114-Status: GOOD ( 14.57 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Use new suspend lock handling for this special case for concatenated MTD devices. Fixes: 013e6292aaf5 ("mtd: rawnand: Simplify the locking") Signed-off-by: Sean Nyekjaer --- drivers/mtd/mtdconcat.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Use new suspend lock handling for this special case for concatenated MTD devices. Fixes: 013e6292aaf5 ("mtd: rawnand: Simplify the locking") Signed-off-by: Sean Nyekjaer --- drivers/mtd/mtdconcat.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index f685a581df48..c497c851481f 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -561,25 +561,32 @@ static void concat_sync(struct mtd_info *mtd) static int concat_suspend(struct mtd_info *mtd) { + struct mtd_info *master = mtd_get_master(mtd); struct mtd_concat *concat = CONCAT(mtd); int i, rc = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - if ((rc = mtd_suspend(subdev)) < 0) + + down_write(&master->master.suspend_lock); + if ((rc = __mtd_suspend(subdev)) < 0) return rc; + up_write(&master->master.suspend_lock); } return rc; } static void concat_resume(struct mtd_info *mtd) { + struct mtd_info *master = mtd_get_master(mtd); struct mtd_concat *concat = CONCAT(mtd); int i; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - mtd_resume(subdev); + down_write(&master->master.suspend_lock); + __mtd_resume(subdev); + up_write(&master->master.suspend_lock); } }