aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/kapi.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-17 10:37:26 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-26 12:15:17 -0500
commite73f4459d969bb266f03dd4cbe21bdba8cb2732c (patch)
tree5af7655da65f2c33f6ea4efdfaa8b0e0670d6aea /drivers/mtd/ubi/kapi.c
parent9f961b57568960a150cc9781c52824c9093a0514 (diff)
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 @@
30 * @ubi_num: UBI device number 30 * @ubi_num: UBI device number
31 * @di: the information is stored here 31 * @di: the information is stored here
32 * 32 *
33 * This function returns %0 in case of success and a %-ENODEV if there is no 33 * This function returns %0 in case of success, %-EINVAL if the UBI device
34 * such UBI device. 34 * number is invalid, and %-ENODEV if there is no such UBI device.
35 */ 35 */
36int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) 36int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
37{ 37{
38 const struct ubi_device *ubi; 38 struct ubi_device *ubi;
39 39
40 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || 40 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
41 !ubi_devices[ubi_num]) 41 return -EINVAL;
42
43 ubi = ubi_get_device(ubi_num);
44 if (!ubi)
42 return -ENODEV; 45 return -ENODEV;
43 46
44 ubi = ubi_devices[ubi_num];
45 di->ubi_num = ubi->ubi_num; 47 di->ubi_num = ubi->ubi_num;
46 di->leb_size = ubi->leb_size; 48 di->leb_size = ubi->leb_size;
47 di->min_io_size = ubi->min_io_size; 49 di->min_io_size = ubi->min_io_size;
48 di->ro_mode = ubi->ro_mode; 50 di->ro_mode = ubi->ro_mode;
49 di->cdev = ubi->cdev.dev; 51 di->cdev = ubi->cdev.dev;
52
53 ubi_put_device(ubi);
50 return 0; 54 return 0;
51} 55}
52EXPORT_SYMBOL_GPL(ubi_get_device_info); 56EXPORT_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)
111 mode != UBI_EXCLUSIVE) 115 mode != UBI_EXCLUSIVE)
112 return ERR_PTR(-EINVAL); 116 return ERR_PTR(-EINVAL);
113 117
114 ubi = ubi_devices[ubi_num]; 118 /*
119 * First of all, we have to get the UBI device to prevent its removal.
120 */
121 ubi = ubi_get_device(ubi_num);
115 if (!ubi) 122 if (!ubi)
116 return ERR_PTR(-ENODEV); 123 return ERR_PTR(-ENODEV);
117 124
118 if (vol_id < 0 || vol_id >= ubi->vtbl_slots) 125 if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
119 return ERR_PTR(-EINVAL); 126 err = -EINVAL;
127 goto out_put_ubi;
128 }
120 129
121 desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); 130 desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
122 if (!desc) 131 if (!desc) {
123 return ERR_PTR(-ENOMEM); 132 err = -ENOMEM;
133 goto out_put_ubi;
134 }
124 135
125 err = -ENODEV; 136 err = -ENODEV;
126 if (!try_module_get(THIS_MODULE)) 137 if (!try_module_get(THIS_MODULE))
@@ -188,6 +199,8 @@ out_unlock:
188 module_put(THIS_MODULE); 199 module_put(THIS_MODULE);
189out_free: 200out_free:
190 kfree(desc); 201 kfree(desc);
202out_put_ubi:
203 ubi_put_device(ubi);
191 return ERR_PTR(err); 204 return ERR_PTR(err);
192} 205}
193EXPORT_SYMBOL_GPL(ubi_open_volume); 206EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
205{ 218{
206 int i, vol_id = -1, len; 219 int i, vol_id = -1, len;
207 struct ubi_device *ubi; 220 struct ubi_device *ubi;
221 struct ubi_volume_desc *ret;
208 222
209 dbg_msg("open volume %s, mode %d", name, mode); 223 dbg_msg("open volume %s, mode %d", name, mode);
210 224
@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
218 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) 232 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
219 return ERR_PTR(-EINVAL); 233 return ERR_PTR(-EINVAL);
220 234
221 ubi = ubi_devices[ubi_num]; 235 ubi = ubi_get_device(ubi_num);
222 if (!ubi) 236 if (!ubi)
223 return ERR_PTR(-ENODEV); 237 return ERR_PTR(-ENODEV);
224 238
@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
234 } 248 }
235 spin_unlock(&ubi->volumes_lock); 249 spin_unlock(&ubi->volumes_lock);
236 250
237 if (vol_id < 0) 251 if (vol_id >= 0)
238 return ERR_PTR(-ENODEV); 252 ret = ubi_open_volume(ubi_num, vol_id, mode);
253 else
254 ret = ERR_PTR(-ENODEV);
239 255
240 return ubi_open_volume(ubi_num, vol_id, mode); 256 /*
257 * We should put the UBI device even in case of success, because
258 * 'ubi_open_volume()' took a reference as well.
259 */
260 ubi_put_device(ubi);
261 return ret;
241} 262}
242EXPORT_SYMBOL_GPL(ubi_open_volume_nm); 263EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
243 264
@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
248void ubi_close_volume(struct ubi_volume_desc *desc) 269void ubi_close_volume(struct ubi_volume_desc *desc)
249{ 270{
250 struct ubi_volume *vol = desc->vol; 271 struct ubi_volume *vol = desc->vol;
272 struct ubi_device *ubi = vol->ubi;
251 273
252 dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); 274 dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
253 275
254 spin_lock(&vol->ubi->volumes_lock); 276 spin_lock(&ubi->volumes_lock);
255 switch (desc->mode) { 277 switch (desc->mode) {
256 case UBI_READONLY: 278 case UBI_READONLY:
257 vol->readers -= 1; 279 vol->readers -= 1;
@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
263 vol->exclusive = 0; 285 vol->exclusive = 0;
264 } 286 }
265 vol->ref_count -= 1; 287 vol->ref_count -= 1;
266 spin_unlock(&vol->ubi->volumes_lock); 288 spin_unlock(&ubi->volumes_lock);
267 289
268 put_device(&vol->dev);
269 kfree(desc); 290 kfree(desc);
291 put_device(&vol->dev);
292 ubi_put_device(ubi);
270 module_put(THIS_MODULE); 293 module_put(THIS_MODULE);
271} 294}
272EXPORT_SYMBOL_GPL(ubi_close_volume); 295EXPORT_SYMBOL_GPL(ubi_close_volume);