* [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM
@ 2023-08-11 1:36 Daniel Golle
2023-08-11 1:36 ` [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI Daniel Golle
` (7 more replies)
0 siblings, 8 replies; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:36 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
The series is a follow-up and contains all patches of the previous
series "mtd: ubi: behave like a good MTD citizen"[1] which was meant in
preparation for implementing the NVMEM provider.
The goal is to support embedded Linux devices which got NVMEM bits
stored inside a UBI volume. Representing the UBI volume in the Device
Tree, adding a phandle to be referenced by NVMEM consumers allows such
devices to come up with their correct MAC addresses and device-specific
Wi-Fi calibration data loaded.
In order to be available for other drivers, attaching UBI devices has
to be moved from late_initcall (which is too late for other drivers) to
happen earlier. As an alternative to the existing kernel cmdline
parameter the Device Tree property 'compatible = "linux,ubi";' inside
an MTD partition can be used to have that MTD device attached as UBI
device. MTD partitions which serve as UBI devices may have a "volumes"
firmware subnode with volumes which may be compatible with
"nvmem-cells".
In this way, other drivers (think: Ethernet, Wi-Fi) can resolve and
acquire NVMEM bits using the usual device tree phandle, just this time
the NVMEM content is read from a UBI volume.
[1]: https://patchwork.ozlabs.org/project/linux-mtd/list/?series=353177&state=%2A&archive=both
Changes since v3:
* dt-bindings fixes as requested
Changes since v2:
* include dt-bindings additions
Changes since v1:
* include patch to fix exiting Kconfig formatting issues
* fix typo and indentation in Kconfig
Daniel Golle (8):
dt-bindings: mtd: add basic bindings for UBI
dt-bindings: mtd: nvmem-cells: add support for UBI volumes
mtd: ubi: block: don't return on error when removing
mtd: ubi: block: use notifier to create ubiblock
mtd: ubi: attach MTD partition from device-tree
mtd: ubi: introduce pre-removal notification for UBI volumes
mtd: ubi: populate ubi volume fwnode
mtd: ubi: provide NVMEM layer over UBI volumes
.../bindings/mtd/partitions/linux,ubi.yaml | 66 ++++++
.../bindings/mtd/partitions/nvmem-cells.yaml | 5 +-
.../bindings/mtd/partitions/ubi-volume.yaml | 36 ++++
drivers/mtd/ubi/Kconfig | 12 ++
drivers/mtd/ubi/Makefile | 1 +
drivers/mtd/ubi/block.c | 186 ++++++++++-------
drivers/mtd/ubi/build.c | 160 +++++++++++----
drivers/mtd/ubi/cdev.c | 4 +-
drivers/mtd/ubi/nvmem.c | 189 ++++++++++++++++++
drivers/mtd/ubi/ubi.h | 6 +-
drivers/mtd/ubi/vmt.c | 32 +++
include/linux/mtd/ubi.h | 2 +
12 files changed, 579 insertions(+), 120 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
create mode 100644 drivers/mtd/ubi/nvmem.c
--
2.41.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
@ 2023-08-11 1:36 ` Daniel Golle
2023-08-21 17:31 ` Rob Herring
2023-08-11 1:36 ` [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes Daniel Golle
` (6 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:36 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
Add basic bindings for UBI devices and volumes.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../bindings/mtd/partitions/linux,ubi.yaml | 65 +++++++++++++++++++
.../bindings/mtd/partitions/ubi-volume.yaml | 36 ++++++++++
2 files changed, 101 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
diff --git a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
new file mode 100644
index 0000000000000..a06c1666d5184
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Unsorted Block Images
+
+description: |
+ UBI ("Unsorted Block Images") is a volume management system for raw
+ flash devices which manages multiple logical volumes on a single
+ physical flash device and spreads the I/O load (i.e, wear-leveling)
+ across whole flash chip.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+allOf:
+ - $ref: partition.yaml#
+
+properties:
+ compatible:
+ const: linux,ubi
+
+ volumes:
+ type: object
+ description: UBI Volumes
+
+ patternProperties:
+ "^ubi-volume-.*$":
+ $ref: /schemas/mtd/partitions/ubi-volume.yaml
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ reg = <0x0 0x100000>;
+ label = "bootloader";
+ read-only;
+ };
+
+ partition@100000 {
+ reg = <0x100000 0x1ff00000>;
+ label = "ubi";
+ compatible = "linux,ubi";
+
+ volumes {
+ ubi-volume-caldata {
+ volume-id = <2>;
+ volume-name = "rf";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
new file mode 100644
index 0000000000000..e14c85bbeeb91
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UBI volume
+
+description: |
+ This binding describes a single UBI volume. Volumes can be matches either
+ by their ID or their name, or both.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+ compatible: true
+
+ volume-id:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Match UBI volume ID
+
+ volume-name:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Match UBI volume name
+
+anyOf:
+ - required:
+ - volume-id
+
+ - required:
+ - volume-name
+
+unevaluatedProperties: false
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
2023-08-11 1:36 ` [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI Daniel Golle
@ 2023-08-11 1:36 ` Daniel Golle
2023-08-21 17:31 ` Rob Herring
2023-08-11 1:37 ` [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing Daniel Golle
` (5 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:36 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
UBI volumes may be used to contain NVMEM bits, typically device MAC
addresses or wireless radio calibration data.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../devicetree/bindings/mtd/partitions/linux,ubi.yaml | 3 ++-
.../devicetree/bindings/mtd/partitions/nvmem-cells.yaml | 5 ++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
index a06c1666d5184..e834441fe5e6a 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
@@ -56,9 +56,10 @@ examples:
compatible = "linux,ubi";
volumes {
- ubi-volume-caldata {
+ wifi_caldata: ubi-volume-caldata {
volume-id = <2>;
volume-name = "rf";
+ compatible = "nvmem-cells";
};
};
};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
index 5474d63268dc5..b92a0b35df094 100644
--- a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -17,9 +17,12 @@ maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
allOf:
- - $ref: /schemas/mtd/partitions/partition.yaml#
- $ref: /schemas/nvmem/nvmem.yaml#
+oneOf:
+ - $ref: /schemas/mtd/partitions/partition.yaml#
+ - $ref: /schemas/mtd/partitions/ubi-volume.yaml#
+
properties:
compatible:
const: nvmem-cells
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
2023-08-11 1:36 ` [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI Daniel Golle
2023-08-11 1:36 ` [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes Daniel Golle
@ 2023-08-11 1:37 ` Daniel Golle
2023-10-03 18:14 ` Richard Weinberger
2023-08-11 1:37 ` [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock Daniel Golle
` (4 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:37 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
There is no point on returning the error from ubiblock_remove in case
it is being called due to a volume removal event -- the volume is gone,
we should destroy and remove the ubiblock device no matter what.
Introduce new boolean parameter 'force' to tell ubiblock_remove to go
on even in case the ubiblock device is still busy. Use that new option
when calling ubiblock_remove due to a UBI_VOLUME_REMOVED event.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 6 +++---
drivers/mtd/ubi/cdev.c | 2 +-
drivers/mtd/ubi/ubi.h | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 437c5b83ffe51..69fa6fecb8494 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -456,7 +456,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
}
-int ubiblock_remove(struct ubi_volume_info *vi)
+int ubiblock_remove(struct ubi_volume_info *vi, bool force)
{
struct ubiblock *dev;
int ret;
@@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi)
/* Found a device, let's lock it so we can check if it's busy */
mutex_lock(&dev->dev_mutex);
- if (dev->refcnt > 0) {
+ if (dev->refcnt > 0 && !force) {
ret = -EBUSY;
goto out_unlock_dev;
}
@@ -545,7 +545,7 @@ static int ubiblock_notify(struct notifier_block *nb,
*/
break;
case UBI_VOLUME_REMOVED:
- ubiblock_remove(&nt->vi);
+ ubiblock_remove(&nt->vi, true);
break;
case UBI_VOLUME_RESIZED:
ubiblock_resize(&nt->vi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index f43430b9c1e65..bb55e863dd296 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -572,7 +572,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
struct ubi_volume_info vi;
ubi_get_volume_info(desc, &vi);
- err = ubiblock_remove(&vi);
+ err = ubiblock_remove(&vi, false);
break;
}
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index c8f1bd4fa1008..44c0eeaf1e1b0 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -979,7 +979,7 @@ static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {}
int ubiblock_init(void);
void ubiblock_exit(void);
int ubiblock_create(struct ubi_volume_info *vi);
-int ubiblock_remove(struct ubi_volume_info *vi);
+int ubiblock_remove(struct ubi_volume_info *vi, bool force);
#else
static inline int ubiblock_init(void) { return 0; }
static inline void ubiblock_exit(void) {}
@@ -987,7 +987,7 @@ static inline int ubiblock_create(struct ubi_volume_info *vi)
{
return -ENOSYS;
}
-static inline int ubiblock_remove(struct ubi_volume_info *vi)
+static inline int ubiblock_remove(struct ubi_volume_info *vi, bool force)
{
return -ENOSYS;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
` (2 preceding siblings ...)
2023-08-11 1:37 ` [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing Daniel Golle
@ 2023-08-11 1:37 ` Daniel Golle
2023-10-03 18:46 ` Richard Weinberger
2023-08-11 1:37 ` [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree Daniel Golle
` (3 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:37 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
Use UBI_VOLUME_ADDED notification to create ubiblock device specified
on kernel cmdline or module parameter.
This makes thing more simple and has the advantage that ubiblock devices
on volumes which are not present at the time the ubi module is probed
will still be created.
Suggested-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 152 ++++++++++++++++++++++------------------
1 file changed, 84 insertions(+), 68 deletions(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 69fa6fecb8494..e0618bbde3613 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -33,6 +33,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/mtd/ubi.h>
#include <linux/blkdev.h>
@@ -65,10 +66,10 @@ struct ubiblock_pdu {
};
/* Numbers of elements set in the @ubiblock_param array */
-static int ubiblock_devs __initdata;
+static int ubiblock_devs;
/* MTD devices specification parameters */
-static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
struct ubiblock {
struct ubi_volume_desc *desc;
@@ -532,6 +533,85 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
return 0;
}
+static bool
+match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
+{
+ int err, len;
+ struct path path;
+ struct kstat stat;
+
+ if (ubi_num == -1) {
+ /* No ubi num, name must be a vol device path */
+ err = kern_path(name, LOOKUP_FOLLOW, &path);
+ if (err)
+ return false;
+
+ err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
+ path_put(&path);
+ if (err)
+ return false;
+
+ if (!S_ISCHR(stat.mode))
+ return false;
+
+ if (vi->ubi_num != ubi_major2num(MAJOR(stat.rdev)))
+ return false;
+
+ if (vi->vol_id != MINOR(stat.rdev) - 1)
+ return false;
+
+ return true;
+ }
+
+ if (vol_id == -1) {
+ if (vi->ubi_num != ubi_num)
+ return false;
+
+ len = strnlen(name, UBI_VOL_NAME_MAX + 1);
+ if (len < 1 || vi->name_len != len)
+ return false;
+
+ if (strcmp(name, vi->name))
+ return false;
+
+ return true;
+ }
+
+ if (vi->ubi_num != ubi_num)
+ return false;
+
+ if (vi->vol_id != vol_id)
+ return false;
+
+ return true;
+}
+
+static void
+ubiblock_create_from_param(struct ubi_volume_info *vi)
+{
+ int i, ret = 0;
+ struct ubiblock_param *p;
+
+ /*
+ * Iterate over ubiblock cmdline parameters. If a parameter matches the
+ * newly added volume create the ubiblock device for it.
+ */
+ for (i = 0; i < ubiblock_devs; i++) {
+ p = &ubiblock_param[i];
+
+ if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
+ continue;
+
+ ret = ubiblock_create(vi);
+ if (ret) {
+ pr_err(
+ "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
+ vi->name, p->ubi_num, p->vol_id, ret);
+ }
+ break;
+ }
+}
+
static int ubiblock_notify(struct notifier_block *nb,
unsigned long notification_type, void *ns_ptr)
{
@@ -539,10 +619,7 @@ static int ubiblock_notify(struct notifier_block *nb,
switch (notification_type) {
case UBI_VOLUME_ADDED:
- /*
- * We want to enforce explicit block device creation for
- * volumes, so when a volume is added we do nothing.
- */
+ ubiblock_create_from_param(&nt->vi);
break;
case UBI_VOLUME_REMOVED:
ubiblock_remove(&nt->vi, true);
@@ -568,56 +645,6 @@ static struct notifier_block ubiblock_notifier = {
.notifier_call = ubiblock_notify,
};
-static struct ubi_volume_desc * __init
-open_volume_desc(const char *name, int ubi_num, int vol_id)
-{
- if (ubi_num == -1)
- /* No ubi num, name must be a vol device path */
- return ubi_open_volume_path(name, UBI_READONLY);
- else if (vol_id == -1)
- /* No vol_id, must be vol_name */
- return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
- else
- return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
-}
-
-static void __init ubiblock_create_from_param(void)
-{
- int i, ret = 0;
- struct ubiblock_param *p;
- struct ubi_volume_desc *desc;
- struct ubi_volume_info vi;
-
- /*
- * If there is an error creating one of the ubiblocks, continue on to
- * create the following ubiblocks. This helps in a circumstance where
- * the kernel command-line specifies multiple block devices and some
- * may be broken, but we still want the working ones to come up.
- */
- for (i = 0; i < ubiblock_devs; i++) {
- p = &ubiblock_param[i];
-
- desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
- if (IS_ERR(desc)) {
- pr_err(
- "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
- p->ubi_num, p->vol_id, PTR_ERR(desc));
- continue;
- }
-
- ubi_get_volume_info(desc, &vi);
- ubi_close_volume(desc);
-
- ret = ubiblock_create(&vi);
- if (ret) {
- pr_err(
- "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
- vi.name, p->ubi_num, p->vol_id, ret);
- continue;
- }
- }
-}
-
static void ubiblock_remove_all(void)
{
struct ubiblock *next;
@@ -643,18 +670,7 @@ int __init ubiblock_init(void)
if (ubiblock_major < 0)
return ubiblock_major;
- /*
- * Attach block devices from 'block=' module param.
- * Even if one block device in the param list fails to come up,
- * still allow the module to load and leave any others up.
- */
- ubiblock_create_from_param();
-
- /*
- * Block devices are only created upon user requests, so we ignore
- * existing volumes.
- */
- ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
if (ret)
goto err_unreg;
return 0;
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
` (3 preceding siblings ...)
2023-08-11 1:37 ` [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock Daniel Golle
@ 2023-08-11 1:37 ` Daniel Golle
2023-10-03 19:45 ` Richard Weinberger
2023-08-11 1:38 ` [PATCH v4 6/8] mtd: ubi: introduce pre-removal notification for UBI volumes Daniel Golle
` (2 subsequent siblings)
7 siblings, 1 reply; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:37 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
Split ubi_init() function into early function to be called by
device_initcall() and keep cmdline attachment in late_initcall().
(when building ubi as module, both is still done in a single
module_init() call)
Register MTD notifier and attach MTD devices which are marked as
compatible with 'linux,ubi' in OF device-tree when being added, detach
UBI device from MTD device when it is being removed.
For existing users this should not change anything besides automatic
removal of (dead) UBI devices when their underlying MTD devices are
already gone, e.g. in case of MTD driver module or (SPI) bus driver
module being removed.
For new users this opens up the option to attach UBI using device-tree
which then happens early and in parallel with other drivers being
probed which slightly reduces the total boot time.
Attachment no longer happening late is also a requirement for other
drivers to make use of UBI, e.g. drivers/nvmem/u-boot-env.c can now
be extended to support U-Boot environment stored in UBI volumes.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 2 +-
drivers/mtd/ubi/build.c | 153 +++++++++++++++++++++++++++++-----------
drivers/mtd/ubi/cdev.c | 2 +-
drivers/mtd/ubi/ubi.h | 2 +-
4 files changed, 115 insertions(+), 44 deletions(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index e0618bbde3613..99b5f502c9dbc 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi, bool force)
}
/* Found a device, let's lock it so we can check if it's busy */
- mutex_lock(&dev->dev_mutex);
+ mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
if (dev->refcnt > 0 && !force) {
ret = -EBUSY;
goto out_unlock_dev;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 8b91a55ec0d28..c153373c13dab 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -27,6 +27,7 @@
#include <linux/log2.h>
#include <linux/kthread.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/major.h>
#include "ubi.h"
@@ -1065,6 +1066,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
* ubi_detach_mtd_dev - detach an MTD device.
* @ubi_num: UBI device number to detach from
* @anyway: detach MTD even if device reference count is not zero
+ * @have_lock: called by MTD notifier holding mtd_table_mutex
*
* This function destroys an UBI device number @ubi_num and detaches the
* underlying MTD device. Returns zero in case of success and %-EBUSY if the
@@ -1074,7 +1076,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
* Note, the invocations of this function has to be serialized by the
* @ubi_devices_mutex.
*/
-int ubi_detach_mtd_dev(int ubi_num, int anyway)
+int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
{
struct ubi_device *ubi;
@@ -1111,6 +1113,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
if (!ubi_dbg_chk_fastmap(ubi))
ubi_update_fastmap(ubi);
#endif
+
/*
* Before freeing anything, we have to stop the background thread to
* prevent it from doing anything on this device while we are freeing.
@@ -1130,7 +1133,11 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
vfree(ubi->peb_buf);
vfree(ubi->fm_buf);
ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
- put_mtd_device(ubi->mtd);
+ if (have_lock)
+ __put_mtd_device(ubi->mtd);
+ else
+ put_mtd_device(ubi->mtd);
+
put_device(&ubi->dev);
return 0;
}
@@ -1207,43 +1214,51 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
return mtd;
}
-static int __init ubi_init(void)
+static void ubi_notify_add(struct mtd_info *mtd)
{
- int err, i, k;
+ struct device_node *np = mtd_get_of_node(mtd);
+ int err;
- /* Ensure that EC and VID headers have correct size */
- BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
- BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+ if (!of_device_is_compatible(np, "linux,ubi"))
+ return;
- if (mtd_devs > UBI_MAX_DEVICES) {
- pr_err("UBI error: too many MTD devices, maximum is %d\n",
- UBI_MAX_DEVICES);
- return -EINVAL;
- }
+ /*
+ * we are already holding &mtd_table_mutex, but still need
+ * to bump refcount
+ */
+ err = __get_mtd_device(mtd);
+ if (err)
+ return;
- /* Create base sysfs directory and sysfs files */
- err = class_register(&ubi_class);
+ /* called while holding mtd_table_mutex */
+ mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
+ mutex_unlock(&ubi_devices_mutex);
if (err < 0)
- return err;
+ __put_mtd_device(mtd);
+}
- err = misc_register(&ubi_ctrl_cdev);
- if (err) {
- pr_err("UBI error: cannot register device\n");
- goto out;
- }
+static void ubi_notify_remove(struct mtd_info *mtd)
+{
+ int i;
- ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
- sizeof(struct ubi_wl_entry),
- 0, 0, NULL);
- if (!ubi_wl_entry_slab) {
- err = -ENOMEM;
- goto out_dev_unreg;
- }
+ /* called while holding mtd_table_mutex */
+ mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
+ for (i = 0; i < UBI_MAX_DEVICES; i++)
+ if (ubi_devices[i] &&
+ ubi_devices[i]->mtd->index == mtd->index)
+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, true);
+ mutex_unlock(&ubi_devices_mutex);
+}
- err = ubi_debugfs_init();
- if (err)
- goto out_slab;
+static struct mtd_notifier ubi_mtd_notifier = {
+ .add = ubi_notify_add,
+ .remove = ubi_notify_remove,
+};
+static int __init ubi_init_attach(void)
+{
+ int err, i, k;
/* Attach MTD devices */
for (i = 0; i < mtd_devs; i++) {
@@ -1291,25 +1306,79 @@ static int __init ubi_init(void)
}
}
+ return 0;
+
+out_detach:
+ for (k = 0; k < i; k++)
+ if (ubi_devices[k]) {
+ mutex_lock(&ubi_devices_mutex);
+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1, false);
+ mutex_unlock(&ubi_devices_mutex);
+ }
+ return err;
+}
+#ifndef CONFIG_MTD_UBI_MODULE
+late_initcall(ubi_init_attach);
+#endif
+
+static int __init ubi_init(void)
+{
+ int err;
+
+ /* Ensure that EC and VID headers have correct size */
+ BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+ BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+
+ if (mtd_devs > UBI_MAX_DEVICES) {
+ pr_err("UBI error: too many MTD devices, maximum is %d\n",
+ UBI_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ /* Create base sysfs directory and sysfs files */
+ err = class_register(&ubi_class);
+ if (err < 0)
+ return err;
+
+ err = misc_register(&ubi_ctrl_cdev);
+ if (err) {
+ pr_err("UBI error: cannot register device\n");
+ goto out;
+ }
+
+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+ sizeof(struct ubi_wl_entry),
+ 0, 0, NULL);
+ if (!ubi_wl_entry_slab) {
+ err = -ENOMEM;
+ goto out_dev_unreg;
+ }
+
+ err = ubi_debugfs_init();
+ if (err)
+ goto out_slab;
+
err = ubiblock_init();
if (err) {
pr_err("UBI error: block: cannot initialize, error %d\n", err);
/* See comment above re-ubi_is_module(). */
if (ubi_is_module())
- goto out_detach;
+ goto out_slab;
+ }
+
+ register_mtd_user(&ubi_mtd_notifier);
+
+ if (ubi_is_module()) {
+ err = ubi_init_attach();
+ if (err)
+ goto out_mtd_notifier;
}
return 0;
-out_detach:
- for (k = 0; k < i; k++)
- if (ubi_devices[k]) {
- mutex_lock(&ubi_devices_mutex);
- ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
- mutex_unlock(&ubi_devices_mutex);
- }
- ubi_debugfs_exit();
+out_mtd_notifier:
+ unregister_mtd_user(&ubi_mtd_notifier);
out_slab:
kmem_cache_destroy(ubi_wl_entry_slab);
out_dev_unreg:
@@ -1319,18 +1388,20 @@ static int __init ubi_init(void)
pr_err("UBI error: cannot initialize UBI, error %d\n", err);
return err;
}
-late_initcall(ubi_init);
+device_initcall(ubi_init);
+
static void __exit ubi_exit(void)
{
int i;
ubiblock_exit();
+ unregister_mtd_user(&ubi_mtd_notifier);
for (i = 0; i < UBI_MAX_DEVICES; i++)
if (ubi_devices[i]) {
mutex_lock(&ubi_devices_mutex);
- ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, false);
mutex_unlock(&ubi_devices_mutex);
}
ubi_debugfs_exit();
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index bb55e863dd296..0ba6aa6a2e11d 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -1065,7 +1065,7 @@ static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
}
mutex_lock(&ubi_devices_mutex);
- err = ubi_detach_mtd_dev(ubi_num, 0);
+ err = ubi_detach_mtd_dev(ubi_num, 0, false);
mutex_unlock(&ubi_devices_mutex);
break;
}
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 44c0eeaf1e1b0..54093858f3385 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -939,7 +939,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
int vid_hdr_offset, int max_beb_per1024,
bool disable_fm);
-int ubi_detach_mtd_dev(int ubi_num, int anyway);
+int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock);
struct ubi_device *ubi_get_device(int ubi_num);
void ubi_put_device(struct ubi_device *ubi);
struct ubi_device *ubi_get_by_major(int major);
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 6/8] mtd: ubi: introduce pre-removal notification for UBI volumes
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
` (4 preceding siblings ...)
2023-08-11 1:37 ` [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree Daniel Golle
@ 2023-08-11 1:38 ` Daniel Golle
2023-08-11 1:38 ` [PATCH v4 7/8] mtd: ubi: populate ubi volume fwnode Daniel Golle
2023-08-11 1:38 ` [PATCH v4 8/8] mtd: ubi: provide NVMEM layer over UBI volumes Daniel Golle
7 siblings, 0 replies; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:38 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
that a volume is just about to be removed.
This is needed because users (such as the NVMEM subsystem) expect that
at the time their removal function is called, the parenting device is
still available (for removal of sysfs nodes, for example, in case of
NVMEM which otherwise WARNs on volume removal).
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
drivers/mtd/ubi/build.c | 7 ++++++-
drivers/mtd/ubi/vmt.c | 5 +++++
include/linux/mtd/ubi.h | 2 ++
4 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 99b5f502c9dbc..1d5148371991b 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -533,6 +533,29 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
return 0;
}
+static int ubiblock_shutdown(struct ubi_volume_info *vi)
+{
+ struct ubiblock *dev;
+ struct gendisk *disk;
+ int ret = 0;
+
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+ if (!dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+ disk = dev->gd;
+
+out_unlock:
+ mutex_unlock(&devices_mutex);
+
+ if (!ret)
+ blk_mark_disk_dead(disk);
+
+ return ret;
+};
+
static bool
match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
{
@@ -624,6 +647,9 @@ static int ubiblock_notify(struct notifier_block *nb,
case UBI_VOLUME_REMOVED:
ubiblock_remove(&nt->vi, true);
break;
+ case UBI_VOLUME_SHUTDOWN:
+ ubiblock_shutdown(&nt->vi);
+ break;
case UBI_VOLUME_RESIZED:
ubiblock_resize(&nt->vi);
break;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index c153373c13dab..ccee4a28ffe97 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1088,7 +1088,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
return -EINVAL;
spin_lock(&ubi_devices_lock);
- put_device(&ubi->dev);
ubi->ref_count -= 1;
if (ubi->ref_count) {
if (!anyway) {
@@ -1099,6 +1098,12 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
ubi_err(ubi, "%s reference count %d, destroy anyway",
ubi->ubi_name, ubi->ref_count);
}
+ spin_unlock(&ubi_devices_lock);
+
+ ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
+
+ spin_lock(&ubi_devices_lock);
+ put_device(&ubi->dev);
ubi_devices[ubi_num] = NULL;
spin_unlock(&ubi_devices_lock);
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 2c867d16f89f7..eed4b57c61bda 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -352,6 +352,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
err = -EBUSY;
goto out_unlock;
}
+ spin_unlock(&ubi->volumes_lock);
+
+ ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
+
+ spin_lock(&ubi->volumes_lock);
ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index a529347fd75b2..562f92504f2b7 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -192,6 +192,7 @@ struct ubi_device_info {
* or a volume was removed)
* @UBI_VOLUME_RESIZED: a volume has been re-sized
* @UBI_VOLUME_RENAMED: a volume has been re-named
+ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
* @UBI_VOLUME_UPDATED: data has been written to a volume
*
* These constants define which type of event has happened when a volume
@@ -202,6 +203,7 @@ enum {
UBI_VOLUME_REMOVED,
UBI_VOLUME_RESIZED,
UBI_VOLUME_RENAMED,
+ UBI_VOLUME_SHUTDOWN,
UBI_VOLUME_UPDATED,
};
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 7/8] mtd: ubi: populate ubi volume fwnode
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
` (5 preceding siblings ...)
2023-08-11 1:38 ` [PATCH v4 6/8] mtd: ubi: introduce pre-removal notification for UBI volumes Daniel Golle
@ 2023-08-11 1:38 ` Daniel Golle
2023-08-11 1:38 ` [PATCH v4 8/8] mtd: ubi: provide NVMEM layer over UBI volumes Daniel Golle
7 siblings, 0 replies; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:38 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
Look for the 'volumes' subnode of an MTD partition attached to a UBI
device and attach matching child nodes to UBI volumes.
This allows UBI volumes to be referenced in device tree, e.g. for use
as NVMEM providers.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/vmt.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index eed4b57c61bda..9db845a43ecfc 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -124,6 +124,31 @@ static void vol_release(struct device *dev)
kfree(vol);
}
+static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
+{
+ struct fwnode_handle *fw_vols, *fw_vol;
+ const char *volname;
+ u32 volid;
+
+ fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
+ if (!fw_vols)
+ return NULL;
+
+ fwnode_for_each_child_node(fw_vols, fw_vol) {
+ if (!fwnode_property_read_string(fw_vol, "volume-name", &volname) &&
+ strncmp(volname, vol->name, vol->name_len))
+ continue;
+
+ if (!fwnode_property_read_u32(fw_vol, "volume-id", &volid) &&
+ vol->vol_id != volid)
+ continue;
+
+ return fw_vol;
+ }
+
+ return NULL;
+}
+
/**
* ubi_create_volume - create volume.
* @ubi: UBI device description object
@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vol->name_len = req->name_len;
memcpy(vol->name, req->name, vol->name_len);
vol->ubi = ubi;
+ device_set_node(&vol->dev, find_volume_fwnode(vol));
/*
* Finish all pending erases because there may be some LEBs belonging
@@ -597,6 +623,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
vol->dev.class = &ubi_class;
vol->dev.groups = volume_dev_groups;
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
+ device_set_node(&vol->dev, find_volume_fwnode(vol));
err = device_register(&vol->dev);
if (err) {
cdev_del(&vol->cdev);
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v4 8/8] mtd: ubi: provide NVMEM layer over UBI volumes
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
` (6 preceding siblings ...)
2023-08-11 1:38 ` [PATCH v4 7/8] mtd: ubi: populate ubi volume fwnode Daniel Golle
@ 2023-08-11 1:38 ` Daniel Golle
7 siblings, 0 replies; 19+ messages in thread
From: Daniel Golle @ 2023-08-11 1:38 UTC (permalink / raw)
To: Randy Dunlap, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Daniel Golle, linux-mtd, devicetree, linux-kernel
In an ideal world we would like UBI to be used where ever possible on a
NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
is possible to achieve an (almost-)all-UBI flash layout. Hence the need
for a way to also use UBI volumes to store board-level constants, such
as MAC addresses and calibration data of wireless interfaces.
Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
providers. Allow UBI devices to have a "volumes" firmware subnode with
volumes which may be compatible with "nvmem-cells".
Access to UBI volumes via the NVMEM interface at this point is
read-only, and it is slow, opening and closing the UBI volume for each
access due to limitations of the NVMEM provider API.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mtd/ubi/Kconfig | 12 +++
drivers/mtd/ubi/Makefile | 1 +
drivers/mtd/ubi/nvmem.c | 189 +++++++++++++++++++++++++++++++++++++++
3 files changed, 202 insertions(+)
create mode 100644 drivers/mtd/ubi/nvmem.c
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 2ed77b7b3fcb5..45d939bbfa853 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -104,4 +104,16 @@ config MTD_UBI_BLOCK
If in doubt, say "N".
+config MTD_UBI_NVMEM
+ tristate "UBI virtual NVMEM"
+ default n
+ depends on NVMEM
+ help
+ This option enabled an additional driver exposing UBI volumes as NVMEM
+ providers, intended for platforms where UBI is part of the firmware
+ specification and used to store also e.g. MAC addresses or board-
+ specific Wi-Fi calibration data.
+
+ If in doubt, say "N".
+
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index 543673605ca72..4b51aaf00d1a2 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
diff --git a/drivers/mtd/ubi/nvmem.c b/drivers/mtd/ubi/nvmem.c
new file mode 100644
index 0000000000000..dd7cc6afb8d00
--- /dev/null
+++ b/drivers/mtd/ubi/nvmem.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
+ */
+
+/* UBI NVMEM provider */
+#include "ubi.h"
+#include <linux/nvmem-provider.h>
+
+/* List of all NVMEM devices */
+static LIST_HEAD(nvmem_devices);
+static DEFINE_MUTEX(devices_mutex);
+
+struct ubi_nvmem {
+ struct nvmem_device *nvmem;
+ int ubi_num;
+ int vol_id;
+ int usable_leb_size;
+ struct list_head list;
+};
+
+static int ubi_nvmem_reg_read(void *priv, unsigned int from,
+ void *val, size_t bytes)
+{
+ struct ubi_nvmem *unv = priv;
+ struct ubi_volume_desc *desc;
+ int err = 0, lnum, offs, bytes_left;
+ size_t to_read;
+
+ desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ lnum = div_u64_rem(from, unv->usable_leb_size, &offs);
+ bytes_left = bytes;
+ while (bytes_left) {
+ to_read = unv->usable_leb_size - offs;
+
+ if (to_read > bytes_left)
+ to_read = bytes_left;
+
+ err = ubi_read(desc, lnum, val, offs, to_read);
+ if (err)
+ break;
+
+ lnum += 1;
+ offs = 0;
+ bytes_left -= to_read;
+ val += to_read;
+ }
+ ubi_close_volume(desc);
+
+ if (err)
+ return err;
+
+ return bytes_left == 0 ? 0 : -EIO;
+}
+
+static int ubi_nvmem_add(struct ubi_volume_info *vi)
+{
+ struct nvmem_config config = {};
+ struct ubi_nvmem *unv;
+ int ret;
+
+ if (!device_is_compatible(vi->dev, "nvmem-cells"))
+ return 0;
+
+ unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
+ if (!unv)
+ return -ENOMEM;
+
+ config.id = NVMEM_DEVID_NONE;
+ config.dev = vi->dev;
+ config.name = dev_name(vi->dev);
+ config.owner = THIS_MODULE;
+ config.priv = unv;
+ config.reg_read = ubi_nvmem_reg_read;
+ config.size = vi->usable_leb_size * vi->size;
+ config.word_size = 1;
+ config.stride = 1;
+ config.read_only = true;
+ config.root_only = true;
+ config.ignore_wp = true;
+ config.of_node = dev_of_node(vi->dev);
+
+ if (!config.of_node)
+ config.no_of_node = true;
+
+ unv->ubi_num = vi->ubi_num;
+ unv->vol_id = vi->vol_id;
+ unv->usable_leb_size = vi->usable_leb_size;
+ unv->nvmem = nvmem_register(&config);
+ if (IS_ERR(unv->nvmem)) {
+ /* Just ignore if there is no NVMEM support in the kernel */
+ if (PTR_ERR(unv->nvmem) == -EOPNOTSUPP)
+ ret = 0;
+ else
+ ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
+ "Failed to register NVMEM device\n");
+
+ kfree(unv);
+ return ret;
+ }
+
+ mutex_lock(&devices_mutex);
+ list_add_tail(&unv->list, &nvmem_devices);
+ mutex_unlock(&devices_mutex);
+
+ return 0;
+}
+
+static void ubi_nvmem_remove(struct ubi_volume_info *vi)
+{
+ struct ubi_nvmem *unv_c, *unv = NULL;
+
+ mutex_lock(&devices_mutex);
+ list_for_each_entry(unv_c, &nvmem_devices, list)
+ if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
+ unv = unv_c;
+ break;
+ }
+
+ if (!unv) {
+ mutex_unlock(&devices_mutex);
+ return;
+ }
+
+ list_del(&unv->list);
+ mutex_unlock(&devices_mutex);
+ nvmem_unregister(unv->nvmem);
+ kfree(unv);
+}
+
+/**
+ * nvmem_notify - UBI notification handler.
+ * @nb: registered notifier block
+ * @l: notification type
+ * @ns_ptr: pointer to the &struct ubi_notification object
+ */
+static int nvmem_notify(struct notifier_block *nb, unsigned long l,
+ void *ns_ptr)
+{
+ struct ubi_notification *nt = ns_ptr;
+
+ switch (l) {
+ case UBI_VOLUME_RESIZED:
+ ubi_nvmem_remove(&nt->vi);
+ fallthrough;
+ case UBI_VOLUME_ADDED:
+ ubi_nvmem_add(&nt->vi);
+ break;
+ case UBI_VOLUME_SHUTDOWN:
+ ubi_nvmem_remove(&nt->vi);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block nvmem_notifier = {
+ .notifier_call = nvmem_notify,
+};
+
+static int __init ubi_nvmem_init(void)
+{
+ return ubi_register_volume_notifier(&nvmem_notifier, 0);
+}
+
+static void __exit ubi_nvmem_exit(void)
+{
+ struct ubi_nvmem *unv, *tmp;
+
+ mutex_lock(&devices_mutex);
+ list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
+ nvmem_unregister(unv->nvmem);
+ list_del(&unv->list);
+ kfree(unv);
+ }
+ mutex_unlock(&devices_mutex);
+
+ ubi_unregister_volume_notifier(&nvmem_notifier);
+}
+
+module_init(ubi_nvmem_init);
+module_exit(ubi_nvmem_exit);
+MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
+MODULE_AUTHOR("Daniel Golle");
+MODULE_LICENSE("GPL");
--
2.41.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
2023-08-11 1:36 ` [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI Daniel Golle
@ 2023-08-21 17:31 ` Rob Herring
2023-09-11 19:01 ` Daniel Golle
0 siblings, 1 reply; 19+ messages in thread
From: Rob Herring @ 2023-08-21 17:31 UTC (permalink / raw)
To: Daniel Golle
Cc: Vignesh Raghavendra, Randy Dunlap, Miquel Raynal, linux-mtd,
Richard Weinberger, devicetree, Krzysztof Kozlowski, Conor Dooley,
Rob Herring, linux-kernel
On Fri, 11 Aug 2023 02:36:37 +0100, Daniel Golle wrote:
> Add basic bindings for UBI devices and volumes.
>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> ---
> .../bindings/mtd/partitions/linux,ubi.yaml | 65 +++++++++++++++++++
> .../bindings/mtd/partitions/ubi-volume.yaml | 36 ++++++++++
> 2 files changed, 101 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
> create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes
2023-08-11 1:36 ` [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes Daniel Golle
@ 2023-08-21 17:31 ` Rob Herring
0 siblings, 0 replies; 19+ messages in thread
From: Rob Herring @ 2023-08-21 17:31 UTC (permalink / raw)
To: Daniel Golle
Cc: Vignesh Raghavendra, Krzysztof Kozlowski, linux-kernel,
devicetree, Randy Dunlap, Richard Weinberger, Miquel Raynal,
Conor Dooley, linux-mtd, Rob Herring
On Fri, 11 Aug 2023 02:36:55 +0100, Daniel Golle wrote:
> UBI volumes may be used to contain NVMEM bits, typically device MAC
> addresses or wireless radio calibration data.
>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> ---
> .../devicetree/bindings/mtd/partitions/linux,ubi.yaml | 3 ++-
> .../devicetree/bindings/mtd/partitions/nvmem-cells.yaml | 5 ++++-
> 2 files changed, 6 insertions(+), 2 deletions(-)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
2023-08-21 17:31 ` Rob Herring
@ 2023-09-11 19:01 ` Daniel Golle
2023-09-11 19:10 ` Richard Weinberger
2023-09-13 13:10 ` Tudor Ambarus
0 siblings, 2 replies; 19+ messages in thread
From: Daniel Golle @ 2023-09-11 19:01 UTC (permalink / raw)
To: linux-mtd
Cc: Zhihao Cheng, Rob Herring, Vignesh Raghavendra, Randy Dunlap,
Miquel Raynal, Richard Weinberger, devicetree,
Krzysztof Kozlowski, Conor Dooley, Rob Herring, linux-kernel
On Mon, Aug 21, 2023 at 12:31:22PM -0500, Rob Herring wrote:
> On Fri, 11 Aug 2023 02:36:37 +0100, Daniel Golle wrote:
> > Add basic bindings for UBI devices and volumes.
> >
> Reviewed-by: Rob Herring <robh@kernel.org>
>
Patch 3 - 7 have previously been discussed on the mailing list, patch
1 and 2 have been reviewed by Rob, patch 8 ("mtd: ubi: provide NVMEM
layer over UBI volumes") still needs review.
Is there anything I can do from my end to have this series moving
forward?
Patchwork: https://patchwork.ozlabs.org/project/linux-mtd/list/?series=368347
Thank you for your advise!
Daniel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
2023-09-11 19:01 ` Daniel Golle
@ 2023-09-11 19:10 ` Richard Weinberger
2023-09-13 13:10 ` Tudor Ambarus
1 sibling, 0 replies; 19+ messages in thread
From: Richard Weinberger @ 2023-09-11 19:10 UTC (permalink / raw)
To: Daniel Golle
Cc: linux-mtd, chengzhihao1, robh, Vignesh Raghavendra, Randy Dunlap,
Miquel Raynal, devicetree, Krzysztof Kozlowski, Conor Dooley,
Rob Herring, linux-kernel
----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
> An: "linux-mtd" <linux-mtd@lists.infradead.org>
> CC: "chengzhihao1" <chengzhihao1@huawei.com>, "robh" <robh@kernel.org>, "Vignesh Raghavendra" <vigneshr@ti.com>, "Randy
> Dunlap" <rdunlap@infradead.org>, "Miquel Raynal" <miquel.raynal@bootlin.com>, "richard" <richard@nod.at>, "devicetree"
> <devicetree@vger.kernel.org>, "Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>, "Conor Dooley"
> <conor+dt@kernel.org>, "Rob Herring" <robh+dt@kernel.org>, "linux-kernel" <linux-kernel@vger.kernel.org>
> Gesendet: Montag, 11. September 2023 21:01:57
> Betreff: Re: [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
> On Mon, Aug 21, 2023 at 12:31:22PM -0500, Rob Herring wrote:
>> On Fri, 11 Aug 2023 02:36:37 +0100, Daniel Golle wrote:
>> > Add basic bindings for UBI devices and volumes.
>> >
>> Reviewed-by: Rob Herring <robh@kernel.org>
>>
>
> Patch 3 - 7 have previously been discussed on the mailing list, patch
> 1 and 2 have been reviewed by Rob, patch 8 ("mtd: ubi: provide NVMEM
> layer over UBI volumes") still needs review.
>
> Is there anything I can do from my end to have this series moving
> forward?
>
> Patchwork: https://patchwork.ozlabs.org/project/linux-mtd/list/?series=368347
It is on my review TODO.
Thanks for your patience,
//richard
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI
2023-09-11 19:01 ` Daniel Golle
2023-09-11 19:10 ` Richard Weinberger
@ 2023-09-13 13:10 ` Tudor Ambarus
1 sibling, 0 replies; 19+ messages in thread
From: Tudor Ambarus @ 2023-09-13 13:10 UTC (permalink / raw)
To: Daniel Golle, linux-mtd
Cc: Zhihao Cheng, Rob Herring, Vignesh Raghavendra, Randy Dunlap,
Miquel Raynal, Richard Weinberger, devicetree,
Krzysztof Kozlowski, Conor Dooley, Rob Herring, linux-kernel
Hi!
On 9/11/23 20:01, Daniel Golle wrote:
> Is there anything I can do from my end to have this series moving forward?
You could review other UBI submissions to reduce the review load on
Richard. I guess the queue of UBI pending patches is at:
https://patchwork.ozlabs.org/project/linux-mtd/list/?series=&submitter=&state=&q=ubi&archive=&delegate=
Cheers,
ta
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing
2023-08-11 1:37 ` [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing Daniel Golle
@ 2023-10-03 18:14 ` Richard Weinberger
0 siblings, 0 replies; 19+ messages in thread
From: Richard Weinberger @ 2023-10-03 18:14 UTC (permalink / raw)
To: Daniel Golle
Cc: Randy Dunlap, Miquel Raynal, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, devicetree,
linux-kernel
----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
> An: "Randy Dunlap" <rdunlap@infradead.org>, "Miquel Raynal" <miquel.raynal@bootlin.com>, "richard" <richard@nod.at>,
> "Vignesh Raghavendra" <vigneshr@ti.com>, "Rob Herring" <robh+dt@kernel.org>, "Krzysztof Kozlowski"
> <krzysztof.kozlowski+dt@linaro.org>, "Conor Dooley" <conor+dt@kernel.org>, "Daniel Golle" <daniel@makrotopia.org>,
> "linux-mtd" <linux-mtd@lists.infradead.org>, "devicetree" <devicetree@vger.kernel.org>, "linux-kernel"
> <linux-kernel@vger.kernel.org>
> Gesendet: Freitag, 11. August 2023 03:37:12
> Betreff: [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing
> There is no point on returning the error from ubiblock_remove in case
> it is being called due to a volume removal event -- the volume is gone,
> we should destroy and remove the ubiblock device no matter what.
>
> Introduce new boolean parameter 'force' to tell ubiblock_remove to go
> on even in case the ubiblock device is still busy. Use that new option
> when calling ubiblock_remove due to a UBI_VOLUME_REMOVED event.
>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> ---
> drivers/mtd/ubi/block.c | 6 +++---
> drivers/mtd/ubi/cdev.c | 2 +-
> drivers/mtd/ubi/ubi.h | 4 ++--
> 3 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
> index 437c5b83ffe51..69fa6fecb8494 100644
> --- a/drivers/mtd/ubi/block.c
> +++ b/drivers/mtd/ubi/block.c
> @@ -456,7 +456,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
> idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
> }
>
> -int ubiblock_remove(struct ubi_volume_info *vi)
> +int ubiblock_remove(struct ubi_volume_info *vi, bool force)
> {
> struct ubiblock *dev;
> int ret;
> @@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi)
>
> /* Found a device, let's lock it so we can check if it's busy */
> mutex_lock(&dev->dev_mutex);
> - if (dev->refcnt > 0) {
> + if (dev->refcnt > 0 && !force) {
> ret = -EBUSY;
> goto out_unlock_dev;
Is it really safe to destroy the blk queue (via ubiblock_cleanup()) if refcnt is > 0?
Thanks,
//richard
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock
2023-08-11 1:37 ` [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock Daniel Golle
@ 2023-10-03 18:46 ` Richard Weinberger
0 siblings, 0 replies; 19+ messages in thread
From: Richard Weinberger @ 2023-10-03 18:46 UTC (permalink / raw)
To: Daniel Golle
Cc: Randy Dunlap, Miquel Raynal, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, devicetree,
linux-kernel
----- Ursprüngliche Mail -----
> Von: "Daniel Golle" <daniel@makrotopia.org>
> An: "Randy Dunlap" <rdunlap@infradead.org>, "Miquel Raynal" <miquel.raynal@bootlin.com>, "richard" <richard@nod.at>,
> "Vignesh Raghavendra" <vigneshr@ti.com>, "Rob Herring" <robh+dt@kernel.org>, "Krzysztof Kozlowski"
> <krzysztof.kozlowski+dt@linaro.org>, "Conor Dooley" <conor+dt@kernel.org>, "Daniel Golle" <daniel@makrotopia.org>,
> "linux-mtd" <linux-mtd@lists.infradead.org>, "devicetree" <devicetree@vger.kernel.org>, "linux-kernel"
> <linux-kernel@vger.kernel.org>
> Gesendet: Freitag, 11. August 2023 03:37:31
> Betreff: [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock
> Use UBI_VOLUME_ADDED notification to create ubiblock device specified
> on kernel cmdline or module parameter.
> This makes thing more simple and has the advantage that ubiblock devices
*things
> on volumes which are not present at the time the ubi module is probed
> will still be created.
>
> Suggested-by: Zhihao Cheng <chengzhihao1@huawei.com>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> ---
> drivers/mtd/ubi/block.c | 152 ++++++++++++++++++++++------------------
> 1 file changed, 84 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
> index 69fa6fecb8494..e0618bbde3613 100644
> --- a/drivers/mtd/ubi/block.c
> +++ b/drivers/mtd/ubi/block.c
> @@ -33,6 +33,7 @@
> #include <linux/kernel.h>
> #include <linux/list.h>
> #include <linux/mutex.h>
> +#include <linux/namei.h>
> #include <linux/slab.h>
> #include <linux/mtd/ubi.h>
> #include <linux/blkdev.h>
> @@ -65,10 +66,10 @@ struct ubiblock_pdu {
> };
>
> /* Numbers of elements set in the @ubiblock_param array */
> -static int ubiblock_devs __initdata;
> +static int ubiblock_devs;
>
> /* MTD devices specification parameters */
> -static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
> +static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
>
> struct ubiblock {
> struct ubi_volume_desc *desc;
> @@ -532,6 +533,85 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
> return 0;
> }
>
> +static bool
> +match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num,
> int vol_id)
> +{
> + int err, len;
> + struct path path;
> + struct kstat stat;
> +
> + if (ubi_num == -1) {
> + /* No ubi num, name must be a vol device path */
> + err = kern_path(name, LOOKUP_FOLLOW, &path);
> + if (err)
> + return false;
> +
> + err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
> + path_put(&path);
> + if (err)
> + return false;
> +
> + if (!S_ISCHR(stat.mode))
> + return false;
> +
> + if (vi->ubi_num != ubi_major2num(MAJOR(stat.rdev)))
> + return false;
> +
> + if (vi->vol_id != MINOR(stat.rdev) - 1)
> + return false;
> +
This is more or less an open coded ubi_open_volume_path().
Please either split or adopt ubi_open_volume_path() to fit your use case.
> + return true;
> + }
> +
> + if (vol_id == -1) {
> + if (vi->ubi_num != ubi_num)
> + return false;
> +
> + len = strnlen(name, UBI_VOL_NAME_MAX + 1);
> + if (len < 1 || vi->name_len != len)
> + return false;
> +
> + if (strcmp(name, vi->name))
> + return false;
> +
> + return true;
> + }
Same for ubi_open_volume_nm().
Thanks,
//richard
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree
2023-08-11 1:37 ` [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree Daniel Golle
@ 2023-10-03 19:45 ` Richard Weinberger
2023-10-05 20:46 ` Richard Weinberger
0 siblings, 1 reply; 19+ messages in thread
From: Richard Weinberger @ 2023-10-03 19:45 UTC (permalink / raw)
To: Daniel Golle
Cc: Randy Dunlap, Miquel Raynal, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, devicetree,
linux-kernel
----- Ursprüngliche Mail -----
> diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
> index e0618bbde3613..99b5f502c9dbc 100644
> --- a/drivers/mtd/ubi/block.c
> +++ b/drivers/mtd/ubi/block.c
> @@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi, bool force)
> }
>
> /* Found a device, let's lock it so we can check if it's busy */
> - mutex_lock(&dev->dev_mutex);
> + mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
The usage of mutex_lock_nested() in this patch looks fishy.
Can you please elaborate a bit more why all these mutexes can be taken twice?
(Any why not more often).
Thanks,
//richard
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree
2023-10-03 19:45 ` Richard Weinberger
@ 2023-10-05 20:46 ` Richard Weinberger
2023-11-12 15:09 ` Daniel Golle
0 siblings, 1 reply; 19+ messages in thread
From: Richard Weinberger @ 2023-10-05 20:46 UTC (permalink / raw)
To: Daniel Golle
Cc: Randy Dunlap, Miquel Raynal, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, devicetree,
linux-kernel
----- Ursprüngliche Mail -----
> Von: "richard" <richard@nod.at>
> ----- Ursprüngliche Mail -----
>> diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
>> index e0618bbde3613..99b5f502c9dbc 100644
>> --- a/drivers/mtd/ubi/block.c
>> +++ b/drivers/mtd/ubi/block.c
>> @@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi, bool force)
>> }
>>
>> /* Found a device, let's lock it so we can check if it's busy */
>> - mutex_lock(&dev->dev_mutex);
>> + mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
>
> The usage of mutex_lock_nested() in this patch looks fishy.
> Can you please elaborate a bit more why all these mutexes can be taken twice?
> (Any why not more often).
I think I figured myself.
ubiblock_ops->open() and ->release() are both called with disk->open_mutex held.
ubiblock_open() and ubiblock_release() take dev->dev_mutex.
So, the locking order is open_mutex, followed by dev_mutex.
On the other hand, ubiblock_remove() is called via UBI notify.
It takes first dev_mutex and then calls del_gendisk() which will trigger ubiblock_ops->release()
under disk->open_mutex but takes dev_mutex again.
So, we this not only takes a lock twice but also in reverse order.
mutex_lock_nested() might silence lockdep but I'm not sure whether this is safe at all.
Thanks,
//richard
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree
2023-10-05 20:46 ` Richard Weinberger
@ 2023-11-12 15:09 ` Daniel Golle
0 siblings, 0 replies; 19+ messages in thread
From: Daniel Golle @ 2023-11-12 15:09 UTC (permalink / raw)
To: Richard Weinberger
Cc: Randy Dunlap, Miquel Raynal, Vignesh Raghavendra, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-mtd, devicetree,
linux-kernel
Hi Richard,
thank you for the review and sorry for my late reply to it.
On Thu, Oct 05, 2023 at 10:46:41PM +0200, Richard Weinberger wrote:
> ----- Ursprüngliche Mail -----
> > Von: "richard" <richard@nod.at>
> > ----- Ursprüngliche Mail -----
> >> diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
> >> index e0618bbde3613..99b5f502c9dbc 100644
> >> --- a/drivers/mtd/ubi/block.c
> >> +++ b/drivers/mtd/ubi/block.c
> >> @@ -470,7 +470,7 @@ int ubiblock_remove(struct ubi_volume_info *vi, bool force)
> >> }
> >>
> >> /* Found a device, let's lock it so we can check if it's busy */
> >> - mutex_lock(&dev->dev_mutex);
> >> + mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
> >
> > The usage of mutex_lock_nested() in this patch looks fishy.
> > Can you please elaborate a bit more why all these mutexes can be taken twice?
> > (Any why not more often).
>
> I think I figured myself.
> ubiblock_ops->open() and ->release() are both called with disk->open_mutex held.
> ubiblock_open() and ubiblock_release() take dev->dev_mutex.
> So, the locking order is open_mutex, followed by dev_mutex.
>
> On the other hand, ubiblock_remove() is called via UBI notify.
> It takes first dev_mutex and then calls del_gendisk() which will trigger ubiblock_ops->release()
> under disk->open_mutex but takes dev_mutex again.
> So, we this not only takes a lock twice but also in reverse order.
> mutex_lock_nested() might silence lockdep but I'm not sure whether this is safe at all.
I agree that the locking here is not trivial.
Taking the same lock twice is that SINGLE_DEPTH_NESTING is intended
for and resolves running into a deadlock otherwise.
I'm not sure if the changed order of acquiring dev_mutex and open_mutex
present a problem.
The detach-by-notification case is anyway quite exotic and I only see
quite synthetic paths to actually get there (such as hotplug removal
of the SPI controller providing access to SPI-NAND flash, which is how
I was testing this...). To make things easier and more aligned with
the original goal (being to attach a UBI device from DT, early enough
to allow its use as NVMEM provider by other drivers) I suggest to for
now only handle attachment by MTD notification (if linux,ubi compatible
is present in DT) and keep handling detachment the way it is now.
This will (just like it is already now) result in "zombie" UBI devices
being present after their MTD device has already been removed. Accessing
them creates loud kernel warnings at best.
Let me know if keeing detachment the way it is and only implementing
attaching from MTD notification and device tree compatible would be ok
with you.
Thank you!
Best regards
Daniel
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2023-11-12 15:10 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-11 1:36 [PATCH v4 0/8] mtd: ubi: allow UBI volumes to provide NVMEM Daniel Golle
2023-08-11 1:36 ` [PATCH v4 1/8] dt-bindings: mtd: add basic bindings for UBI Daniel Golle
2023-08-21 17:31 ` Rob Herring
2023-09-11 19:01 ` Daniel Golle
2023-09-11 19:10 ` Richard Weinberger
2023-09-13 13:10 ` Tudor Ambarus
2023-08-11 1:36 ` [PATCH v4 2/8] dt-bindings: mtd: nvmem-cells: add support for UBI volumes Daniel Golle
2023-08-21 17:31 ` Rob Herring
2023-08-11 1:37 ` [PATCH v4 3/8] mtd: ubi: block: don't return on error when removing Daniel Golle
2023-10-03 18:14 ` Richard Weinberger
2023-08-11 1:37 ` [PATCH v4 4/8] mtd: ubi: block: use notifier to create ubiblock Daniel Golle
2023-10-03 18:46 ` Richard Weinberger
2023-08-11 1:37 ` [PATCH v4 5/8] mtd: ubi: attach MTD partition from device-tree Daniel Golle
2023-10-03 19:45 ` Richard Weinberger
2023-10-05 20:46 ` Richard Weinberger
2023-11-12 15:09 ` Daniel Golle
2023-08-11 1:38 ` [PATCH v4 6/8] mtd: ubi: introduce pre-removal notification for UBI volumes Daniel Golle
2023-08-11 1:38 ` [PATCH v4 7/8] mtd: ubi: populate ubi volume fwnode Daniel Golle
2023-08-11 1:38 ` [PATCH v4 8/8] mtd: ubi: provide NVMEM layer over UBI volumes Daniel Golle
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).