]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mtd: rawnand: serialize lock/unlock against other NAND operations
authorKamal Dasu <kamal.dasu@broadcom.com>
Thu, 5 Mar 2026 19:49:06 +0000 (14:49 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Mar 2026 10:08:56 +0000 (11:08 +0100)
[ Upstream commit bab2bc6e850a697a23b9e5f0e21bb8c187615e95 ]

nand_lock() and nand_unlock() call into chip->ops.lock_area/unlock_area
without holding the NAND device lock. On controllers that implement
SET_FEATURES via multiple low-level PIO commands, these can race with
concurrent UBI/UBIFS background erase/write operations that hold the
device lock, resulting in cmd_pending conflicts on the NAND controller.

Add nand_get_device()/nand_release_device() around the lock/unlock
operations to serialize them against all other NAND controller access.

Fixes: 92270086b7e5 ("mtd: rawnand: Add support for manufacturer specific lock/unlock operation")
Signed-off-by: Kamal Dasu <kamal.dasu@broadcom.com>
Reviewed-by: William Zhang <william.zhang@broadcom.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/mtd/nand/raw/nand_base.c

index 3e1844bfb8089e08d9b19ec3dcc6bfd4a4565cc7..d654e5f52ee09d42160ed2c0502abb36b40ce4ae 100644 (file)
@@ -4868,11 +4868,16 @@ static void nand_shutdown(struct mtd_info *mtd)
 static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
+       int ret;
 
        if (!chip->ops.lock_area)
                return -ENOTSUPP;
 
-       return chip->ops.lock_area(chip, ofs, len);
+       nand_get_device(chip);
+       ret = chip->ops.lock_area(chip, ofs, len);
+       nand_release_device(chip);
+
+       return ret;
 }
 
 /**
@@ -4884,11 +4889,16 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
+       int ret;
 
        if (!chip->ops.unlock_area)
                return -ENOTSUPP;
 
-       return chip->ops.unlock_area(chip, ofs, len);
+       nand_get_device(chip);
+       ret = chip->ops.unlock_area(chip, ofs, len);
+       nand_release_device(chip);
+
+       return ret;
 }
 
 /* Set default functions */