Linux 6.9-rc5
[sfrench/cifs-2.6.git] / drivers / mtd / ubi / block.c
index 5c8fdcc088a0df73e4ee4684a4406780fddd978e..f82e3423acb9fb92c3d46bc92a1a1f6d31e66e83 100644 (file)
@@ -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;
@@ -536,6 +536,70 @@ 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, 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)
 {
@@ -543,10 +607,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);
@@ -572,56 +633,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;
@@ -647,18 +658,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;