mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 14:34:27 -05:00 
			
		
		
		
	The series was merged for Linux v6.9, so move it to backports. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
		
			
				
	
	
		
			286 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 2bba1cdcfcd2907d0696cc0139f1bd078d36ee81 Mon Sep 17 00:00:00 2001
 | 
						|
From: Daniel Golle <daniel@makrotopia.org>
 | 
						|
Date: Tue, 19 Dec 2023 02:32:35 +0000
 | 
						|
Subject: [PATCH 3/8] 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>
 | 
						|
Signed-off-by: Richard Weinberger <richard@nod.at>
 | 
						|
---
 | 
						|
 drivers/mtd/ubi/block.c | 136 ++++++++++++++++++++--------------------
 | 
						|
 drivers/mtd/ubi/kapi.c  |  54 +++++++++++-----
 | 
						|
 drivers/mtd/ubi/ubi.h   |   1 +
 | 
						|
 3 files changed, 106 insertions(+), 85 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/mtd/ubi/block.c
 | 
						|
+++ b/drivers/mtd/ubi/block.c
 | 
						|
@@ -65,10 +65,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 +532,70 @@ 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, cur_ubi_num, cur_vol_id;
 | 
						|
+
 | 
						|
+	if (ubi_num == -1) {
 | 
						|
+		/* No ubi num, name must be a vol device path */
 | 
						|
+		err = ubi_get_num_by_path(name, &cur_ubi_num, &cur_vol_id);
 | 
						|
+		if (err || vi->ubi_num != cur_ubi_num || vi->vol_id != cur_vol_id)
 | 
						|
+			return false;
 | 
						|
+
 | 
						|
+		return true;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (vol_id == -1) {
 | 
						|
+		/* Got ubi_num, but no vol_id, name must be volume name */
 | 
						|
+		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 +603,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);
 | 
						|
@@ -568,56 +629,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;
 | 
						|
@@ -643,18 +654,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;
 | 
						|
--- a/drivers/mtd/ubi/kapi.c
 | 
						|
+++ b/drivers/mtd/ubi/kapi.c
 | 
						|
@@ -280,6 +280,41 @@ struct ubi_volume_desc *ubi_open_volume_
 | 
						|
 EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 | 
						|
 
 | 
						|
 /**
 | 
						|
+ * ubi_get_num_by_path - get UBI device and volume number from device path
 | 
						|
+ * @pathname: volume character device node path
 | 
						|
+ * @ubi_num: pointer to UBI device number to be set
 | 
						|
+ * @vol_id: pointer to UBI volume ID to be set
 | 
						|
+ *
 | 
						|
+ * Returns 0 on success and sets ubi_num and vol_id, returns error otherwise.
 | 
						|
+ */
 | 
						|
+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id)
 | 
						|
+{
 | 
						|
+	int error;
 | 
						|
+	struct path path;
 | 
						|
+	struct kstat stat;
 | 
						|
+
 | 
						|
+	error = kern_path(pathname, LOOKUP_FOLLOW, &path);
 | 
						|
+	if (error)
 | 
						|
+		return error;
 | 
						|
+
 | 
						|
+	error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
 | 
						|
+	path_put(&path);
 | 
						|
+	if (error)
 | 
						|
+		return error;
 | 
						|
+
 | 
						|
+	if (!S_ISCHR(stat.mode))
 | 
						|
+		return -EINVAL;
 | 
						|
+
 | 
						|
+	*ubi_num = ubi_major2num(MAJOR(stat.rdev));
 | 
						|
+	*vol_id = MINOR(stat.rdev) - 1;
 | 
						|
+
 | 
						|
+	if (*vol_id < 0 || *ubi_num < 0)
 | 
						|
+		return -ENODEV;
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/**
 | 
						|
  * ubi_open_volume_path - open UBI volume by its character device node path.
 | 
						|
  * @pathname: volume character device node path
 | 
						|
  * @mode: open mode
 | 
						|
@@ -290,32 +325,17 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 | 
						|
 struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
 | 
						|
 {
 | 
						|
 	int error, ubi_num, vol_id;
 | 
						|
-	struct path path;
 | 
						|
-	struct kstat stat;
 | 
						|
 
 | 
						|
 	dbg_gen("open volume %s, mode %d", pathname, mode);
 | 
						|
 
 | 
						|
 	if (!pathname || !*pathname)
 | 
						|
 		return ERR_PTR(-EINVAL);
 | 
						|
 
 | 
						|
-	error = kern_path(pathname, LOOKUP_FOLLOW, &path);
 | 
						|
-	if (error)
 | 
						|
-		return ERR_PTR(error);
 | 
						|
-
 | 
						|
-	error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
 | 
						|
-	path_put(&path);
 | 
						|
+	error = ubi_get_num_by_path(pathname, &ubi_num, &vol_id);
 | 
						|
 	if (error)
 | 
						|
 		return ERR_PTR(error);
 | 
						|
 
 | 
						|
-	if (!S_ISCHR(stat.mode))
 | 
						|
-		return ERR_PTR(-EINVAL);
 | 
						|
-
 | 
						|
-	ubi_num = ubi_major2num(MAJOR(stat.rdev));
 | 
						|
-	vol_id = MINOR(stat.rdev) - 1;
 | 
						|
-
 | 
						|
-	if (vol_id >= 0 && ubi_num >= 0)
 | 
						|
-		return ubi_open_volume(ubi_num, vol_id, mode);
 | 
						|
-	return ERR_PTR(-ENODEV);
 | 
						|
+	return ubi_open_volume(ubi_num, vol_id, mode);
 | 
						|
 }
 | 
						|
 EXPORT_SYMBOL_GPL(ubi_open_volume_path);
 | 
						|
 
 | 
						|
--- a/drivers/mtd/ubi/ubi.h
 | 
						|
+++ b/drivers/mtd/ubi/ubi.h
 | 
						|
@@ -956,6 +956,7 @@ void ubi_free_internal_volumes(struct ub
 | 
						|
 void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
 | 
						|
 void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
 | 
						|
 			    struct ubi_volume_info *vi);
 | 
						|
+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id);
 | 
						|
 /* scan.c */
 | 
						|
 int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
 | 
						|
 		      int pnum, const struct ubi_vid_hdr *vid_hdr);
 |