diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-17 10:37:26 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-12-26 12:15:17 -0500 |
commit | e73f4459d969bb266f03dd4cbe21bdba8cb2732c (patch) | |
tree | 5af7655da65f2c33f6ea4efdfaa8b0e0670d6aea /drivers/mtd/ubi/kapi.c | |
parent | 9f961b57568960a150cc9781c52824c9093a0514 (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.c | 59 |
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 | */ |
36 | int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) | 36 | int 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 | } |
52 | EXPORT_SYMBOL_GPL(ubi_get_device_info); | 56 | 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) | |||
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); |
189 | out_free: | 200 | out_free: |
190 | kfree(desc); | 201 | kfree(desc); |
202 | out_put_ubi: | ||
203 | ubi_put_device(ubi); | ||
191 | return ERR_PTR(err); | 204 | return ERR_PTR(err); |
192 | } | 205 | } |
193 | EXPORT_SYMBOL_GPL(ubi_open_volume); | 206 | EXPORT_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 | } |
242 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | 263 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); |
243 | 264 | ||
@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | |||
248 | void ubi_close_volume(struct ubi_volume_desc *desc) | 269 | void 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 | } |
272 | EXPORT_SYMBOL_GPL(ubi_close_volume); | 295 | EXPORT_SYMBOL_GPL(ubi_close_volume); |