From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24787606A335 for ; Sat, 7 Nov 2026 10:16:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=aRAwQkV9; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=PWb5S/Sf 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:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Unsubscribe-Post:List-Owner; bh=0yYdECXEBmL0j9/e2Su/uJ7P1RVXhTuVkFim8UFs1IE=; b=aRAwQkV9YXnAODR2DwkeQ/Fmkh ShHZE1Y7h/vJevcwY+xnR9nAQZz7gIjfeUMKyiMMak4J4a4KLPzC3ODcxFGw8NSszeJmXcBRITKt6 9T7hlkN2svQuZUynChkBhRFLDX9Y/7DG4HkwgfVqeQeO2QQJ5BrsPWncn7y7JMu1q0T5lJz/1hz5v gqeLiTy5/z/fa4XN7VsqP6X0Z4+3TGzbuFmWkuLZFo7ZzOIyDyJU706CvcE3mH+WgOgNGDtMOHYB6 zwb6RwBu+Y/WeWypjM2b9ZSCQFDbqUxQVIMZR5bBxu3Oag0JjBd1nuF6vXuN67Mwry7biO6fO4qXQ MjMRWfPA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.100.1 #2 (Red Hat Linux)) id 1xPdTe-0000000ET7T-2qKX; Sat, 07 Nov 2026 10:16:50 +0000 Received: from mail-ot1-x32e.google.com ([2607:f8b0:4864:20::32e]) by bombadil.infradead.org with esmtps (Exim 4.100.1 #2 (Red Hat Linux)) id 1xPdTS-0000000ESk6-0EqQ for linux-amlogic@lists.infradead.org; Sat, 07 Nov 2026 10:16:45 +0000 Received: by mail-ot1-x32e.google.com with SMTP id 46e09a7af769-7f48c750afcso835983a34.0 for ; Sat, 07 Nov 2026 02:16:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1794046597; x=1794651397; darn=lists.infradead.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0zdj0JMmNNgvImUjXW+dc1czDRoUybgPmc34A31iLmc=; b=PWb5S/SfGHeBmibj0mEen/VXx714T/WMbpt0zI7U2yarIkPlTBWOq3Fwv0RraGaOA6 gBqKw/wDfimbpCANIQeTk/QPEmbG26SC2MwkHqFGyeY/5pcEeMYyOCH3v3/xE2+JaT1z DUyEvDkn2kbwWDuQW/YpDtkf8nzqIy1cm5Be/NSXcjsZ2YUkTZh1eWYKs6rVyhiLxnNM qpK1i2f5AqdKC3yH7Xve3iXFKKR3PEiCMVpbEowajPbS79td8GUmhnv0TSylGrRdflip 64wFPS60CwqdeC94P3AJYAgOI56KJ5w8MPmunY15lko0kJLFI8edKg6eSmA+On9kjIEK 9Q3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794046597; x=1794651397; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=0zdj0JMmNNgvImUjXW+dc1czDRoUybgPmc34A31iLmc=; b=ZvO2xW7KjIm6GEZ+x6GP6Dm6He1ayWw11hSISY58M4jpyV+ApgbMKNBd+XtuSUmRLF qPUJr4ubg9c5FoColD4pUHiE7L/5WueEKeSYxxmYPjMbwpQIfkKoSzZ1QEdtqyuVQf0r yCcuqyoYy6PJLn/u/GJOomk8Z7me2+/p0ifR0vZORJ0ug5G2g1xpx01DeThHiNrSj1wh lxAkTNLCL7fKguLhvpMfx4CPJaMokyO2dRDUPu7Jj1rjJvt3T+z/IbEIWIsLBfBL+xhc 8914xgmRXYZjyMBdzRKBWys6ptW3k8OgmlCHVGGXYI5PUA7J3EQw3tK4DWavVa0Hz4kw 88Ow== X-Forwarded-Encrypted: i=1; AKwUvBxyokeQuXtdd2yjojq5PbXb2A6Im+tAJPCU1uKTlpwqjUWicTEIdHbBEX4gmBy0ijYC2sJzWT+dXsorCec1@lists.infradead.org X-Gm-Message-State: APuU4Z9Xypq8dUIwdhKMzccolD6QwXkLnD8/j+trKdhcSHOF+DaBtMcR 39fMauB2RetNTZ3rY5X5giZybYmC3ji99yWs80e2G3LTjYSKVkHvljr5 X-Gm-Gg: AYBFou2+7Hk7wfD00uJrW/KB8kxocZDe+05DwdxDa8eZcCdOBet4qhoiEuqFKR8YkjA YOqNwux4/J6Q1OPrC6xXECMTiz5XpZ6dVJceP6/IBJa668qdeCLVr7mGBm+c0DVSS9t0GHSZLyV l98UX4/OM4H1h6JfbeBqA0cYcazUuxMwJ6jtSu85HQZd/upN3XTrl/oCoZBGH6/TjZDHUcSAXYE CNKSk6pCPvslygyenw2Tgfuhs7HNVgY3oBjhajXHhgdbD0Dn8nZ7KU34yqyr8prubzcxvosbl66 OBdYKwgyI16vJBnsTr43jnh/Q7xXzCogxbss8ENj121mGYVE2g+TCB+QY+1ren9KRNSZkG4tJ7I CcXk973nAQ+nJLsl5zg3EvYr533GU8pJC3MnA9YbRW8q8KUwTEdnwSuDIjLAUG9Cs6r7+6SAoWJ 2YX3tpa3ESRQnKxxvFt3+Xut+3WZO0zv6zFk6vA5F1vHz/EmMBAT6HUEWyZ+j32W0hOhHDVhabC EWyTOpxgB4km6XEtcFNcdwYlv7fzbaH0kSwutTzHN+EtrKv2T/+liFKPHVSrYJ7F3xg9CuQWTlU gnS5I1KMeeXYUts2Ug8cgIdg/2fzpV10CLcJictwsJZdWF/jWITto7DAdSq4B8QQfc1YHJ7aTa6 OcpQU5z4z+lTfEwPod85dWf4CXwkEMyB/DuhW+WdT7K5BDGyuvK90kGRfKAMG3GofG/v0Xh6mhP wVni0fCrs8ach0g7xy52PVh1et5Cro/3XRTuJy+AizbYMFi4SgwNXO X-Received: by 2002:a05:6830:6809:b0:85e:ef69:238a with SMTP id 46e09a7af769-85f1cfce0famr5153719a34.11.1794046596984; Sat, 07 Nov 2026 02:16:36 -0800 (PST) Received: from [127.0.1.1] (174-29-1-49.hlrn.qwest.net. [174.29.1.49]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-85f1dbef224sm3990269a34.12.2026.11.07.02.16.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Nov 2026 02:16:36 -0800 (PST) From: James Hilliard Date: Sat, 07 Nov 2026 03:16:01 -0700 Subject: [PATCH 04/58] mtd: rawnand: separate hardware disconnection from cleanup X-Archived-By: MIME-Version: 1.0 Message-Id: <20261107-submit-rawnand-retained-handle-lifetime-v1-v1-4-0181ef0cc4c8@gmail.com> References: <20261107-submit-rawnand-retained-handle-lifetime-v1-v1-0-0181ef0cc4c8@gmail.com> In-Reply-To: <20261107-submit-rawnand-retained-handle-lifetime-v1-v1-0-0181ef0cc4c8@gmail.com> To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Brian Norris , Boris Brezillon , Arseniy Krasnov , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Thomas Gleixner , Vitaly Wool , David Woodhouse , Russell King , David Woodhouse , Mike Rapoport , Maxime Coquelin , Alexandre Torgue , Christophe Kerello , Jason Roberts , Michal Simek , Boris Brezillon , Mason Yang , Ramuthevar Vadivel Murugan , Stefan Agner , Lucas Stach , Thierry Reding , Jonathan Hunter , Dmitry Osipenko , Matthias Brugger , AngeloGioacchino Del Regno , Jorge Ramirez-Ortiz , Heiko Stuebner , Yifeng Zhao , Nicolas Ferre , Alexandre Belloni , Claudiu Beznea , Keguang Zhang , Jacky Huang , Shan-Chun Hung , Frank Li , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , Han Xu , Liang Yang , Neil Armstrong , Kevin Hilman , Jerome Brunet , Martin Blumenstingl , Manivannan Sadhasivam , Kamal Dasu , Broadcom internal kernel review list , Vladimir Zapolskiy , Piotr Wojtaszczyk , Paul Cercueil , Harvey Hunt , Maxim Levitsky , Michael Walle , Srinivas Kandagatla Cc: Tze Yee Ng , linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-tegra@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-mips@vger.kernel.org, imx@lists.linux.dev, linux-renesas-soc@vger.kernel.org, linux-amlogic@lists.infradead.org, linux-arm-msm@vger.kernel.org, James Hilliard X-Mailer: b4 0.15.2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20261107_021638_972953_9E2A94E1 X-CRM114-Status: GOOD ( 27.40 ) X-Spam-Score: -1.9 (-) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-amlogic" X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF, FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on aws-us-west-2-korg-listserv-alma10-1 A retained MTD handle can still enter NAND operations after its controller is unbound. Closing a writable character device also calls nand_sync(), which takes the chip and controller locks. Freeing their storage during remove is therefore unsafe even without another explicit read or write. Add nand_disconnect() to serialize disconnection with regular operations under the chip and controller locks. Make nand_get_device() reject a disconnected chip and propagate that error through its callers. A sync after disconnection becomes a no-op. Suspend and resume also honor the disconnected state. Unregister MTD devices first so removal notifiers can finish their I/O, then disconnect before releasing controller resources. Wake any remaining suspended waiters when disconnecting. Panic writes also check the disconnected flag; their notifier clients must be drained by MTD unregistration before controller resources are released. Keep nand_cleanup() separate. Controllers adopting this interface must retain the chip, controller lock storage and NAND metadata until their last MTD and device references are gone. Signed-off-by: James Hilliard --- drivers/mtd/nand/raw/nand_base.c | 76 +++++++++++++++++++++++++++++++++------- include/linux/mtd/rawnand.h | 9 +++-- 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index a5b278ab9384..8f7d2571e8d9 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -336,21 +336,47 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) * * Lock the device and its controller for exclusive access */ -static void nand_get_device(struct nand_chip *chip) +static int nand_get_device(struct nand_chip *chip) { /* Wait until the device is resumed. */ while (1) { mutex_lock(&chip->lock); + if (chip->disconnected) { + mutex_unlock(&chip->lock); + return -ENODEV; + } if (!chip->suspended) { mutex_lock(&chip->controller->lock); - return; + return 0; } mutex_unlock(&chip->lock); - wait_event(chip->resume_wq, !chip->suspended); + wait_event(chip->resume_wq, !READ_ONCE(chip->suspended) || + READ_ONCE(chip->disconnected)); } } +/** + * nand_disconnect - drain hardware access and reject further operations + * @chip: NAND chip object + * + * Unregister the MTD device first so removal notifiers can finish their I/O. + * Call before releasing controller resources. Operations waiting for resume + * are woken and fail with -ENODEV. + * The chip, controller lock and NAND metadata must remain alive + * until existing MTD handles are released; nand_cleanup() is a separate step. + */ +void nand_disconnect(struct nand_chip *chip) +{ + mutex_lock(&chip->lock); + mutex_lock(&chip->controller->lock); + WRITE_ONCE(chip->disconnected, true); + mutex_unlock(&chip->controller->lock); + mutex_unlock(&chip->lock); + wake_up_all(&chip->resume_wq); +} +EXPORT_SYMBOL_GPL(nand_disconnect); + /** * nand_check_wp - [GENERIC] check if the chip is write protected * @chip: NAND chip object @@ -581,7 +607,9 @@ 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 */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; ret = nand_markbad_bbm(chip, ofs); nand_release_device(chip); @@ -3879,7 +3907,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->mode != MTD_OPS_RAW) return -ENOTSUPP; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; old_stats = mtd->ecc_stats; @@ -4449,6 +4479,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, struct mtd_oob_ops ops; int ret; + if (READ_ONCE(chip->disconnected)) + return -ENODEV; + nand_select_target(chip, chipnr); /* Wait for the device to get ready */ @@ -4479,7 +4512,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ops->retlen = 0; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4539,7 +4574,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, return -EIO; /* Grab the lock and see if the device is available */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -4627,7 +4664,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 */ - nand_get_device(chip); + if (nand_get_device(chip)) + return; /* Release it and go back */ nand_release_device(chip); } @@ -4644,7 +4682,9 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) int ret; /* Select the NAND device */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; nand_select_target(chip, chipnr); @@ -4688,10 +4728,14 @@ static int nand_suspend(struct mtd_info *mtd) int ret = 0; mutex_lock(&chip->lock); + if (chip->disconnected) { + mutex_unlock(&chip->lock); + return -ENODEV; + } if (chip->ops.suspend) ret = chip->ops.suspend(chip); if (!ret) - chip->suspended = 1; + WRITE_ONCE(chip->suspended, true); mutex_unlock(&chip->lock); return ret; @@ -4706,10 +4750,12 @@ static void nand_resume(struct mtd_info *mtd) struct nand_chip *chip = mtd_to_nand(mtd); scoped_guard(mutex, &chip->lock) { + if (chip->disconnected) + return; if (chip->suspended) { if (chip->ops.resume) chip->ops.resume(chip); - chip->suspended = 0; + WRITE_ONCE(chip->suspended, false); } else { pr_err("%s called for a chip which is not in suspended state\n", __func__); @@ -4743,7 +4789,9 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (!chip->ops.lock_area) return -ENOTSUPP; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; ret = chip->ops.lock_area(chip, ofs, len); nand_release_device(chip); @@ -4764,7 +4812,9 @@ static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (!chip->ops.unlock_area) return -ENOTSUPP; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; ret = chip->ops.unlock_area(chip, ofs, len); nand_release_device(chip); diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 5c70e7bd3ed5..90b2169cc745 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1264,9 +1264,10 @@ 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 + * @lock: Lock protecting the suspended and disconnected fields. Also serializes + * accesses to the NAND device * @suspended: Set to 1 when the device is suspended, 0 when it's not + * @disconnected: Controller resources are unavailable; reject hardware access * @resume_wq: wait queue to sleep if rawnand is in suspended state. * @cur_cs: Currently selected target. -1 means no target selected, otherwise we * should always have cur_cs >= 0 && cur_cs < nanddev_ntargets(). @@ -1326,7 +1327,8 @@ struct nand_chip { /* Internals */ struct mutex lock; - unsigned int suspended : 1; + bool suspended; + bool disconnected; wait_queue_head_t resume_wq; int cur_cs; int read_retries; @@ -1595,6 +1597,7 @@ void nand_wait_ready(struct nand_chip *chip); * sucessful nand_scan(). */ void nand_cleanup(struct nand_chip *chip); +void nand_disconnect(struct nand_chip *chip); /* * External helper for controller drivers that have to implement the WAITRDY -- 2.53.0 _______________________________________________ linux-amlogic mailing list linux-amlogic@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-amlogic