@@ -619,7 +619,7 @@ open_volume_desc(const char *name, int ubi_num, int vol_id)
return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
}
-static void __init ubiblock_create_from_param(void)
+void __init ubiblock_create_from_param(void)
{
int i, ret = 0;
struct ubiblock_param *p;
@@ -648,9 +648,10 @@ static void __init ubiblock_create_from_param(void)
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);
+ if (ret != -EEXIST && ret != -ENOENT)
+ 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;
}
}
@@ -681,13 +682,6 @@ 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.
@@ -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"
@@ -1198,9 +1199,42 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
return mtd;
}
+static void __init ubi_notify_add(struct mtd_info *mtd)
+{
+ struct device_node *np = mtd_get_of_node(mtd);
+ int err;
+
+ if (!of_device_is_compatible(np, "linux,ubi"))
+ return;
+
+ mutex_lock(&ubi_devices_mutex);
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
+ mutex_unlock(&ubi_devices_mutex);
+ if (err >= 0)
+ ubiblock_create_from_param();
+}
+
+static void __init ubi_notify_remove(struct mtd_info *mtd)
+{
+ int i;
+
+ for (i = 0; i < UBI_MAX_DEVICES; i++)
+ if (ubi_devices[i]) {
+ mutex_lock(&ubi_devices_mutex);
+ if (ubi_devices[i]->mtd->index == mtd->index)
+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+ mutex_unlock(&ubi_devices_mutex);
+ }
+}
+
+static struct mtd_notifier ubi_mtd_notifier __initdata = {
+ .add = ubi_notify_add,
+ .remove = ubi_notify_remove,
+};
+
static int __init ubi_init(void)
{
- int err, i, k;
+ int err;
/* Ensure that EC and VID headers have correct size */
BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
@@ -1235,6 +1269,33 @@ static int __init ubi_init(void)
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_slab;
+ }
+
+ register_mtd_user(&ubi_mtd_notifier);
+
+ return 0;
+out_slab:
+ kmem_cache_destroy(ubi_wl_entry_slab);
+out_dev_unreg:
+ misc_deregister(&ubi_ctrl_cdev);
+out:
+ class_unregister(&ubi_class);
+ pr_err("UBI error: cannot initialize UBI, error %d\n", err);
+
+ return err;
+}
+device_initcall(ubi_init);
+
+static int __init ubi_init_attach(void)
+{
+ int err, i, k;
/* Attach MTD devices */
for (i = 0; i < mtd_devs; i++) {
@@ -1282,14 +1343,10 @@ static int __init ubi_init(void)
}
}
- 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;
- }
+ /*
+ * Attach block devices from 'block=' module param.
+ */
+ ubiblock_create_from_param();
return 0;
@@ -1300,17 +1357,9 @@ static int __init ubi_init(void)
ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
mutex_unlock(&ubi_devices_mutex);
}
- ubi_debugfs_exit();
-out_slab:
- kmem_cache_destroy(ubi_wl_entry_slab);
-out_dev_unreg:
- misc_deregister(&ubi_ctrl_cdev);
-out:
- class_unregister(&ubi_class);
- pr_err("UBI error: cannot initialize UBI, error %d\n", err);
return err;
}
-late_initcall(ubi_init);
+late_initcall(ubi_init_attach);
static void __exit ubi_exit(void)
{
@@ -976,11 +976,13 @@ static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {}
/* block.c */
#ifdef CONFIG_MTD_UBI_BLOCK
+void ubiblock_create_from_param(void);
int ubiblock_init(void);
void ubiblock_exit(void);
int ubiblock_create(struct ubi_volume_info *vi);
int ubiblock_remove(struct ubi_volume_info *vi);
#else
+static inline void ubiblock_create_from_param(void) {}
static inline int ubiblock_init(void) { return 0; }
static inline void ubiblock_exit(void) {}
static inline int ubiblock_create(struct ubi_volume_info *vi)