UBI: make UBI devices dynamic
Subsystems (2)
v2 cover UBI: make UBI devices dynamic
Hi,
here is the second iteration of the patch-set. Changes (were requested by Arnd):
* data_offset is removed as it makes no sens to set it to anything but the default value
* UBI control device is now registered as "misc" device, so we do not waste Linux major/minor numbers
* More commentaries in the ubi-user.h file
The ltree slab cache is not removed, it will be done separately.
The original message
~~~~~~~~~~~~~~~~~~~~
here is a patch-set which makes UBI devices dynamic. This means, that you may attach/detach MTD devices run-time, not just when UBI module is loaded/unloaded. This is very convenient - you do may compile UBI into the kernel and attach/detach needed MTD devices later, when your init scripts (loaded from initrd) decide which exactly MTD device(s) to attach. This also makes testing a lot easier.
The idea is similar to what the device mapper has: UBI creates an UBI control device, which registers itself in UBI sysfs hierarchy (/sys/class/ubi/ubi_ctrl) with dynamically allocated major and minor numbers. The control device has 2 ioctls - attach MTD device and detach MTD device.
This patch-set applies on top of my other UBI changes and fixes, which you may find in the UBI git.
I CC Frank and Andreas, as one of the main UBI users. I CC Arnd as an ioctl expert.
--
Best regards,
Artem Bityutskiy (Битюцкий Артём)
PATCH v2 1/6 UBI: add UBI control device
Quoted 1 line
From
028997ff1dca743d538187962133ea77aefbc510Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Sun, 16 Dec 2007 16:59:31 +0200
Subject: [PATCH] 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
--- drivers/mtd/ubi/build.c | 69 ++++++++++++++++++++++++++++++++++++++++------- drivers/mtd/ubi/cdev.c | 10 +++++++ drivers/mtd/ubi/ubi.h | 3 +- 3 files changed, 71 insertions(+), 11 deletions(-)
drivers/mtd/ubi/build.c +59 -10
@@ -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 <linux/err.h>
@@ -70,6 +75,11 @@ struct kmem_cache *ubi_ltree_slab;/* Slab cache for wear-leveling entries */ struct kmem_cache *ubi_wl_entry_slab; +/* UBI control character device major number */ +static int ubi_ctrl_major; + +/* Linux device model object corresponding to the control UBI device */ +static struct device ubi_ctrl_dev;/* "Show" method for files in '/<sysfs>/class/ubi/' */ static ssize_t ubi_version_show (struct class *class,char *buf)
@@ -142,6 +152,9 @@ static ssize_t dev_attribute_show(struct device *dev,/* Fake "release" method for UBI devices */ static void dev_release (struct device *dev) { } +/* Fake "release" method for UBI control device */ +static void ctrl_dev_release (struct device *dev) { } +/** * ubi_sysfs_init - initialize sysfs for an UBI device. * @ubi: UBI device description object
@@ -701,19 +714,45 @@ static int __init ubi_init(void)return -EINVAL ; } +/* Allocate major number for the UBI control device and register it */ + ubi_ctrl_major =register_chrdev (0 ,"ubi_ctrl" , + &ubi_ctrl_cdev_operations); +if (ubi_ctrl_major <0 ) { + err = ubi_ctrl_major; +printk (KERN_ERR "UBI error: cannot register control device\n" ); +return err; + } + +/* 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_cdev_unreg; + } 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; + } + +/* Register the control device in the Linux device system */ + ubi_ctrl_dev.release = ctrl_dev_release; + ubi_ctrl_dev.devt =MKDEV (ubi_ctrl_major,0 ); + ubi_ctrl_dev.class = ubi_class; +sprintf (&ubi_ctrl_dev.bus_id[0 ],"ubi_ctrl" ); + err =device_register (&ubi_ctrl_dev); +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 +766,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 +781,15 @@ out_detach:kmem_cache_destroy (ubi_wl_entry_slab); out_ltree:kmem_cache_destroy (ubi_ltree_slab); +out_dev_unreg: +device_unregister (&ubi_ctrl_dev); out_version:class_remove_file (ubi_class, &ubi_version); out_class:class_destroy (ubi_class); +out_cdev_unreg: +unregister_chrdev (ubi_ctrl_major,"ubi_ctrl" ); +printk (KERN_ERR "UBI error: cannot initialize UBI, error %d\n" , err);return err; }module_init (ubi_init);
@@ -756,8 +803,10 @@ 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); +device_unregister (&ubi_ctrl_dev);class_remove_file (ubi_class, &ubi_version);class_destroy (ubi_class); +unregister_chrdev (ubi_ctrl_major,"ubi_ctrl" ); }module_exit (ubi_exit);
drivers/mtd/ubi/cdev.c +10 -0
@@ -28,6 +28,11 @@* * Major and minor numbers are assigned dynamically to both UBI and volume * character devices. +* +* Well, there is the third kind of character devices - the UBI control +* character device, which allows to manipulate by UBI devices - create and +* delete them. In other words, it is used for attaching and detaching MTD +* devices. */ #include <linux/module.h>
@@ -693,6 +698,11 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,return err; } +/* UBI control character device operations */ +struct file_operations ubi_ctrl_cdev_operations = { + .owner =THIS_MODULE , +}; +/* UBI character device operations */ struct file_operations ubi_cdev_operations = { .owner =THIS_MODULE ,
drivers/mtd/ubi/ubi.h +2 -1
@@ -235,7 +235,7 @@ struct ubi_wl_entry;/** * struct ubi_device - UBI device description structure -* @dev: class device object to use the the Linux device model +* @dev: UBI device object to use the the Linux device model * @cdev: character device object to create character device * @ubi_num: UBI device number * @ubi_name: UBI device name
@@ -398,6 +398,7 @@ struct ubi_device {extern struct kmem_cache *ubi_ltree_slab;extern struct kmem_cache *ubi_wl_entry_slab; +extern struct file_operations ubi_ctrl_cdev_operations;extern struct file_operations ubi_cdev_operations;extern struct file_operations ubi_vol_cdev_operations;extern struct ubi_device *ubi_devices[];
Signature · 1 line
1.5.3.4
PATCH v2 2/6 UBI: add UBI devices reference counting
In reply to Artem BityutskiyQuoted 1 line
From
502c3f72aacff2056497bbbdb219459914a28a7fMon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Mon, 17 Dec 2007 17:37:26 +0200
Subject: [PATCH] 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.
--- drivers/mtd/ubi/build.c | 142 ++++++++++++++++++++++++++++++++++++++++++----- drivers/mtd/ubi/cdev.c | 34 +++-------- drivers/mtd/ubi/eba.c | 5 ++ drivers/mtd/ubi/kapi.c | 59 ++++++++++++++------ drivers/mtd/ubi/ubi.h | 9 +++- drivers/mtd/ubi/vmt.c | 14 +++-- drivers/mtd/ubi/wl.c | 1 + 7 files changed, 201 insertions(+), 63 deletions(-)
drivers/mtd/ubi/build.c +127 -15
@@ -63,9 +63,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 '/<sysfs>/class/ubi/') */ struct class *ubi_class;
@@ -81,6 +78,12 @@ static int ubi_ctrl_major;/* Linux device model object corresponding to the control UBI device */ static struct device ubi_ctrl_dev; +/* 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 '/<sysfs>/class/ubi/' */ static ssize_t ubi_version_show (struct class *class,char *buf) {
@@ -116,37 +119,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 '/<sysfs>/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 */
@@ -671,6 +782,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);
drivers/mtd/ubi/cdev.c +10 -24
@@ -56,23 +56,6 @@#endif /** -* major_to_device - get UBI device object by character device major number. -* @major: major number -* -* This function returns a pointer to the UBI device object. -*/ -static struct ubi_device *major_to_device (int major) -{ -int i; - -for (i =0 ; i <UBI_MAX_DEVICES ; i++) -if (ubi_devices[i] &&MAJOR (ubi_devices[i]->cdev.dev) == major) -return ubi_devices[i]; -BUG (); -return NULL ; -} - -/** * get_exclusive - get exclusive access to an UBI volume. * @desc: volume descriptor *
@@ -129,9 +112,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)static int vol_cdev_open (struct inode *inode,struct file *file) {struct ubi_volume_desc *desc; -const struct ubi_device *ubi =major_to_device (imajor (inode)); -int vol_id =iminor (inode) -1 ; -int mode; +int vol_id =iminor (inode) -1 , mode, ubi_num; + + ubi_num =ubi_major2num (imajor (inode)); +if (ubi_num <0 ) +return ubi_num;if (file->f_mode &FMODE_WRITE ) mode =UBI_READWRITE ;
@@ -140,7 +125,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)dbg_msg ("open volume %d, mode %d" , vol_id, mode); - desc =ubi_open_volume (ubi->ubi_num, vol_id, mode); + desc =ubi_open_volume (ubi_num, vol_id, mode);if (IS_ERR (desc))return PTR_ERR (desc);
@@ -586,9 +571,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,if (!capable (CAP_SYS_RESOURCE ))return -EPERM ; - ubi =major_to_device (imajor (inode)); -if (IS_ERR (ubi)) -return PTR_ERR (ubi); + ubi =ubi_get_by_major (imajor (inode)); +if (!ubi) +return -ENODEV ;switch (cmd) {/* Create volume command */
@@ -695,6 +680,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,break ; } +ubi_put_device (ubi);return err; }
drivers/mtd/ubi/eba.c +5 -0
@@ -339,6 +339,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, {int err, pnum, vol_id = vol->vol_id; +ubi_assert (ubi->ref_count >0 );ubi_assert (vol->ref_count >0 );if (ubi->ro_mode)
@@ -389,6 +390,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,struct ubi_vid_hdr *vid_hdr;uint32_t uninitialized_var (crc ); +ubi_assert (ubi->ref_count >0 );ubi_assert (vol->ref_count >0 ); err =leb_read_lock (ubi, vol_id, lnum);
@@ -614,6 +616,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,int err, pnum, tries =0 , vol_id = vol->vol_id;struct ubi_vid_hdr *vid_hdr; +ubi_assert (ubi->ref_count >0 );ubi_assert (vol->ref_count >0 );if (ubi->ro_mode)
@@ -749,6 +752,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,struct ubi_vid_hdr *vid_hdr;uint32_t crc; +ubi_assert (ubi->ref_count >0 );ubi_assert (vol->ref_count >0 );if (ubi->ro_mode)
@@ -865,6 +869,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,struct ubi_vid_hdr *vid_hdr;uint32_t crc; +ubi_assert (ubi->ref_count >0 );ubi_assert (vol->ref_count >0 );if (ubi->ro_mode)
drivers/mtd/ubi/kapi.c +41 -18
129 lines not on this page · raw message
drivers/mtd/ubi/ubi.h +8 -1
@@ -245,6 +245,7 @@ struct ubi_wl_entry;* @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, * @vol->readers, @vol->writers, @vol->exclusive, * @vol->ref_count, @vol->mapping and @vol->eba_tbl. +* @ref_count: count of references on the UBI device * * @rsvd_pebs: count of reserved physical eraseblocks * @avail_pebs: count of available physical eraseblocks
@@ -325,6 +326,7 @@ struct ubi_device {int vol_count;struct ubi_volume *volumes[UBI_MAX_VOLUMES +UBI_INT_VOL_COUNT ];spinlock_t volumes_lock; +int ref_count;int rsvd_pebs;int avail_pebs;
@@ -401,7 +403,6 @@ extern struct kmem_cache *ubi_wl_entry_slab;extern struct file_operations ubi_ctrl_cdev_operations;extern struct file_operations ubi_cdev_operations;extern struct file_operations ubi_vol_cdev_operations; -extern struct ubi_device *ubi_devices[];extern struct class *ubi_class;/* vtbl.c */
@@ -479,6 +480,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,int ubi_io_write_vid_hdr (struct ubi_device *ubi,int pnum,struct ubi_vid_hdr *vid_hdr); +/* build.c */ +struct ubi_device *ubi_get_device (int ubi_num); +void ubi_put_device (struct ubi_device *ubi); +struct ubi_device *ubi_get_by_major (int major); +int ubi_major2num (int major); +/* * ubi_rb_for_each_entry - walk an RB-tree. * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
drivers/mtd/ubi/vmt.c +9 -5
@@ -71,11 +71,16 @@ static ssize_t vol_attribute_show(struct device *dev, {int ret; struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); -struct ubi_device *ubi = vol->ubi; +struct ubi_device *ubi; + + ubi =ubi_get_device (vol->ubi->ubi_num); +if (!ubi) +return -ENODEV ;spin_lock (&ubi->volumes_lock);if (!ubi->volumes[vol->vol_id]) {spin_unlock (&ubi->volumes_lock); +ubi_put_device (ubi);return -ENODEV ; }/* Take a reference to prevent volume removal */
@@ -108,10 +113,12 @@ static ssize_t vol_attribute_show(struct device *dev,/* This must be a bug */ ret = -EINVAL ; +/* We've done the operation, drop volume and UBI device references */ spin_lock (&ubi->volumes_lock); vol->ref_count -=1 ;ubi_assert (vol->ref_count >=0 );spin_unlock (&ubi->volumes_lock); +ubi_put_device (ubi);return ret; }
@@ -260,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) } ubi->avail_pebs -= vol->reserved_pebs; ubi->rsvd_pebs += vol->reserved_pebs; +spin_unlock (&ubi->volumes_lock); vol->vol_id = vol_id; vol->alignment = req->alignment;
@@ -267,9 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->vol_type = req->vol_type; vol->name_len = req->name_len;memcpy (vol->name, req->name, vol->name_len +1 ); - vol->exclusive =1 ; vol->ubi = ubi; -spin_unlock (&ubi->volumes_lock);/* * Finish all pending erases because there may be some LEBs belonging
@@ -350,8 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) goto out_sysfs;spin_lock (&ubi->volumes_lock); - ubi->vol_count +=1 ; - vol->exclusive =0 ; ubi->volumes[vol_id] = vol;spin_unlock (&ubi->volumes_lock);
drivers/mtd/ubi/wl.c +1 -0
@@ -1303,6 +1303,7 @@ int ubi_wl_flush(struct ubi_device *ubi)* Make sure all the works which have been done in parallel are * finished. */ +ubi_assert (ubi->ref_count >0 );down_write (&ubi->work_sem);up_write (&ubi->work_sem);
Signature · 1 line
1.5.3.4
PATCH v2 3/6 UBI: prepare attach and detach functions
In reply to Artem BityutskiyQuoted 1 line
From
9fd405794615345e2089a6cfe719988f8bf4ff9aMon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Mon, 17 Dec 2007 20:33:20 +0200
Subject: [PATCH] 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
--- drivers/mtd/ubi/build.c | 235 ++++++++++++++++++++++++++++++++--------------- drivers/mtd/ubi/ubi.h | 5 + drivers/mtd/ubi/wl.c | 16 +--- 3 files changed, 169 insertions(+), 87 deletions(-)
drivers/mtd/ubi/build.c +162 -73
@@ -39,6 +39,7 @@#include <linux/stringify.h> #include <linux/stat.h> #include <linux/log2.h> +#include <linux/kthread.h> #include "ubi.h" /* Maximum length of the 'mtd=' parameter */
@@ -81,6 +82,9 @@ static struct device ubi_ctrl_dev;/* 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);
@@ -190,7 +194,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)
@@ -486,9 +490,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.
@@ -509,6 +513,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.
@@ -617,84 +624,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;
@@ -725,8 +710,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 );
@@ -755,8 +748,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);
@@ -768,21 +763,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);
@@ -793,9 +824,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 ; }/**
@@ -812,6 +843,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;
@@ -875,10 +946,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;
@@ -889,7 +971,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);
@@ -911,8 +997,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);device_unregister (&ubi_ctrl_dev);
drivers/mtd/ubi/ubi.h +5 -0
@@ -404,6 +404,7 @@ extern struct file_operations ubi_ctrl_cdev_operations;extern struct file_operations ubi_cdev_operations;extern struct file_operations ubi_vol_cdev_operations;extern struct class *ubi_class; +extern struct mutex ubi_devices_mutex;/* vtbl.c */ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
@@ -462,6 +463,7 @@ int ubi_wl_flush(struct ubi_device *ubi);int ubi_wl_scrub_peb (struct ubi_device *ubi,int pnum);int ubi_wl_init_scan (struct ubi_device *ubi,struct ubi_scan_info *si);void ubi_wl_close (struct ubi_device *ubi); +int ubi_thread (void *u);/* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
@@ -481,6 +483,9 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr);/* build.c */ +int ubi_attach_mtd_dev (struct mtd_info *mtd,int vid_hdr_offset, +int data_offset); +int ubi_detach_mtd_dev (int ubi_num,int anyway);struct ubi_device *ubi_get_device (int ubi_num);void ubi_put_device (struct ubi_device *ubi);struct ubi_device *ubi_get_by_major (int major);
drivers/mtd/ubi/wl.c +2 -14
@@ -1356,7 +1356,7 @@ static void tree_destroy(struct rb_root *root)* ubi_thread - UBI background thread. * @u: the UBI device description object pointer */ -static int ubi_thread (void *u) +int ubi_thread (void *u) {int failures =0 ;struct ubi_device *ubi = u;
@@ -1454,18 +1454,10 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)sprintf (ubi->bgt_name,UBI_BGT_NAME_PATTERN , ubi->ubi_num); - 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); -return err; - } - err = -ENOMEM ; ubi->lookuptbl =kzalloc (ubi->peb_count *sizeof (void *),GFP_KERNEL );if (!ubi->lookuptbl) - goto out_free; +return err;list_for_each_entry_safe (seb, tmp, &si->erase, u.list) {cond_resched ();
@@ -1598,10 +1590,6 @@ static void protection_trees_destroy(struct ubi_device *ubi)*/ void ubi_wl_close (struct ubi_device *ubi) { -dbg_wl ("disable \"%s\"" , ubi->bgt_name); -if (ubi->bgt_thread) -kthread_stop (ubi->bgt_thread); -dbg_wl ("close the UBI wear-leveling unit" );cancel_pending (ubi);
Signature · 1 line
1.5.3.4
PATCH v2 4/6 UBI: UBI: remove data_offset
In reply to Artem BityutskiyQuoted 1 line
From
09610a4ca122838a1292ec919ac2d05cf499a140Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Wed, 19 Dec 2007 21:43:32 +0200
Subject: [PATCH] UBI: remove data_offset
'data_offset' parameter does not really make sense and it is not needed. Get rid of it.
--- drivers/mtd/ubi/build.c | 42 +++++++++++++++--------------------------- drivers/mtd/ubi/ubi.h | 3 +-- 2 files changed, 16 insertions(+), 29 deletions(-)
drivers/mtd/ubi/build.c +15 -27
@@ -49,13 +49,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 */
@@ -513,7 +511,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 ;/*
@@ -563,10 +561,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);
@@ -627,7 +623,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,
@@ -638,8 +633,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;
@@ -675,10 +669,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)
@@ -957,7 +950,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);
@@ -1111,13 +1104,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 ;
@@ -1125,16 +1114,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=<name|num>[,<vid_hdr_offs>,<data_offs>]. " +"mtd=<name|num>[,<vid_hdr_offs>].\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" );
drivers/mtd/ubi/ubi.h +1 -2
@@ -483,8 +483,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr);/* build.c */ -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);int ubi_detach_mtd_dev (int ubi_num,int anyway);struct ubi_device *ubi_get_device (int ubi_num);void ubi_put_device (struct ubi_device *ubi);
Signature · 1 line
1.5.3.4
PATCH v2 5/6 UBI: introduce attach ioctls
In reply to Artem BityutskiyQuoted 1 line
From
9143611137b01d56137c3b21b2b360e7e38cee9aMon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Tue, 18 Dec 2007 18:22:16 +0200
Subject: [PATCH] UBI: introduce attach ioctls
--- include/mtd/ubi-user.h | 69 ++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 64 insertions(+), 5 deletions(-)
include/mtd/ubi-user.h +64 -5
@@ -22,6 +22,21 @@#define __UBI_USER_H__/* +* UBI device creation (the same as MTD device attachment) +* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* +* MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI +* control device. The caller has to properly fill and pass +* &struct ubi_attach_req object - UBI will attach the MTD device specified in +* the request and return the newly created UBI device number as the ioctl +* return value. +* +* UBI device deletion (the same as MTD device detachment) +* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* +* An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI +* control device. +* * UBI volume creation * ~~~~~~~~~~~~~~~~~~~ *
@@ -80,6 +95,15 @@/* Re-size an UBI volume */ #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) +/* IOCTL commands of the UBI control character device */ + +#define UBI_CTRL_IOC_MAGIC 'o' + +/* Attach an MTD device */ +#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) +/* Detach an MTD device */ +#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) +/* IOCTL commands of UBI volume character devices */ #define UBI_VOL_IOC_MAGIC 'O'
@@ -89,6 +113,9 @@/* An eraseblock erasure command, used for debugging, disabled by default */ #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) +/* Maximum MTD device name length supported by UBI */ +#define MAX_UBI_MTD_NAME_LEN 127 +/* * UBI volume type constants. *
@@ -97,19 +124,51 @@*/ enum {UBI_DYNAMIC_VOLUME =3 , -UBI_STATIC_VOLUME =4 +UBI_STATIC_VOLUME =4 , +}; + +/** +* struct ubi_attach_req - attach MTD device request. +* @vid_hdr_offset: VID header offset (use defaults if %0) +* @mtd_num: MTD device number to attach +* @padding: reserved for future, not used, has to be zeroed +* +* This data structure is used to specify MTD device UBI has to attach and the +* parameters it has to use. The "attach MTD device" ioctl returns the number +* of the newly created UBI device as the return value. +* +* Most applications should pass %0 in @vid_hdr_offset to make UBI use default +* offset of the VID header within physical eraseblocks. The default offset is +* the next min. I/O unit after the EC header. For example, it will be offset +* 512 in case of a 512 bytes page NAND flash with no sub-page support. Or +* it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. +* +* But in rare cases, if this optimizes things, the VID header may be placed to +* a different offset. For example, the boot-loader might do things faster if the +* VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As +* the boot-loader would not normally need to read EC headers (unless it needs +* UBI in RW mode), it might be faster to calculate ECC. This is weird example, +* but it real-life example. So, in this example, @vid_hdr_offer would be +* 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes +* aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page +* of the first page and add needed padding. +*/ +struct ubi_attach_req { +int32_t vid_hdr_offset; +int32_t mtd_num; +uint8_t padding[12 ]; };/** * struct ubi_mkvol_req - volume description data structure used in -* volume creation requests. +* volume creation requests. * @vol_id: volume number * @alignment: volume alignment * @bytes: volume size in bytes * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -* @padding1: reserved for future, not used +* @padding1: reserved for future, not used, has to be zeroed * @name_len: volume name length -* @padding2: reserved for future, not used +* @padding2: reserved for future, not used, has to be zeroed * @name: volume name * * This structure is used by userspace programs when creating new volumes. The
@@ -139,7 +198,7 @@ struct ubi_mkvol_req {int8_t padding1;int16_t name_len;int8_t padding2[4 ]; -char name[UBI_MAX_VOLUME_NAME +1 ]; +char name[UBI_MAX_VOLUME_NAME +1 ]; } __attribute__ ((packed));/**
Signature · 1 line
1.5.3.4
PATCH v2 5/6 UBI: handle attach ioctl
In reply to Artem BityutskiyQuoted 1 line
From
f3a2178d8b632f712992d5a62f5d4b78440df527Mon Sep 17 00:00:00 2001
From: Artem Bityutskiy <[email protected]>
Date: Tue, 18 Dec 2007 18:23:39 +0200
Subject: [PATCH] UBI: handle attach ioctl
Actually implement the MTD device attach/detach handlers.
--- drivers/mtd/ubi/cdev.c | 84 +++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 69 insertions(+), 15 deletions(-)
drivers/mtd/ubi/cdev.c +69 -15
@@ -44,17 +44,6 @@#include <asm/div64.h> #include "ubi.h" -/* -* Maximum sequence numbers of UBI and volume character device IOCTLs (direct -* logical eraseblock erase is a debug-only feature). -*/ -#define UBI_CDEV_IOC_MAX_SEQ 2 -#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO -#define VOL_CDEV_IOC_MAX_SEQ 1 -#else -#define VOL_CDEV_IOC_MAX_SEQ 2 -#endif -/** * get_exclusive - get exclusive access to an UBI volume. * @desc: volume descriptor
@@ -582,8 +571,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,struct ubi_mkvol_req req;dbg_msg ("create volume" ); - err =copy_from_user (&req, argp, -sizeof (struct ubi_mkvol_req )); + err =copy_from_user (&req, argp,sizeof (struct ubi_mkvol_req ));if (err) { err = -EFAULT ;break ;
@@ -647,8 +635,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,struct ubi_rsvol_req req;dbg_msg ("re-size volume" ); - err =copy_from_user (&req, argp, -sizeof (struct ubi_rsvol_req )); + err =copy_from_user (&req, argp,sizeof (struct ubi_rsvol_req ));if (err) { err = -EFAULT ;break ;
@@ -684,8 +671,75 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,return err; } +static int ctrl_cdev_ioctl (struct inode *inode,struct file *file, +unsigned int cmd,unsigned long arg) +{ +int err =0 ; +void __user *argp = (void __user *)arg; + +if (!capable (CAP_SYS_RESOURCE )) +return -EPERM ; + +switch (cmd) { +/* Attach an MTD device command */ +case UBI_IOCATT : + { +struct ubi_attach_req req; +struct mtd_info *mtd; + +dbg_msg ("attach MTD device" ); + err =copy_from_user (&req, argp,sizeof (struct ubi_attach_req )); +if (err) { + err = -EFAULT ; +break ; + } + +if (req.mtd_num <0 ) +return -EINVAL ; + + mtd =get_mtd_device (NULL , req.mtd_num); +if (IS_ERR (mtd)) +return PTR_ERR (mtd); + +/* Note, request verification is done by the attach function */ +mutex_lock (&ubi_devices_mutex); + err =ubi_attach_mtd_dev (mtd, req.vid_hdr_offset, + req.data_offset); +mutex_unlock (&ubi_devices_mutex); +if (err <0 ) +put_mtd_device (mtd); +break ; + } + +/* Detach an MTD device command */ +case UBI_IOCDET : + { +int ubi_num; + +dbg_msg ("dettach MTD device" ); + err =get_user (ubi_num, (__user int32_t *)argp); +if (err) { + err = -EFAULT ; +break ; + } + +mutex_lock (&ubi_devices_mutex); + err =ubi_detach_mtd_dev (ubi_num,0 ); +mutex_unlock (&ubi_devices_mutex); +break ; + } + +default : + err = -ENOTTY ; +break ; + } + +return err; +} +/* UBI control character device operations */ struct file_operations ubi_ctrl_cdev_operations = { + .ioctl = ctrl_cdev_ioctl, .owner =THIS_MODULE , };
Signature · 1 line
1.5.3.4