mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 18:47:06 +00:00
fc153aa8d9
Similar to supporting nvmem-layouts on MTD devices, also allow referencing UBI and MMC devices in DT. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
226 lines
6.0 KiB
Diff
226 lines
6.0 KiB
Diff
From e5cf19bd8204925f3bd2067df9e867313eac388b Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Mon, 1 May 2023 11:57:51 +0100
|
|
Subject: [PATCH 03/15] mtd: ubi: block: use notifier to create ubiblock from
|
|
parameter
|
|
|
|
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 | 154 ++++++++++++++++++++++------------------
|
|
1 file changed, 85 insertions(+), 69 deletions(-)
|
|
|
|
--- 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/workqueue.h>
|
|
@@ -67,10 +68,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;
|
|
@@ -504,7 +505,7 @@ int ubiblock_remove(struct ubi_volume_in
|
|
}
|
|
|
|
/* 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) {
|
|
ret = -EBUSY;
|
|
goto out_unlock_dev;
|
|
@@ -567,6 +568,85 @@ static int ubiblock_resize(struct ubi_vo
|
|
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)
|
|
{
|
|
@@ -574,10 +654,7 @@ static int ubiblock_notify(struct notifi
|
|
|
|
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);
|
|
@@ -603,56 +680,6 @@ static struct notifier_block ubiblock_no
|
|
.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;
|
|
@@ -678,18 +705,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;
|