From 49dfc299288fe183b62a3f679a40c91b482d6d73 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sat, 15 Dec 2007 18:13:56 +0200 Subject: UBI: remove redundant field Remove redundant ubi->major field - we have it in ubi->cdev.dev already. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 023653977a1a..b0791f795056 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -150,7 +150,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi) int err; ubi->dev.release = dev_release; - ubi->dev.devt = MKDEV(ubi->major, 0); + ubi->dev.devt = ubi->cdev.dev; ubi->dev.class = ubi_class; sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); err = device_register(&ubi->dev); @@ -278,12 +278,11 @@ static int uif_init(struct ubi_device *ubi) return err; } + ubi_assert(MINOR(dev) == 0); cdev_init(&ubi->cdev, &ubi_cdev_operations); - ubi->major = MAJOR(dev); - dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); + dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); ubi->cdev.owner = THIS_MODULE; - dev = MKDEV(ubi->major, 0); err = cdev_add(&ubi->cdev, dev, 1); if (err) { ubi_err("cannot add character device %s", ubi->ubi_name); @@ -309,8 +308,7 @@ out_volumes: out_cdev: cdev_del(&ubi->cdev); out_unreg: - unregister_chrdev_region(MKDEV(ubi->major, 0), - ubi->vtbl_slots + 1); + unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); return err; } @@ -323,7 +321,7 @@ static void uif_close(struct ubi_device *ubi) kill_volumes(ubi); ubi_sysfs_close(ubi); cdev_del(&ubi->cdev); - unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); + unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); } /** -- cgit v1.2.3 From 01f7b309e453dc8499c318f6810f76b606b66134 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sat, 15 Dec 2007 19:56:51 +0200 Subject: UBI: improve error messages Always print error code with error messages, sometimes it is extremely helpful info. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index b0791f795056..5490a73deca5 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -211,7 +211,8 @@ out_eraseblock_size: out_unregister: device_unregister(&ubi->dev); out: - ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); + ubi_err("failed to initialize sysfs for %s, error %d", + ubi->ubi_name, err); return err; } @@ -285,7 +286,7 @@ static int uif_init(struct ubi_device *ubi) err = cdev_add(&ubi->cdev, dev, 1); if (err) { - ubi_err("cannot add character device %s", ubi->ubi_name); + ubi_err("cannot add character device"); goto out_unreg; } @@ -296,8 +297,10 @@ static int uif_init(struct ubi_device *ubi) for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) { err = ubi_add_volume(ubi, i); - if (err) + if (err) { + ubi_err("cannot add volume %d", i); goto out_volumes; + } } return 0; @@ -309,6 +312,7 @@ out_cdev: cdev_del(&ubi->cdev); out_unreg: unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); + ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); return err; } @@ -422,7 +426,8 @@ static int io_init(struct ubi_device *ubi) /* Make sure minimal I/O unit is power of 2 */ if (!is_power_of_2(ubi->min_io_size)) { - ubi_err("bad min. I/O unit"); + ubi_err("min. I/O unit (%d) is not power of 2", + ubi->min_io_size); return -EINVAL; } -- cgit v1.2.3 From 3a8d4642861fb69b62401949e490c0bcb19ceb40 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 12:32:51 +0200 Subject: UBI: create ltree_entry slab on initialization Since the ltree_entry slab cache is a global entity, which is used by all UBI devices, it is more logical to create it on module initialization time and destro on module exit time. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5490a73deca5..44c852144a9c 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -67,6 +67,9 @@ struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; /* Root UBI "class" object (corresponds to '//class/ubi/') */ struct class *ubi_class; +/* Slab cache for lock-tree entries */ +struct kmem_cache *ubi_ltree_slab; + /* "Show" method for files in '//class/ubi/' */ static ssize_t ubi_version_show(struct class *class, char *buf) { @@ -687,6 +690,20 @@ static void detach_mtd_dev(struct ubi_device *ubi) ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); } +/** + * ltree_entry_ctor - lock tree entries slab cache constructor. + * @obj: the lock-tree entry to construct + * @cache: the lock tree entry slab cache + * @flags: constructor flags + */ +static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) +{ + struct ubi_ltree_entry *le = obj; + + le->users = 0; + init_rwsem(&le->mutex); +} + static int __init ubi_init(void) { int err, i, k; @@ -709,6 +726,12 @@ static int __init ubi_init(void) if (err) goto out_class; + ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab", + sizeof(struct ubi_ltree_entry), 0, + 0, <ree_entry_ctor); + if (!ubi_ltree_slab) + goto out_version; + /* Attach MTD devices */ for (i = 0; i < mtd_devs; i++) { struct mtd_dev_param *p = &mtd_dev_param[i]; @@ -724,6 +747,8 @@ static int __init ubi_init(void) out_detach: for (k = 0; k < i; k++) detach_mtd_dev(ubi_devices[k]); + kmem_cache_destroy(ubi_ltree_slab); +out_version: class_remove_file(ubi_class, &ubi_version); out_class: class_destroy(ubi_class); @@ -737,6 +762,7 @@ static void __exit ubi_exit(void) for (i = 0; i < n; i++) detach_mtd_dev(ubi_devices[i]); + kmem_cache_destroy(ubi_ltree_slab); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); } -- cgit v1.2.3 From 06b68ba15671f32a3aa3bbddf04b0d2dd7fbf902 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 12:49:01 +0200 Subject: UBI: create ubi_wl_entry slab on initialization Similarly to ltree_entry_slab, it makes more sense to create and destroy ubi_wl_entry slab on module initialization/exit. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 44c852144a9c..7f6820becf10 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -70,6 +70,10 @@ struct class *ubi_class; /* Slab cache for lock-tree entries */ struct kmem_cache *ubi_ltree_slab; +/* Slab cache for wear-leveling entries */ +struct kmem_cache *ubi_wl_entry_slab; + + /* "Show" method for files in '//class/ubi/' */ static ssize_t ubi_version_show(struct class *class, char *buf) { @@ -732,6 +736,12 @@ static int __init ubi_init(void) if (!ubi_ltree_slab) goto out_version; + ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", + sizeof(struct ubi_wl_entry), + 0, 0, NULL); + if (!ubi_wl_entry_slab) + goto out_ltree; + /* Attach MTD devices */ for (i = 0; i < mtd_devs; i++) { struct mtd_dev_param *p = &mtd_dev_param[i]; @@ -747,6 +757,8 @@ static int __init ubi_init(void) out_detach: for (k = 0; k < i; k++) detach_mtd_dev(ubi_devices[k]); + kmem_cache_destroy(ubi_wl_entry_slab); +out_ltree: kmem_cache_destroy(ubi_ltree_slab); out_version: class_remove_file(ubi_class, &ubi_version); @@ -762,6 +774,7 @@ static void __exit ubi_exit(void) for (i = 0; i < n; i++) detach_mtd_dev(ubi_devices[i]); + kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_ltree_slab); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); -- cgit v1.2.3 From b96bf4c33d4860bf1584ad2f9ed3b783d79aada8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 13:01:03 +0200 Subject: UBI: remove ubi_devices_cnt This global variablea is not really needed, remove it Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 7f6820becf10..9b94427be145 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -58,9 +58,6 @@ static int mtd_devs = 0; /* MTD devices specification parameters */ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; -/* Number of UBI devices in system */ -int ubi_devices_cnt; - /* All UBI devices in system */ struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; @@ -566,26 +563,39 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, } /* Check if we already have the same MTD device attached */ - for (i = 0; i < ubi_devices_cnt; i++) - if (ubi_devices[i]->mtd->index == mtd->index) { + for (i = 0; i < UBI_MAX_DEVICES; i++) + ubi = ubi_devices[i]; + if (ubi && ubi->mtd->index == mtd->index) { ubi_err("mtd%d is already attached to ubi%d", mtd->index, i); err = -EINVAL; goto out_mtd; } - ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), - GFP_KERNEL); + ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); if (!ubi) { err = -ENOMEM; goto out_mtd; } - ubi->ubi_num = ubi_devices_cnt; ubi->mtd = mtd; + /* Search for an empty slot in the @ubi_devices array */ + ubi->ubi_num = -1; + for (i = 0; i < UBI_MAX_DEVICES; i++) + if (!ubi_devices[i]) { + ubi->ubi_num = i; + break; + } + + if (ubi->ubi_num == -1) { + ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); + err = -ENFILE; + goto out_free; + } + dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", - ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset); + ubi->mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); ubi->vid_hdr_offset = vid_hdr_offset; ubi->leb_start = data_offset; @@ -619,7 +629,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, if (err) goto out_detach; - ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); + ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi->ubi_num); ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); ubi_msg("physical eraseblock size: %d bytes (%d KiB)", @@ -648,7 +658,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, wake_up_process(ubi->bgt_thread); } - ubi_devices_cnt += 1; + ubi_devices[ubi->ubi_num] = ubi; return 0; out_detach: @@ -664,7 +674,6 @@ out_free: kfree(ubi); out_mtd: put_mtd_device(mtd); - ubi_devices[ubi_devices_cnt] = NULL; return err; } @@ -689,8 +698,6 @@ static void detach_mtd_dev(struct ubi_device *ubi) #endif kfree(ubi_devices[ubi_num]); ubi_devices[ubi_num] = NULL; - ubi_devices_cnt -= 1; - ubi_assert(ubi_devices_cnt >= 0); ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); } @@ -770,10 +777,11 @@ module_init(ubi_init); static void __exit ubi_exit(void) { - int i, n = ubi_devices_cnt; + int i; - for (i = 0; i < n; i++) - detach_mtd_dev(ubi_devices[i]); + for (i = 0; i < UBI_MAX_DEVICES; i++) + if (ubi_devices[i]) + detach_mtd_dev(ubi_devices[i]); kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_ltree_slab); class_remove_file(ubi_class, &ubi_version); -- cgit v1.2.3 From 77c722dde9975361051c5530475f8f92ed67a506 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 16:46:57 +0200 Subject: UBI: bugfix: dont oops with NULL module parameter E.g., it oopsed in case of: modprobe ubi mtd = 0 Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 9b94427be145..b85ca186afc6 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -845,6 +845,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) char *pbuf = &buf[0]; char *tokens[3] = {NULL, NULL, NULL}; + if (!val) + return -EINVAL; + if (mtd_devs == UBI_MAX_DEVICES) { printk("UBI error: too many parameters, max. is %d\n", UBI_MAX_DEVICES); -- cgit v1.2.3 From 89b96b69290668351a33b09372ec1c94cb5748e5 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 20:00:38 +0200 Subject: UBI: improve internal interfaces Pass volume description object to the EBA function which makes more sense, and EBA function do not have to find the volume description object by volume ID. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index b85ca186afc6..5d00364d4a4a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -249,7 +249,7 @@ static void kill_volumes(struct ubi_device *ubi) for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) - ubi_free_volume(ubi, i); + ubi_free_volume(ubi, ubi->volumes[i]); } /** @@ -300,7 +300,7 @@ static int uif_init(struct ubi_device *ubi) for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) { - err = ubi_add_volume(ubi, i); + err = ubi_add_volume(ubi, ubi->volumes[i]); if (err) { ubi_err("cannot add volume %d", i); goto out_volumes; -- cgit v1.2.3 From cae0a77125467c42f0918e78457913ee4a2f925b Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 17 Dec 2007 12:46:48 +0200 Subject: UBI: tweak volumes locking Transform vtbl_mutex to volumes_mutex - this just makes code easier to understand. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5d00364d4a4a..61225f493f6d 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -264,7 +264,7 @@ static int uif_init(struct ubi_device *ubi) int i, err; dev_t dev; - mutex_init(&ubi->vtbl_mutex); + mutex_init(&ubi->volumes_mutex); spin_lock_init(&ubi->volumes_lock); sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); -- cgit v1.2.3 From db6e5770ef0ab351a403ac26e1ab1309e58f15d7 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 17 Dec 2007 15:48:49 +0200 Subject: UBI: simplify error handling If we fail halfway through sysfs file creation, we may just call sysfs remove function and it will delete all the files we created. For non-existing files it will also be OK - the remove functions just return -ENOENT. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 52 ++++++++++++------------------------------------- 1 file changed, 12 insertions(+), 40 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 61225f493f6d..6ad291b33a1e 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -159,64 +159,36 @@ static int ubi_sysfs_init(struct ubi_device *ubi) sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); err = device_register(&ubi->dev); if (err) - goto out; + return err; err = device_create_file(&ubi->dev, &dev_eraseblock_size); if (err) - goto out_unregister; + return err; err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); if (err) - goto out_eraseblock_size; + return err; err = device_create_file(&ubi->dev, &dev_total_eraseblocks); if (err) - goto out_avail_eraseblocks; + return err; err = device_create_file(&ubi->dev, &dev_volumes_count); if (err) - goto out_total_eraseblocks; + return err; err = device_create_file(&ubi->dev, &dev_max_ec); if (err) - goto out_volumes_count; + return err; err = device_create_file(&ubi->dev, &dev_reserved_for_bad); if (err) - goto out_volumes_max_ec; + return err; err = device_create_file(&ubi->dev, &dev_bad_peb_count); if (err) - goto out_reserved_for_bad; + return err; err = device_create_file(&ubi->dev, &dev_max_vol_count); if (err) - goto out_bad_peb_count; + return err; err = device_create_file(&ubi->dev, &dev_min_io_size); if (err) - goto out_max_vol_count; + return err; err = device_create_file(&ubi->dev, &dev_bgt_enabled); - if (err) - goto out_min_io_size; - - return 0; - -out_min_io_size: - device_remove_file(&ubi->dev, &dev_min_io_size); -out_max_vol_count: - device_remove_file(&ubi->dev, &dev_max_vol_count); -out_bad_peb_count: - device_remove_file(&ubi->dev, &dev_bad_peb_count); -out_reserved_for_bad: - device_remove_file(&ubi->dev, &dev_reserved_for_bad); -out_volumes_max_ec: - device_remove_file(&ubi->dev, &dev_max_ec); -out_volumes_count: - device_remove_file(&ubi->dev, &dev_volumes_count); -out_total_eraseblocks: - device_remove_file(&ubi->dev, &dev_total_eraseblocks); -out_avail_eraseblocks: - device_remove_file(&ubi->dev, &dev_avail_eraseblocks); -out_eraseblock_size: - device_remove_file(&ubi->dev, &dev_eraseblock_size); -out_unregister: - device_unregister(&ubi->dev); -out: - ubi_err("failed to initialize sysfs for %s, error %d", - ubi->ubi_name, err); return err; } @@ -296,7 +268,7 @@ static int uif_init(struct ubi_device *ubi) err = ubi_sysfs_init(ubi); if (err) - goto out_cdev; + goto out_sysfs; for (i = 0; i < ubi->vtbl_slots; i++) if (ubi->volumes[i]) { @@ -311,8 +283,8 @@ static int uif_init(struct ubi_device *ubi) out_volumes: kill_volumes(ubi); +out_sysfs: ubi_sysfs_close(ubi); -out_cdev: cdev_del(&ubi->cdev); out_unreg: unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); -- cgit v1.2.3 From 458dbb3d07574e8fcdcb921ac155ccd81b16b05f Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 19 Dec 2007 17:03:42 +0200 Subject: UBI: fix printk Add proper log level to printk's. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6ad291b33a1e..b3efb2fa3c10 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -696,8 +696,8 @@ static int __init ubi_init(void) BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); if (mtd_devs > UBI_MAX_DEVICES) { - printk("UBI error: too many MTD devices, maximum is %d\n", - UBI_MAX_DEVICES); + printk(KERN_ERR "UBI error: too many MTD devices, " + "maximum is %d\n", UBI_MAX_DEVICES); return -EINVAL; } @@ -776,7 +776,8 @@ static int __init bytes_str_to_int(const char *str) result = simple_strtoul(str, &endp, 0); if (str == endp || result < 0) { - printk("UBI error: incorrect bytes count: \"%s\"\n", str); + printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", + str); return -EINVAL; } @@ -794,7 +795,8 @@ static int __init bytes_str_to_int(const char *str) case '\0': break; default: - printk("UBI error: incorrect bytes count: \"%s\"\n", str); + printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", + str); return -EINVAL; } @@ -821,20 +823,21 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) return -EINVAL; if (mtd_devs == UBI_MAX_DEVICES) { - printk("UBI error: too many parameters, max. is %d\n", + printk(KERN_ERR "UBI error: too many parameters, max. is %d\n", UBI_MAX_DEVICES); return -EINVAL; } len = strnlen(val, MTD_PARAM_LEN_MAX); if (len == MTD_PARAM_LEN_MAX) { - printk("UBI error: parameter \"%s\" is too long, max. is %d\n", - val, MTD_PARAM_LEN_MAX); + printk(KERN_ERR "UBI error: parameter \"%s\" is too long, " + "max. is %d\n", val, MTD_PARAM_LEN_MAX); return -EINVAL; } if (len == 0) { - printk("UBI warning: empty 'mtd=' parameter - ignored\n"); + printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - " + "ignored\n"); return 0; } @@ -848,7 +851,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) tokens[i] = strsep(&pbuf, ","); if (pbuf) { - printk("UBI error: too many arguments at \"%s\"\n", val); + printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n", + val); return -EINVAL; } -- cgit v1.2.3 From 9f961b57568960a150cc9781c52824c9093a0514 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Dec 2007 16:59:31 +0200 Subject: UBI: add UBI control device This patch is a preparation to make UBI devices dynamic. It adds an UBI control device which has dynamically allocated major number and registers itself as "ubi_ctrl". It does not do anything so far. The idea is that this device will allow to attach/detach MTD devices from userspace. This is symilar to what the Linux device mapper has. The next things to do are: * Fix UBI, because it now assumes UBI devices cannot go away * Implement control device ioctls which will attach/detach MTD devices Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 52 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index b3efb2fa3c10..3f37b16f8774 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -21,11 +21,16 @@ */ /* - * This file includes UBI initialization and building of UBI devices. At the - * moment UBI devices may only be added while UBI is initialized, but dynamic - * device add/remove functionality is planned. Also, at the moment we only - * attach UBI devices by scanning, which will become a bottleneck when flashes - * reach certain large size. Then one may improve UBI and add other methods. + * This file includes UBI initialization and building of UBI devices. + * + * When UBI is initialized, it attaches all the MTD devices specified as the + * module load parameters or the kernel boot parameters. If MTD devices were + * specified, UBI does not attach any MTD device, but it is possible to do + * later using the "UBI control device". + * + * At the moment we only attach UBI devices by scanning, which will become a + * bottleneck when flashes reach certain large size. Then one may improve UBI + * and add other methods, although it does not seem to be easy to do. */ #include @@ -33,6 +38,7 @@ #include #include #include +#include #include #include "ubi.h" @@ -70,6 +76,12 @@ struct kmem_cache *ubi_ltree_slab; /* Slab cache for wear-leveling entries */ struct kmem_cache *ubi_wl_entry_slab; +/* UBI control character device */ +static struct miscdevice ubi_ctrl_cdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ubi_ctrl", + .fops = &ubi_ctrl_cdev_operations, +}; /* "Show" method for files in '//class/ubi/' */ static ssize_t ubi_version_show(struct class *class, char *buf) @@ -701,19 +713,31 @@ static int __init ubi_init(void) return -EINVAL; } + /* Create base sysfs directory and sysfs files */ ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); - if (IS_ERR(ubi_class)) - return PTR_ERR(ubi_class); + if (IS_ERR(ubi_class)) { + err = PTR_ERR(ubi_class); + printk(KERN_ERR "UBI error: cannot create UBI class\n"); + goto out; + } err = class_create_file(ubi_class, &ubi_version); - if (err) + if (err) { + printk(KERN_ERR "UBI error: cannot create sysfs file\n"); goto out_class; + } + + err = misc_register(&ubi_ctrl_cdev); + if (err) { + printk(KERN_ERR "UBI error: cannot register device\n"); + goto out_version; + } ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab", sizeof(struct ubi_ltree_entry), 0, 0, <ree_entry_ctor); if (!ubi_ltree_slab) - goto out_version; + goto out_dev_unreg; ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", sizeof(struct ubi_wl_entry), @@ -727,8 +751,11 @@ static int __init ubi_init(void) cond_resched(); err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); - if (err) + if (err) { + printk(KERN_ERR "UBI error: cannot attach %s\n", + p->name); goto out_detach; + } } return 0; @@ -739,10 +766,14 @@ out_detach: kmem_cache_destroy(ubi_wl_entry_slab); out_ltree: kmem_cache_destroy(ubi_ltree_slab); +out_dev_unreg: + misc_deregister(&ubi_ctrl_cdev); out_version: class_remove_file(ubi_class, &ubi_version); out_class: class_destroy(ubi_class); +out: + printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err); return err; } module_init(ubi_init); @@ -756,6 +787,7 @@ static void __exit ubi_exit(void) detach_mtd_dev(ubi_devices[i]); kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_ltree_slab); + misc_deregister(&ubi_ctrl_cdev); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); } -- cgit v1.2.3 From e73f4459d969bb266f03dd4cbe21bdba8cb2732c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 17 Dec 2007 17:37:26 +0200 Subject: UBI: add UBI devices reference counting This is one more step on the way to "removable" UBI devices. It adds reference counting for UBI devices. Every time a volume on this device is opened - the device's refcount is increased. It is also increased if someone is reading any sysfs file of this UBI device or of one of its volumes. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 142 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 15 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 3f37b16f8774..a4faf71ee3f2 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -64,9 +64,6 @@ static int mtd_devs = 0; /* MTD devices specification parameters */ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; -/* All UBI devices in system */ -struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; - /* Root UBI "class" object (corresponds to '//class/ubi/') */ struct class *ubi_class; @@ -83,6 +80,12 @@ static struct miscdevice ubi_ctrl_cdev = { .fops = &ubi_ctrl_cdev_operations, }; +/* All UBI devices in system */ +static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; + +/* Protects @ubi_devices and @ubi->ref_count */ +static DEFINE_SPINLOCK(ubi_devices_lock); + /* "Show" method for files in '//class/ubi/' */ static ssize_t ubi_version_show(struct class *class, char *buf) { @@ -118,37 +121,145 @@ static struct device_attribute dev_min_io_size = static struct device_attribute dev_bgt_enabled = __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); +/** + * ubi_get_device - get UBI device. + * @ubi_num: UBI device number + * + * This function returns UBI device description object for UBI device number + * @ubi_num, or %NULL if the device does not exist. This function increases the + * device reference count to prevent removal of the device. In other words, the + * device cannot be removed if its reference count is not zero. + */ +struct ubi_device *ubi_get_device(int ubi_num) +{ + struct ubi_device *ubi; + + spin_lock(&ubi_devices_lock); + ubi = ubi_devices[ubi_num]; + if (ubi) { + ubi_assert(ubi->ref_count >= 0); + ubi->ref_count += 1; + get_device(&ubi->dev); + } + spin_unlock(&ubi_devices_lock); + + return ubi; +} + +/** + * ubi_put_device - drop an UBI device reference. + * @ubi: UBI device description object + */ +void ubi_put_device(struct ubi_device *ubi) +{ + spin_lock(&ubi_devices_lock); + ubi->ref_count -= 1; + put_device(&ubi->dev); + spin_unlock(&ubi_devices_lock); +} + +/** + * ubi_get_by_major - get UBI device description object by character device + * major number. + * @major: major number + * + * This function is similar to 'ubi_get_device()', but it searches the device + * by its major number. + */ +struct ubi_device *ubi_get_by_major(int major) +{ + int i; + struct ubi_device *ubi; + + spin_lock(&ubi_devices_lock); + for (i = 0; i < UBI_MAX_DEVICES; i++) { + ubi = ubi_devices[i]; + if (ubi && MAJOR(ubi->cdev.dev) == major) { + ubi_assert(ubi->ref_count >= 0); + ubi->ref_count += 1; + get_device(&ubi->dev); + spin_unlock(&ubi_devices_lock); + return ubi; + } + } + spin_unlock(&ubi_devices_lock); + + return NULL; +} + +/** + * ubi_major2num - get UBI device number by character device major number. + * @major: major number + * + * This function searches UBI device number object by its major number. If UBI + * device was not found, this function returns -ENODEV, othewise the UBI device + * number is returned. + */ +int ubi_major2num(int major) +{ + int i, ubi_num = -ENODEV; + + spin_lock(&ubi_devices_lock); + for (i = 0; i < UBI_MAX_DEVICES; i++) { + struct ubi_device *ubi = ubi_devices[i]; + + if (ubi && MAJOR(ubi->cdev.dev) == major) { + ubi_num = ubi->ubi_num; + break; + } + } + spin_unlock(&ubi_devices_lock); + + return ubi_num; +} + /* "Show" method for files in '//class/ubi/ubiX/' */ static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct ubi_device *ubi; + ssize_t ret; + struct ubi_device *ubi; + /* + * The below code looks weird, but it actually makes sense. We get the + * UBI device reference from the contained 'struct ubi_device'. But it + * is unclear if the device was removed or not yet. Indeed, if the + * device was removed before we increased its reference count, + * 'ubi_get_device()' will return -ENODEV and we fail. + * + * Remember, 'struct ubi_device' is freed in the release function, so + * we still can use 'ubi->ubi_num'. + */ ubi = container_of(dev, struct ubi_device, dev); + ubi = ubi_get_device(ubi->ubi_num); + if (!ubi) + return -ENODEV; + if (attr == &dev_eraseblock_size) - return sprintf(buf, "%d\n", ubi->leb_size); + ret = sprintf(buf, "%d\n", ubi->leb_size); else if (attr == &dev_avail_eraseblocks) - return sprintf(buf, "%d\n", ubi->avail_pebs); + ret = sprintf(buf, "%d\n", ubi->avail_pebs); else if (attr == &dev_total_eraseblocks) - return sprintf(buf, "%d\n", ubi->good_peb_count); + ret = sprintf(buf, "%d\n", ubi->good_peb_count); else if (attr == &dev_volumes_count) - return sprintf(buf, "%d\n", ubi->vol_count); + ret = sprintf(buf, "%d\n", ubi->vol_count); else if (attr == &dev_max_ec) - return sprintf(buf, "%d\n", ubi->max_ec); + ret = sprintf(buf, "%d\n", ubi->max_ec); else if (attr == &dev_reserved_for_bad) - return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); + ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); else if (attr == &dev_bad_peb_count) - return sprintf(buf, "%d\n", ubi->bad_peb_count); + ret = sprintf(buf, "%d\n", ubi->bad_peb_count); else if (attr == &dev_max_vol_count) - return sprintf(buf, "%d\n", ubi->vtbl_slots); + ret = sprintf(buf, "%d\n", ubi->vtbl_slots); else if (attr == &dev_min_io_size) - return sprintf(buf, "%d\n", ubi->min_io_size); + ret = sprintf(buf, "%d\n", ubi->min_io_size); else if (attr == &dev_bgt_enabled) - return sprintf(buf, "%d\n", ubi->thread_enabled); + ret = sprintf(buf, "%d\n", ubi->thread_enabled); else BUG(); - return 0; + ubi_put_device(ubi); + return ret; } /* Fake "release" method for UBI devices */ @@ -670,6 +781,7 @@ static void detach_mtd_dev(struct ubi_device *ubi) int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); + ubi_assert(ubi->ref_count == 0); uif_close(ubi); ubi_eba_close(ubi); ubi_wl_close(ubi); -- cgit v1.2.3 From cdfa788acd134a35d3e5b73d1a76fca4033d8aa9 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 17 Dec 2007 20:33:20 +0200 Subject: UBI: prepare attach and detach functions Prepare the attach and detach functions to by used outside of module initialization: * detach function checks reference count before detaching * it kills the background thread as well Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 235 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 162 insertions(+), 73 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a4faf71ee3f2..071454376643 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ @@ -83,6 +84,9 @@ static struct miscdevice ubi_ctrl_cdev = { /* All UBI devices in system */ static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; +/* Serializes UBI devices creations and removals */ +DEFINE_MUTEX(ubi_devices_mutex); + /* Protects @ubi_devices and @ubi->ref_count */ static DEFINE_SPINLOCK(ubi_devices_lock); @@ -192,7 +196,7 @@ struct ubi_device *ubi_get_by_major(int major) * @major: major number * * This function searches UBI device number object by its major number. If UBI - * device was not found, this function returns -ENODEV, othewise the UBI device + * device was not found, this function returns -ENODEV, otherwise the UBI device * number is returned. */ int ubi_major2num(int major) @@ -485,9 +489,9 @@ out_si: * assumed: * o EC header is always at offset zero - this cannot be changed; * o VID header starts just after the EC header at the closest address - * aligned to @io->@hdrs_min_io_size; + * aligned to @io->hdrs_min_io_size; * o data starts just after the VID header at the closest address aligned to - * @io->@min_io_size + * @io->min_io_size * * This function returns zero in case of success and a negative error code in * case of failure. @@ -508,6 +512,9 @@ static int io_init(struct ubi_device *ubi) return -EINVAL; } + if (ubi->vid_hdr_offset < 0 || ubi->leb_start < ubi->vid_hdr_offset) + return -EINVAL; + /* * Note, in this implementation we support MTD devices with 0x7FFFFFFF * physical eraseblocks maximum. @@ -616,84 +623,62 @@ static int io_init(struct ubi_device *ubi) } /** - * attach_mtd_dev - attach an MTD device. - * @mtd_dev: MTD device name or number string + * ubi_attach_mtd_dev - attach an MTD device. + * @mtd_dev: MTD device description object * @vid_hdr_offset: VID header offset * @data_offset: data offset * * This function attaches an MTD device to UBI. It first treats @mtd_dev as the * MTD device name, and tries to open it by this name. If it is unable to open, * it tries to convert @mtd_dev to an integer and open the MTD device by its - * number. Returns zero in case of success and a negative error code in case of - * failure. + * number. Returns new UBI device's number in case of success and a negative + * error code in case of failure. + * + * Note, the invocations of this function has to be serialized by the + * @ubi_devices_mutex. */ -static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, - int data_offset) +int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset, + int data_offset) { struct ubi_device *ubi; - struct mtd_info *mtd; int i, err; - mtd = get_mtd_device_nm(mtd_dev); - if (IS_ERR(mtd)) { - int mtd_num; - char *endp; - - if (PTR_ERR(mtd) != -ENODEV) - return PTR_ERR(mtd); - - /* - * Probably this is not MTD device name but MTD device number - - * check this out. - */ - mtd_num = simple_strtoul(mtd_dev, &endp, 0); - if (*endp != '\0' || mtd_dev == endp) { - ubi_err("incorrect MTD device: \"%s\"", mtd_dev); - return -ENODEV; - } - - mtd = get_mtd_device(NULL, mtd_num); - if (IS_ERR(mtd)) - return PTR_ERR(mtd); - } - - /* Check if we already have the same MTD device attached */ + /* + * Check if we already have the same MTD device attached. + * + * Note, this function assumes that UBI devices creations and deletions + * are serialized, so it does not take the &ubi_devices_lock. + */ for (i = 0; i < UBI_MAX_DEVICES; i++) ubi = ubi_devices[i]; - if (ubi && ubi->mtd->index == mtd->index) { + if (ubi && mtd->index == ubi->mtd->index) { ubi_err("mtd%d is already attached to ubi%d", mtd->index, i); - err = -EINVAL; - goto out_mtd; + return -EINVAL; } - ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); - if (!ubi) { - err = -ENOMEM; - goto out_mtd; - } - - ubi->mtd = mtd; - /* Search for an empty slot in the @ubi_devices array */ - ubi->ubi_num = -1; for (i = 0; i < UBI_MAX_DEVICES; i++) - if (!ubi_devices[i]) { - ubi->ubi_num = i; + if (!ubi_devices[i]) break; - } - if (ubi->ubi_num == -1) { + if (i == UBI_MAX_DEVICES) { ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); - err = -ENFILE; - goto out_free; + return -ENFILE; } - dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", - ubi->mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); + ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); + if (!ubi) + return -ENOMEM; + ubi->mtd = mtd; + ubi->ubi_num = i; ubi->vid_hdr_offset = vid_hdr_offset; ubi->leb_start = data_offset; + + dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", + mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); + err = io_init(ubi); if (err) goto out_free; @@ -724,8 +709,16 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, if (err) goto out_detach; - ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi->ubi_num); - ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); + ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); + if (IS_ERR(ubi->bgt_thread)) { + err = PTR_ERR(ubi->bgt_thread); + ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, + err); + goto out_uif; + } + + ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num); + ubi_msg("MTD device name: \"%s\"", mtd->name); ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); ubi_msg("physical eraseblock size: %d bytes (%d KiB)", ubi->peb_size, ubi->peb_size >> 10); @@ -754,8 +747,10 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, } ubi_devices[ubi->ubi_num] = ubi; - return 0; + return ubi->ubi_num; +out_uif: + uif_close(ubi); out_detach: ubi_eba_close(ubi); ubi_wl_close(ubi); @@ -767,21 +762,57 @@ out_free: vfree(ubi->dbg_peb_buf); #endif kfree(ubi); -out_mtd: - put_mtd_device(mtd); return err; } /** - * detach_mtd_dev - detach an MTD device. - * @ubi: UBI device description object + * 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 + * + * 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 + * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not + * exist. + * + * Note, the invocations of this function has to be serialized by the + * @ubi_devices_mutex. */ -static void detach_mtd_dev(struct ubi_device *ubi) +int ubi_detach_mtd_dev(int ubi_num, int anyway) { - int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; + struct ubi_device *ubi; + + if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) + return -EINVAL; + + spin_lock(&ubi_devices_lock); + ubi = ubi_devices[ubi_num]; + if (!ubi) { + spin_lock(&ubi_devices_lock); + return -EINVAL; + } + + if (ubi->ref_count) { + if (!anyway) { + spin_lock(&ubi_devices_lock); + return -EBUSY; + } + /* This may only happen if there is a bug */ + ubi_err("%s reference count %d, destroy anyway", + ubi->ubi_name, ubi->ref_count); + } + ubi_devices[ubi->ubi_num] = NULL; + spin_unlock(&ubi_devices_lock); + + dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num); + + /* + * Before freeing anything, we have to stop the background thread to + * prevent it from doing anything on this device while we are freeing. + */ + if (ubi->bgt_thread) + kthread_stop(ubi->bgt_thread); - dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); - ubi_assert(ubi->ref_count == 0); uif_close(ubi); ubi_eba_close(ubi); ubi_wl_close(ubi); @@ -792,9 +823,9 @@ static void detach_mtd_dev(struct ubi_device *ubi) #ifdef CONFIG_MTD_UBI_DEBUG vfree(ubi->dbg_peb_buf); #endif - kfree(ubi_devices[ubi_num]); - ubi_devices[ubi_num] = NULL; - ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); + ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); + kfree(ubi); + return 0; } /** @@ -811,6 +842,46 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) init_rwsem(&le->mutex); } +/** + * find_mtd_device - open an MTD device by its name or number. + * @mtd_dev: name or number of the device + * + * This function tries to open and MTD device with name @mtd_dev, and if it + * fails, then it tries to interpret the @mtd_dev string as an ASCII-coded + * integer and open an MTD device with this number. Returns MTD device + * description object in case of success and a negative error code in case of + * failure. + */ +static struct mtd_info * __init open_mtd_device(const char *mtd_dev) +{ + struct mtd_info *mtd; + + mtd = get_mtd_device_nm(mtd_dev); + if (IS_ERR(mtd)) { + int mtd_num; + char *endp; + + if (PTR_ERR(mtd) != -ENODEV) + return mtd; + + /* + * Probably this is not MTD device name but MTD device number - + * check this out. + */ + mtd_num = simple_strtoul(mtd_dev, &endp, 0); + if (*endp != '\0' || mtd_dev == endp) { + ubi_err("incorrect MTD device: \"%s\"", mtd_dev); + return ERR_PTR(-ENODEV); + } + + mtd = get_mtd_device(NULL, mtd_num); + if (IS_ERR(mtd)) + return mtd; + } + + return mtd; +} + static int __init ubi_init(void) { int err, i, k; @@ -860,10 +931,21 @@ static int __init ubi_init(void) /* Attach MTD devices */ for (i = 0; i < mtd_devs; i++) { struct mtd_dev_param *p = &mtd_dev_param[i]; + struct mtd_info *mtd; cond_resched(); - err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); - if (err) { + + mtd = open_mtd_device(p->name); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + goto out_detach; + } + + mutex_lock(&ubi_devices_mutex); + err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs, p->data_offs); + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + put_mtd_device(mtd); printk(KERN_ERR "UBI error: cannot attach %s\n", p->name); goto out_detach; @@ -874,7 +956,11 @@ static int __init ubi_init(void) out_detach: for (k = 0; k < i; k++) - detach_mtd_dev(ubi_devices[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); + } kmem_cache_destroy(ubi_wl_entry_slab); out_ltree: kmem_cache_destroy(ubi_ltree_slab); @@ -895,8 +981,11 @@ static void __exit ubi_exit(void) int i; for (i = 0; i < UBI_MAX_DEVICES; i++) - if (ubi_devices[i]) - detach_mtd_dev(ubi_devices[i]); + if (ubi_devices[i]) { + mutex_lock(&ubi_devices_mutex); + ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1); + mutex_unlock(&ubi_devices_mutex); + } kmem_cache_destroy(ubi_wl_entry_slab); kmem_cache_destroy(ubi_ltree_slab); misc_deregister(&ubi_ctrl_cdev); -- cgit v1.2.3 From dd38fccfbc77e12417512c38508a5283ea79a375 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 19 Dec 2007 21:43:32 +0200 Subject: UBI: remove data_offset 'data_offset' parameter does not really make sense and it is not needed. Get rid of it. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 071454376643..403c10a668bd 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -50,13 +50,11 @@ * struct mtd_dev_param - MTD device parameter description data structure. * @name: MTD device name or number string * @vid_hdr_offs: VID header offset - * @data_offs: data offset */ struct mtd_dev_param { char name[MTD_PARAM_LEN_MAX]; int vid_hdr_offs; - int data_offs; }; /* Numbers of elements set in the @mtd_dev_param array */ @@ -512,7 +510,7 @@ static int io_init(struct ubi_device *ubi) return -EINVAL; } - if (ubi->vid_hdr_offset < 0 || ubi->leb_start < ubi->vid_hdr_offset) + if (ubi->vid_hdr_offset < 0) return -EINVAL; /* @@ -562,10 +560,8 @@ static int io_init(struct ubi_device *ubi) } /* Similar for the data offset */ - if (ubi->leb_start == 0) { - ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; - ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); - } + ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; + ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); @@ -626,7 +622,6 @@ static int io_init(struct ubi_device *ubi) * ubi_attach_mtd_dev - attach an MTD device. * @mtd_dev: MTD device description object * @vid_hdr_offset: VID header offset - * @data_offset: data offset * * This function attaches an MTD device to UBI. It first treats @mtd_dev as the * MTD device name, and tries to open it by this name. If it is unable to open, @@ -637,8 +632,7 @@ static int io_init(struct ubi_device *ubi) * Note, the invocations of this function has to be serialized by the * @ubi_devices_mutex. */ -int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset, - int data_offset) +int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) { struct ubi_device *ubi; int i, err; @@ -674,10 +668,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset, ubi->mtd = mtd; ubi->ubi_num = i; ubi->vid_hdr_offset = vid_hdr_offset; - ubi->leb_start = data_offset; - dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", - mtd->index, ubi->ubi_num, vid_hdr_offset, data_offset); + dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", + mtd->index, ubi->ubi_num, vid_hdr_offset); err = io_init(ubi); if (err) @@ -942,7 +935,7 @@ static int __init ubi_init(void) } mutex_lock(&ubi_devices_mutex); - err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs, p->data_offs); + err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs); mutex_unlock(&ubi_devices_mutex); if (err < 0) { put_mtd_device(mtd); @@ -1094,13 +1087,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) if (tokens[1]) p->vid_hdr_offs = bytes_str_to_int(tokens[1]); - if (tokens[2]) - p->data_offs = bytes_str_to_int(tokens[2]); if (p->vid_hdr_offs < 0) return p->vid_hdr_offs; - if (p->data_offs < 0) - return p->data_offs; mtd_devs += 1; return 0; @@ -1108,16 +1097,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " - "mtd=[,,]. " + "mtd=[,].\n" "Multiple \"mtd\" parameters may be specified.\n" - "MTD devices may be specified by their number or name. " - "Optional \"vid_hdr_offs\" and \"data_offs\" parameters " - "specify UBI VID header position and data starting " - "position to be used by UBI.\n" - "Example: mtd=content,1984,2048 mtd=4 - attach MTD device" - "with name content using VID header offset 1984 and data " - "start 2048, and MTD device number 4 using default " - "offsets"); + "MTD devices may be specified by their number or name.\n" + "Optional \"vid_hdr_offs\" parameter specifies UBI VID " + "header position and data starting position to be used " + "by UBI.\n" + "Example: mtd=content,1984 mtd=4 - attach MTD device" + "with name \"content\" using VID header offset 1984, and " + "MTD device number 4 with default VID header offset."); MODULE_VERSION(__stringify(UBI_VERSION)); MODULE_DESCRIPTION("UBI - Unsorted Block Images"); -- cgit v1.2.3 From 897a316c9e6f7fea6f1d3759797b75c0ebaec479 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 18 Dec 2007 18:23:39 +0200 Subject: UBI: handle attach ioctl Actually implement the MTD device attach/detach handlers. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 80 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 26 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 403c10a668bd..70c0b9a9e6e3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -621,18 +621,19 @@ static int io_init(struct ubi_device *ubi) /** * ubi_attach_mtd_dev - attach an MTD device. * @mtd_dev: MTD device description object + * @ubi_num: number to assign to the new UBI device * @vid_hdr_offset: VID header offset * - * This function attaches an MTD device to UBI. It first treats @mtd_dev as the - * MTD device name, and tries to open it by this name. If it is unable to open, - * it tries to convert @mtd_dev to an integer and open the MTD device by its - * number. Returns new UBI device's number in case of success and a negative - * error code in case of failure. + * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number + * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in + * which case this function finds a vacant device nubert and assings it + * automatically. Returns the new UBI device number in case of success and a + * negative error code in case of failure. * * Note, the invocations of this function has to be serialized by the * @ubi_devices_mutex. */ -int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) { struct ubi_device *ubi; int i, err; @@ -643,22 +644,47 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) * Note, this function assumes that UBI devices creations and deletions * are serialized, so it does not take the &ubi_devices_lock. */ - for (i = 0; i < UBI_MAX_DEVICES; i++) + for (i = 0; i < UBI_MAX_DEVICES; i++) { ubi = ubi_devices[i]; if (ubi && mtd->index == ubi->mtd->index) { - ubi_err("mtd%d is already attached to ubi%d", + dbg_err("mtd%d is already attached to ubi%d", mtd->index, i); - return -EINVAL; + return -EEXIST; } + } - /* Search for an empty slot in the @ubi_devices array */ - for (i = 0; i < UBI_MAX_DEVICES; i++) - if (!ubi_devices[i]) - break; + /* + * Make sure this MTD device is not emulated on top of an UBI volume + * already. Well, generally this recursion works fine, but there are + * different problems like the UBI module takes a reference to itself + * by attaching (and thus, opening) the emulated MTD device. This + * results in inability to unload the module. And in general it makes + * no sense to attach emulated MTD devices, so we prohibit this. + */ + if (mtd->type == MTD_UBIVOLUME) { + ubi_err("refuse attaching mtd%d - it is already emulated on " + "top of UBI", mtd->index); + return -EINVAL; + } + + if (ubi_num == UBI_DEV_NUM_AUTO) { + /* Search for an empty slot in the @ubi_devices array */ + for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) + if (!ubi_devices[ubi_num]) + break; + if (ubi_num == UBI_MAX_DEVICES) { + dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); + return -ENFILE; + } + } else { + if (ubi_num >= UBI_MAX_DEVICES) + return -EINVAL; - if (i == UBI_MAX_DEVICES) { - ubi_err("only %d UBI devices may be created", UBI_MAX_DEVICES); - return -ENFILE; + /* Make sure ubi_num is not busy */ + if (ubi_devices[ubi_num]) { + dbg_err("ubi%d already exists", ubi_num); + return -EEXIST; + } } ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); @@ -666,11 +692,11 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) return -ENOMEM; ubi->mtd = mtd; - ubi->ubi_num = i; + ubi->ubi_num = ubi_num; ubi->vid_hdr_offset = vid_hdr_offset; dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", - mtd->index, ubi->ubi_num, vid_hdr_offset); + mtd->index, ubi_num, vid_hdr_offset); err = io_init(ubi); if (err) @@ -710,7 +736,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) goto out_uif; } - ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi->ubi_num); + ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); ubi_msg("MTD device name: \"%s\"", mtd->name); ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); ubi_msg("physical eraseblock size: %d bytes (%d KiB)", @@ -739,8 +765,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int vid_hdr_offset) wake_up_process(ubi->bgt_thread); } - ubi_devices[ubi->ubi_num] = ubi; - return ubi->ubi_num; + ubi_devices[ubi_num] = ubi; + return ubi_num; out_uif: uif_close(ubi); @@ -781,23 +807,24 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) spin_lock(&ubi_devices_lock); ubi = ubi_devices[ubi_num]; if (!ubi) { - spin_lock(&ubi_devices_lock); + spin_unlock(&ubi_devices_lock); return -EINVAL; } if (ubi->ref_count) { if (!anyway) { - spin_lock(&ubi_devices_lock); + spin_unlock(&ubi_devices_lock); return -EBUSY; } /* This may only happen if there is a bug */ ubi_err("%s reference count %d, destroy anyway", ubi->ubi_name, ubi->ref_count); } - ubi_devices[ubi->ubi_num] = NULL; + ubi_devices[ubi_num] = NULL; spin_unlock(&ubi_devices_lock); - dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi->ubi_num); + ubi_assert(ubi_num == ubi->ubi_num); + dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); /* * Before freeing anything, we have to stop the background thread to @@ -935,7 +962,8 @@ static int __init ubi_init(void) } mutex_lock(&ubi_devices_mutex); - err = ubi_attach_mtd_dev(mtd, p->vid_hdr_offs); + err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, + p->vid_hdr_offs); mutex_unlock(&ubi_devices_mutex); if (err < 0) { put_mtd_device(mtd); -- cgit v1.2.3 From 783b273afab43437dca731a229d53d72faf77fd3 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 25 Dec 2007 18:13:33 +0200 Subject: UBI: use separate mutex for volumes checking Introduce a separate mutex which serializes volumes checking, because we cammot really use volumes_mutex - it cases reverse locking problems with mtd_tbl_mutex when gluebi is used - thanks to lockdep. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 70c0b9a9e6e3..6ac133994f94 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -703,6 +703,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) goto out_free; mutex_init(&ubi->buf_mutex); + mutex_init(&ubi->ckvol_mutex); ubi->peb_buf1 = vmalloc(ubi->peb_size); if (!ubi->peb_buf1) goto out_free; -- cgit v1.2.3 From d1f3dd6cc00f5bf744118fb2820ecdf09a1f4b73 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 25 Dec 2007 19:17:00 +0200 Subject: UBI: fix mtd device string parsing UBI allows to specify MTD device name or number when the module is being loaded. When parsing MTD device identity string, it first tries to treat it as device NAME, and if that fails, it treats it as device number. Make it vice-versa as this is more logical and makes less troubles when you have an MTD device named "1" and try to load mtd1 which has different name. This is especially easy to hit when gluebi is enabled. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6ac133994f94..0ed8105f9c11 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -867,38 +867,26 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) * find_mtd_device - open an MTD device by its name or number. * @mtd_dev: name or number of the device * - * This function tries to open and MTD device with name @mtd_dev, and if it - * fails, then it tries to interpret the @mtd_dev string as an ASCII-coded - * integer and open an MTD device with this number. Returns MTD device - * description object in case of success and a negative error code in case of - * failure. + * This function tries to open and MTD device described by @mtd_dev string, + * which is first treated as an ASCII number, and if it is not true, it is + * treated as MTD device name. Returns MTD device description object in case of + * success and a negative error code in case of failure. */ static struct mtd_info * __init open_mtd_device(const char *mtd_dev) { struct mtd_info *mtd; + int mtd_num; + char *endp; - mtd = get_mtd_device_nm(mtd_dev); - if (IS_ERR(mtd)) { - int mtd_num; - char *endp; - - if (PTR_ERR(mtd) != -ENODEV) - return mtd; - + mtd_num = simple_strtoul(mtd_dev, &endp, 0); + if (*endp != '\0' || mtd_dev == endp) { /* - * Probably this is not MTD device name but MTD device number - - * check this out. + * This does not look like an ASCII integer, probably this is + * MTD device name. */ - mtd_num = simple_strtoul(mtd_dev, &endp, 0); - if (*endp != '\0' || mtd_dev == endp) { - ubi_err("incorrect MTD device: \"%s\"", mtd_dev); - return ERR_PTR(-ENODEV); - } - + mtd = get_mtd_device_nm(mtd_dev); + } else mtd = get_mtd_device(NULL, mtd_num); - if (IS_ERR(mtd)) - return mtd; - } return mtd; } -- cgit v1.2.3 From b6b76ba466bbd47397efad0fdaeaa5ebf7d462c7 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 26 Dec 2007 13:46:46 +0200 Subject: UBI: add mtd_num sysfs attribute Expose number or the underlying MTD device in sysfs. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 0ed8105f9c11..5098e6d57092 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -122,6 +122,8 @@ static struct device_attribute dev_min_io_size = __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_bgt_enabled = __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_mtd_num = + __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); /** * ubi_get_device - get UBI device. @@ -257,8 +259,10 @@ static ssize_t dev_attribute_show(struct device *dev, ret = sprintf(buf, "%d\n", ubi->min_io_size); else if (attr == &dev_bgt_enabled) ret = sprintf(buf, "%d\n", ubi->thread_enabled); + else if (attr == &dev_mtd_num) + ret = sprintf(buf, "%d\n", ubi->mtd->index); else - BUG(); + ret = -EINVAL; ubi_put_device(ubi); return ret; @@ -314,6 +318,9 @@ static int ubi_sysfs_init(struct ubi_device *ubi) if (err) return err; err = device_create_file(&ubi->dev, &dev_bgt_enabled); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_mtd_num); return err; } @@ -323,6 +330,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi) */ static void ubi_sysfs_close(struct ubi_device *ubi) { + device_remove_file(&ubi->dev, &dev_mtd_num); device_remove_file(&ubi->dev, &dev_bgt_enabled); device_remove_file(&ubi->dev, &dev_min_io_size); device_remove_file(&ubi->dev, &dev_max_vol_count); -- cgit v1.2.3 From aeddb87718823fb81b896155b34d1bb4c8cae874 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 26 Dec 2007 14:25:58 +0200 Subject: UBI: do not support kiB Be strict and accept only KiB, MiB and GiB, not Kib, not kib, etc. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5098e6d57092..b967191cc97e 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1038,10 +1038,8 @@ static int __init bytes_str_to_int(const char *str) case 'M': result *= 1024; case 'K': - case 'k': result *= 1024; - if (endp[1] == 'i' && (endp[2] == '\0' || - endp[2] == 'B' || endp[2] == 'b')) + if (endp[1] == 'i' && endp[2] == 'B') endp += 2; case '\0': break; -- cgit v1.2.3 From 4b3cc340614e552c476bec29d984c5a363b26494 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 26 Dec 2007 15:59:39 +0200 Subject: UBI: bugfix: do not forget to increment vol_count When creating a new volume, do not forget to increment the vol_count variable. Also, users are not interested in internal volumes, so do not show them in the volumes_count sysfs file. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index b967191cc97e..8f1f9feb2d60 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -246,7 +246,7 @@ static ssize_t dev_attribute_show(struct device *dev, else if (attr == &dev_total_eraseblocks) ret = sprintf(buf, "%d\n", ubi->good_peb_count); else if (attr == &dev_volumes_count) - ret = sprintf(buf, "%d\n", ubi->vol_count); + ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); else if (attr == &dev_max_ec) ret = sprintf(buf, "%d\n", ubi->max_ec); else if (attr == &dev_reserved_for_bad) -- cgit v1.2.3 From b9a06623d9d0c6dff758d525ceb0d9e2bba8f7d6 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 12:11:54 +0200 Subject: UBI: get rid of ubi_ltree_slab This slab cache is not really needed since the number of objects is low and the constructor does not make much sense because we allocate oblects when doint I/O, which is way slower then allocation. Suggested-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8f1f9feb2d60..8b4573559dfe 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -66,9 +66,6 @@ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; /* Root UBI "class" object (corresponds to '//class/ubi/') */ struct class *ubi_class; -/* Slab cache for lock-tree entries */ -struct kmem_cache *ubi_ltree_slab; - /* Slab cache for wear-leveling entries */ struct kmem_cache *ubi_wl_entry_slab; @@ -857,20 +854,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) return 0; } -/** - * ltree_entry_ctor - lock tree entries slab cache constructor. - * @obj: the lock-tree entry to construct - * @cache: the lock tree entry slab cache - * @flags: constructor flags - */ -static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) -{ - struct ubi_ltree_entry *le = obj; - - le->users = 0; - init_rwsem(&le->mutex); -} - /** * find_mtd_device - open an MTD device by its name or number. * @mtd_dev: name or number of the device @@ -933,17 +916,11 @@ static int __init ubi_init(void) goto out_version; } - ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab", - sizeof(struct ubi_ltree_entry), 0, - 0, <ree_entry_ctor); - if (!ubi_ltree_slab) - goto out_dev_unreg; - ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", sizeof(struct ubi_wl_entry), 0, 0, NULL); if (!ubi_wl_entry_slab) - goto out_ltree; + goto out_dev_unreg; /* Attach MTD devices */ for (i = 0; i < mtd_devs; i++) { @@ -980,8 +957,6 @@ out_detach: mutex_unlock(&ubi_devices_mutex); } kmem_cache_destroy(ubi_wl_entry_slab); -out_ltree: - kmem_cache_destroy(ubi_ltree_slab); out_dev_unreg: misc_deregister(&ubi_ctrl_cdev); out_version: @@ -1005,7 +980,6 @@ static void __exit ubi_exit(void) mutex_unlock(&ubi_devices_mutex); } kmem_cache_destroy(ubi_wl_entry_slab); - kmem_cache_destroy(ubi_ltree_slab); misc_deregister(&ubi_ctrl_cdev); class_remove_file(ubi_class, &ubi_version); class_destroy(ubi_class); -- cgit v1.2.3 From 4ccf8cffa963c7b5bdc6d455ea9417084ee49aa8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 16 Jan 2008 15:44:24 +0200 Subject: UBI: add auto-resize feature The problem: NAND flashes have different amount of initial bad physical eraseblocks (marked as bad by the manufacturer). For example, for 256MiB Samsung OneNAND flash there might be from 0 to 40 bad initial eraseblocks, which is about 2%. When UBI is used as the base system, one needs to know the exact amount of good physical eraseblocks, because this number is needed to create the UBI image which is put to the devices during production. But this number is not know, which forces us to use the minimum number of good physical eraseblocks. And UBI additionally reserves some percentage of physical eraseblocks for bad block handling (default is 1%), so we have 1-3% of PEBs reserved at the end, depending on the amount of initial bad PEBs. But it is desired to always have 1% (or more, depending on the configuration). Solution: this patch adds an "auto-resize" flag to the volume table. The volume which has the "auto-resize" flag will automatically be re-sized (enlarged) on the first UBI initialization. UBI clears the flag when the volume is re-sized. Only one volume may have the "auto-resize" flag. So, the production UBI image may have one volume with "auto-resize" flag set, and its size is automatically adjusted on the first boot of the device. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 69 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8b4573559dfe..4e761e957de8 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -366,9 +366,6 @@ static int uif_init(struct ubi_device *ubi) int i, err; dev_t dev; - mutex_init(&ubi->volumes_mutex); - spin_lock_init(&ubi->volumes_lock); - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); /* @@ -623,6 +620,58 @@ static int io_init(struct ubi_device *ubi) return 0; } +/** + * autoresize - re-size the volume which has the "auto-resize" flag set. + * @ubi: UBI device description object + * @vol_id: ID of the volume to re-size + * + * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in + * the volume table to the largest possible size. See comments in ubi-header.h + * for more description of the flag. Returns zero in case of success and a + * negative error code in case of failure. + */ +static int autoresize(struct ubi_device *ubi, int vol_id) +{ + struct ubi_volume_desc desc; + struct ubi_volume *vol = ubi->volumes[vol_id]; + int err, old_reserved_pebs = vol->reserved_pebs; + + /* + * Clear the auto-resize flag in the volume in-memory copy of the + * volume table, and 'ubi_resize_volume()' will propogate this change + * to the flash. + */ + ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; + + if (ubi->avail_pebs == 0) { + struct ubi_vtbl_record vtbl_rec; + + /* + * No avalilable PEBs to re-size the volume, clear the flag on + * flash and exit. + */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], + sizeof(struct ubi_vtbl_record)); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + ubi_err("cannot clean auto-resize flag for volume %d", + vol_id); + } else { + desc.vol = vol; + err = ubi_resize_volume(&desc, + old_reserved_pebs + ubi->avail_pebs); + if (err) + ubi_err("cannot auto-resize volume %d", vol_id); + } + + if (err) + return err; + + ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + vol->name, old_reserved_pebs, vol->reserved_pebs); + return 0; +} + /** * ubi_attach_mtd_dev - attach an MTD device. * @mtd_dev: MTD device description object @@ -699,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi->mtd = mtd; ubi->ubi_num = ubi_num; ubi->vid_hdr_offset = vid_hdr_offset; + ubi->autoresize_vol_id = -1; + + mutex_init(&ubi->buf_mutex); + mutex_init(&ubi->ckvol_mutex); + mutex_init(&ubi->volumes_mutex); + spin_lock_init(&ubi->volumes_lock); dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", mtd->index, ubi_num, vid_hdr_offset); @@ -707,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) if (err) goto out_free; - mutex_init(&ubi->buf_mutex); - mutex_init(&ubi->ckvol_mutex); ubi->peb_buf1 = vmalloc(ubi->peb_size); if (!ubi->peb_buf1) goto out_free; @@ -730,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) goto out_free; } + if (ubi->autoresize_vol_id != -1) { + err = autoresize(ubi, ubi->autoresize_vol_id); + if (err) + goto out_detach; + } + err = uif_init(ubi); if (err) goto out_detach; -- cgit v1.2.3 From ddc4939161c502452392b353f9e0dd088239e4c1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 17 Jan 2008 15:35:57 +0200 Subject: UBI: amend array size Since the data offset parameter was removed, the size of the parameters array is now 2, not 3. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4e761e957de8..51bff88342af 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1099,7 +1099,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) struct mtd_dev_param *p; char buf[MTD_PARAM_LEN_MAX]; char *pbuf = &buf[0]; - char *tokens[3] = {NULL, NULL, NULL}; + char *tokens[2] = {NULL, NULL}; if (!val) return -EINVAL; @@ -1129,7 +1129,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) if (buf[len - 1] == '\n') buf[len - 1] = '\0'; - for (i = 0; i < 3; i++) + for (i = 0; i < 2; i++) tokens[i] = strsep(&pbuf, ","); if (pbuf) { -- cgit v1.2.3 From d536058752274b2fe60135142da550b5355ffa94 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 17 Jan 2008 15:41:14 +0200 Subject: UBI: bugfix: calculate data offset properly Data offset is VID header offset + VID header size aligned to the min. I/O unit size up. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/ubi/build.c') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 51bff88342af..6ac81e35355c 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -562,7 +562,7 @@ static int io_init(struct ubi_device *ubi) } /* Similar for the data offset */ - ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; + ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); -- cgit v1.2.3