summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/kapi.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-17 16:37:26 +0100
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-26 18:15:17 +0100
commite73f4459d969bb266f03dd4cbe21bdba8cb2732c (patch)
tree5af7655da65f2c33f6ea4efdfaa8b0e0670d6aea /drivers/mtd/ubi/kapi.c
parentUBI: add UBI control device (diff)
downloadlinux-e73f4459d969bb266f03dd4cbe21bdba8cb2732c.tar.xz
linux-e73f4459d969bb266f03dd4cbe21bdba8cb2732c.zip
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 <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/kapi.c')
-rw-r--r--drivers/mtd/ubi/kapi.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 780c273ff452..4ec3a33b2577 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -30,23 +30,27 @@
* @ubi_num: UBI device number
* @di: the information is stored here
*
- * This function returns %0 in case of success and a %-ENODEV if there is no
- * such UBI device.
+ * This function returns %0 in case of success, %-EINVAL if the UBI device
+ * number is invalid, and %-ENODEV if there is no such UBI device.
*/
int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
{
- const struct ubi_device *ubi;
+ struct ubi_device *ubi;
- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
- !ubi_devices[ubi_num])
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return -EINVAL;
+
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
return -ENODEV;
- ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num;
di->leb_size = ubi->leb_size;
di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode;
di->cdev = ubi->cdev.dev;
+
+ ubi_put_device(ubi);
return 0;
}
EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
mode != UBI_EXCLUSIVE)
return ERR_PTR(-EINVAL);
- ubi = ubi_devices[ubi_num];
+ /*
+ * First of all, we have to get the UBI device to prevent its removal.
+ */
+ ubi = ubi_get_device(ubi_num);
if (!ubi)
return ERR_PTR(-ENODEV);
- if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
- return ERR_PTR(-EINVAL);
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
+ err = -EINVAL;
+ goto out_put_ubi;
+ }
desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
- if (!desc)
- return ERR_PTR(-ENOMEM);
+ if (!desc) {
+ err = -ENOMEM;
+ goto out_put_ubi;
+ }
err = -ENODEV;
if (!try_module_get(THIS_MODULE))
@@ -188,6 +199,8 @@ out_unlock:
module_put(THIS_MODULE);
out_free:
kfree(desc);
+out_put_ubi:
+ ubi_put_device(ubi);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
{
int i, vol_id = -1, len;
struct ubi_device *ubi;
+ struct ubi_volume_desc *ret;
dbg_msg("open volume %s, mode %d", name, mode);
@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
return ERR_PTR(-EINVAL);
- ubi = ubi_devices[ubi_num];
+ ubi = ubi_get_device(ubi_num);
if (!ubi)
return ERR_PTR(-ENODEV);
@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
}
spin_unlock(&ubi->volumes_lock);
- if (vol_id < 0)
- return ERR_PTR(-ENODEV);
+ if (vol_id >= 0)
+ ret = ubi_open_volume(ubi_num, vol_id, mode);
+ else
+ ret = ERR_PTR(-ENODEV);
- return ubi_open_volume(ubi_num, vol_id, mode);
+ /*
+ * We should put the UBI device even in case of success, because
+ * 'ubi_open_volume()' took a reference as well.
+ */
+ ubi_put_device(ubi);
+ return ret;
}
EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
void ubi_close_volume(struct ubi_volume_desc *desc)
{
struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
- spin_lock(&vol->ubi->volumes_lock);
+ spin_lock(&ubi->volumes_lock);
switch (desc->mode) {
case UBI_READONLY:
vol->readers -= 1;
@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
vol->exclusive = 0;
}
vol->ref_count -= 1;
- spin_unlock(&vol->ubi->volumes_lock);
+ spin_unlock(&ubi->volumes_lock);
- put_device(&vol->dev);
kfree(desc);
+ put_device(&vol->dev);
+ ubi_put_device(ubi);
module_put(THIS_MODULE);
}
EXPORT_SYMBOL_GPL(ubi_close_volume);