From patchwork Wed Oct 4 13:52:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 821317 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="ZeJrzrCC"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y6cnQ4Sbbz9s7M for ; Thu, 5 Oct 2017 00:53:46 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=I/Vh1hFYCk3fb8iZSB8bvXPmE0Y6ZEnbYlSKlUEqQ2g=; b=ZeJ rzrCCwturj9uZN6AOiO77lk7hYLRKsfMp4Hm3pdInQ7XR8KEH/9iOMmVbsBQGTTWMW/6qjyR6etSq m1Qy/Zcjlw23jrSxg5+RfoIYnhWXAM/G4FvFjJ6kdHr6x7aCcYVvGiRSrRENtcA+LIaAnfZ8mod7i JHizPdzOf0r77SWSEGnbHfJfKevG4yZaX5t8+xoYeEgh3pE5sCur29KABQ/Qg2PSG2jLtNzWU6hcD oHGNIFpFmiWHpz0Pi42swxC492YLeLA4iKWzOD5jUoVJD07rkd8FZU6pxvLalRt5+8SD2MpytZsUG oJcZCPvoED5zMTcOAAlm2iCPQr8bcqw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dzk7C-0002fW-Rc; Wed, 04 Oct 2017 13:53:34 +0000 Received: from mail.free-electrons.com ([62.4.15.54]) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dzk6u-0002Qs-AM for linux-mtd@lists.infradead.org; Wed, 04 Oct 2017 13:53:18 +0000 Received: by mail.free-electrons.com (Postfix, from userid 110) id 26F422091B; Wed, 4 Oct 2017 15:52:52 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost.localdomain (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id D226D2091B; Wed, 4 Oct 2017 15:52:41 +0200 (CEST) From: Boris Brezillon To: David Woodhouse , Brian Norris , Boris Brezillon , Marek Vasut , Richard Weinberger , Cyrille Pitchen , linux-mtd@lists.infradead.org Subject: [PATCH 1/2] mtd: Make sure MTD objects always have a valid debugfs dir Date: Wed, 4 Oct 2017 15:52:38 +0200 Message-Id: <20171004135239.16316-1-boris.brezillon@free-electrons.com> X-Mailer: git-send-email 2.11.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20171004_065316_653659_7850F699 X-CRM114-Status: GOOD ( 21.52 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "Mario J. Rugiero" MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Master MTD devices are not registered to MTD subsystem if they are exposing MTD partitions unless the CONFIG_MTD_PARTITIONED_MASTER option is enabled. This lead to a weird situation where some MTD device drivers are trying to add debugfs files to the master MTD device, but this device has no valid debugfs directory. Rework the core logic to do most of the MTD registration steps (including debugfs dir creation) except the registration to the device model, so that master devices are never exposed to the outside world but are still able to expose debugfs entries. These devices will be exposed as mtd-hiddenX in the mtd debugfs dir. Note that X is unique within the hidden MTD device pool but can collide with ids of exposed MTD devs. This commit fixes a bug introduced by commit e8e3edb95ce6 ("mtd: create per-device and module-scope debugfs entries") which is preventing nandsim from loading when CONFIG_DEBUG_FS is enabled. Fixes: e8e3edb95ce6 ("mtd: create per-device and module-scope debugfs entries") Signed-off-by: Boris Brezillon Reported-by: Richard Weinberger Tested-by: Richard Weinberger --- drivers/mtd/mtdcore.c | 83 ++++++++++++++++++++++++++++++++----------------- include/linux/mtd/mtd.h | 1 + 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e7ea842ba3db..323e621f2eba 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -79,6 +79,10 @@ static struct class mtd_class = { .pm = MTD_CLS_PM_OPS, }; +#define MTD_MAX_IDS 0x10000 +#define MTD_ID_START 0x0 +#define MTD_HIDDEN_ID_START (MTD_ID_START + MTD_MAX_IDS) + static DEFINE_IDR(mtd_idr); /* These are exported solely for the purpose of mtd_blkdevs.c. You @@ -88,7 +92,13 @@ EXPORT_SYMBOL_GPL(mtd_table_mutex); struct mtd_info *__mtd_next_device(int i) { - return idr_get_next(&mtd_idr, &i); + struct mtd_info *mtd; + + mtd = idr_get_next(&mtd_idr, &i); + if (!mtd || i >= MTD_MAX_IDS) + return NULL; + + return mtd; } EXPORT_SYMBOL_GPL(__mtd_next_device); @@ -505,7 +515,13 @@ int add_mtd_device(struct mtd_info *mtd) BUG_ON(mtd->writesize == 0); mutex_lock(&mtd_table_mutex); - i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); + if (!mtd->hidden) + i = idr_alloc(&mtd_idr, mtd, MTD_ID_START, MTD_MAX_IDS, + GFP_KERNEL); + else + i = idr_alloc(&mtd_idr, mtd, MTD_HIDDEN_ID_START, + MTD_HIDDEN_ID_START + MTD_MAX_IDS, + GFP_KERNEL); if (i < 0) { error = i; goto fail_locked; @@ -545,15 +561,20 @@ int add_mtd_device(struct mtd_info *mtd) /* Caller should have set dev.parent to match the * physical device, if appropriate. */ - mtd->dev.type = &mtd_devtype; - mtd->dev.class = &mtd_class; - mtd->dev.devt = MTD_DEVT(i); - dev_set_name(&mtd->dev, "mtd%d", i); dev_set_drvdata(&mtd->dev, mtd); of_node_get(mtd_get_of_node(mtd)); - error = device_register(&mtd->dev); - if (error) - goto fail_added; + if (!mtd->hidden) { + mtd->dev.type = &mtd_devtype; + mtd->dev.class = &mtd_class; + mtd->dev.devt = MTD_DEVT(i); + dev_set_name(&mtd->dev, "mtd%d", i); + error = device_register(&mtd->dev); + if (error) + goto fail_added; + } else { + dev_set_name(&mtd->dev, "mtdmaster%d", + i - MTD_HIDDEN_ID_START); + } if (!IS_ERR_OR_NULL(dfs_dir_mtd)) { mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd); @@ -563,14 +584,16 @@ int add_mtd_device(struct mtd_info *mtd) } } - device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, - "mtd%dro", i); + if (!mtd->hidden) { + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, + NULL, "mtd%dro", i); - pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); - /* No need to get a refcount on the module containing - the notifier, since we hold the mtd_table_mutex */ - list_for_each_entry(not, &mtd_notifiers, list) - not->add(mtd); + pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each_entry(not, &mtd_notifiers, list) + not->add(mtd); + } mutex_unlock(&mtd_table_mutex); /* We _know_ we aren't being removed, because @@ -612,17 +635,20 @@ int del_mtd_device(struct mtd_info *mtd) goto out_error; } - /* No need to get a refcount on the module containing - the notifier, since we hold the mtd_table_mutex */ - list_for_each_entry(not, &mtd_notifiers, list) - not->remove(mtd); + if (!mtd->hidden) { + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each_entry(not, &mtd_notifiers, list) + not->remove(mtd); + } if (mtd->usecount) { printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", mtd->index, mtd->name, mtd->usecount); ret = -EBUSY; } else { - device_unregister(&mtd->dev); + if (!mtd->hidden) + device_unregister(&mtd->dev); idr_remove(&mtd_idr, mtd->index); of_node_put(mtd_get_of_node(mtd)); @@ -643,15 +669,16 @@ static int mtd_add_device_partitions(struct mtd_info *mtd, int nbparts = parts->nr_parts; int ret; - if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { - ret = add_mtd_device(mtd); - if (ret) - return ret; - } + if (nbparts && !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + mtd->hidden = true; + + ret = add_mtd_device(mtd); + if (ret) + return ret; if (nbparts > 0) { ret = add_mtd_partitions(mtd, real_parts, nbparts); - if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + if (ret) del_mtd_device(mtd); return ret; } @@ -857,7 +884,7 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) break; } } - } else if (num >= 0) { + } else if (num >= MTD_ID_START && num < MTD_MAX_IDS) { ret = idr_find(&mtd_idr, num); if (mtd && mtd != ret) ret = NULL; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 6cd0f6b7658b..382c996b51df 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -268,6 +268,7 @@ struct mtd_info { unsigned int bitflip_threshold; // Kernel-only stuff starts here. + bool hidden; const char *name; int index;