diff options
Diffstat (limited to 'drivers/mtd/ubi/kapi.c')
-rw-r--r-- | drivers/mtd/ubi/kapi.c | 177 |
1 files changed, 116 insertions, 61 deletions
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 03c774f41549..a70d58823f8d 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 | |||
40 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) | ||
41 | return -EINVAL; | ||
39 | 42 | ||
40 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || | 43 | ubi = ubi_get_device(ubi_num); |
41 | !ubi_devices[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 = MKDEV(ubi->major, 0); | 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); |
@@ -73,7 +77,7 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc, | |||
73 | vi->usable_leb_size = vol->usable_leb_size; | 77 | vi->usable_leb_size = vol->usable_leb_size; |
74 | vi->name_len = vol->name_len; | 78 | vi->name_len = vol->name_len; |
75 | vi->name = vol->name; | 79 | vi->name = vol->name; |
76 | vi->cdev = MKDEV(ubi->major, vi->vol_id + 1); | 80 | vi->cdev = vol->cdev.dev; |
77 | } | 81 | } |
78 | EXPORT_SYMBOL_GPL(ubi_get_volume_info); | 82 | EXPORT_SYMBOL_GPL(ubi_get_volume_info); |
79 | 83 | ||
@@ -104,37 +108,39 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
104 | 108 | ||
105 | dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); | 109 | dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); |
106 | 110 | ||
107 | err = -ENODEV; | 111 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) |
108 | if (ubi_num < 0) | 112 | return ERR_PTR(-EINVAL); |
109 | return ERR_PTR(err); | ||
110 | |||
111 | ubi = ubi_devices[ubi_num]; | ||
112 | |||
113 | if (!try_module_get(THIS_MODULE)) | ||
114 | return ERR_PTR(err); | ||
115 | |||
116 | if (ubi_num >= UBI_MAX_DEVICES || !ubi) | ||
117 | goto out_put; | ||
118 | 113 | ||
119 | err = -EINVAL; | ||
120 | if (vol_id < 0 || vol_id >= ubi->vtbl_slots) | ||
121 | goto out_put; | ||
122 | if (mode != UBI_READONLY && mode != UBI_READWRITE && | 114 | if (mode != UBI_READONLY && mode != UBI_READWRITE && |
123 | mode != UBI_EXCLUSIVE) | 115 | mode != UBI_EXCLUSIVE) |
124 | goto out_put; | 116 | return ERR_PTR(-EINVAL); |
117 | |||
118 | /* | ||
119 | * First of all, we have to get the UBI device to prevent its removal. | ||
120 | */ | ||
121 | ubi = ubi_get_device(ubi_num); | ||
122 | if (!ubi) | ||
123 | return ERR_PTR(-ENODEV); | ||
124 | |||
125 | if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { | ||
126 | err = -EINVAL; | ||
127 | goto out_put_ubi; | ||
128 | } | ||
125 | 129 | ||
126 | desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); | 130 | desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); |
127 | if (!desc) { | 131 | if (!desc) { |
128 | err = -ENOMEM; | 132 | err = -ENOMEM; |
129 | goto out_put; | 133 | goto out_put_ubi; |
130 | } | 134 | } |
131 | 135 | ||
136 | err = -ENODEV; | ||
137 | if (!try_module_get(THIS_MODULE)) | ||
138 | goto out_free; | ||
139 | |||
132 | spin_lock(&ubi->volumes_lock); | 140 | spin_lock(&ubi->volumes_lock); |
133 | vol = ubi->volumes[vol_id]; | 141 | vol = ubi->volumes[vol_id]; |
134 | if (!vol) { | 142 | if (!vol) |
135 | err = -ENODEV; | ||
136 | goto out_unlock; | 143 | goto out_unlock; |
137 | } | ||
138 | 144 | ||
139 | err = -EBUSY; | 145 | err = -EBUSY; |
140 | switch (mode) { | 146 | switch (mode) { |
@@ -156,21 +162,19 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
156 | vol->exclusive = 1; | 162 | vol->exclusive = 1; |
157 | break; | 163 | break; |
158 | } | 164 | } |
165 | get_device(&vol->dev); | ||
166 | vol->ref_count += 1; | ||
159 | spin_unlock(&ubi->volumes_lock); | 167 | spin_unlock(&ubi->volumes_lock); |
160 | 168 | ||
161 | desc->vol = vol; | 169 | desc->vol = vol; |
162 | desc->mode = mode; | 170 | desc->mode = mode; |
163 | 171 | ||
164 | /* | 172 | mutex_lock(&ubi->ckvol_mutex); |
165 | * To prevent simultaneous checks of the same volume we use @vtbl_mutex, | ||
166 | * although it is not the purpose it was introduced for. | ||
167 | */ | ||
168 | mutex_lock(&ubi->vtbl_mutex); | ||
169 | if (!vol->checked) { | 173 | if (!vol->checked) { |
170 | /* This is the first open - check the volume */ | 174 | /* This is the first open - check the volume */ |
171 | err = ubi_check_volume(ubi, vol_id); | 175 | err = ubi_check_volume(ubi, vol_id); |
172 | if (err < 0) { | 176 | if (err < 0) { |
173 | mutex_unlock(&ubi->vtbl_mutex); | 177 | mutex_unlock(&ubi->ckvol_mutex); |
174 | ubi_close_volume(desc); | 178 | ubi_close_volume(desc); |
175 | return ERR_PTR(err); | 179 | return ERR_PTR(err); |
176 | } | 180 | } |
@@ -181,14 +185,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
181 | } | 185 | } |
182 | vol->checked = 1; | 186 | vol->checked = 1; |
183 | } | 187 | } |
184 | mutex_unlock(&ubi->vtbl_mutex); | 188 | mutex_unlock(&ubi->ckvol_mutex); |
189 | |||
185 | return desc; | 190 | return desc; |
186 | 191 | ||
187 | out_unlock: | 192 | out_unlock: |
188 | spin_unlock(&ubi->volumes_lock); | 193 | spin_unlock(&ubi->volumes_lock); |
189 | kfree(desc); | ||
190 | out_put: | ||
191 | module_put(THIS_MODULE); | 194 | module_put(THIS_MODULE); |
195 | out_free: | ||
196 | kfree(desc); | ||
197 | out_put_ubi: | ||
198 | ubi_put_device(ubi); | ||
192 | return ERR_PTR(err); | 199 | return ERR_PTR(err); |
193 | } | 200 | } |
194 | EXPORT_SYMBOL_GPL(ubi_open_volume); | 201 | EXPORT_SYMBOL_GPL(ubi_open_volume); |
@@ -205,8 +212,8 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
205 | int mode) | 212 | int mode) |
206 | { | 213 | { |
207 | int i, vol_id = -1, len; | 214 | int i, vol_id = -1, len; |
208 | struct ubi_volume_desc *ret; | ||
209 | struct ubi_device *ubi; | 215 | struct ubi_device *ubi; |
216 | struct ubi_volume_desc *ret; | ||
210 | 217 | ||
211 | dbg_msg("open volume %s, mode %d", name, mode); | 218 | dbg_msg("open volume %s, mode %d", name, mode); |
212 | 219 | ||
@@ -217,14 +224,12 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
217 | if (len > UBI_VOL_NAME_MAX) | 224 | if (len > UBI_VOL_NAME_MAX) |
218 | return ERR_PTR(-EINVAL); | 225 | return ERR_PTR(-EINVAL); |
219 | 226 | ||
220 | ret = ERR_PTR(-ENODEV); | 227 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) |
221 | if (!try_module_get(THIS_MODULE)) | 228 | return ERR_PTR(-EINVAL); |
222 | return ret; | ||
223 | |||
224 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num]) | ||
225 | goto out_put; | ||
226 | 229 | ||
227 | ubi = ubi_devices[ubi_num]; | 230 | ubi = ubi_get_device(ubi_num); |
231 | if (!ubi) | ||
232 | return ERR_PTR(-ENODEV); | ||
228 | 233 | ||
229 | spin_lock(&ubi->volumes_lock); | 234 | spin_lock(&ubi->volumes_lock); |
230 | /* Walk all volumes of this UBI device */ | 235 | /* Walk all volumes of this UBI device */ |
@@ -238,13 +243,16 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
238 | } | 243 | } |
239 | spin_unlock(&ubi->volumes_lock); | 244 | spin_unlock(&ubi->volumes_lock); |
240 | 245 | ||
241 | if (vol_id < 0) | 246 | if (vol_id >= 0) |
242 | goto out_put; | 247 | ret = ubi_open_volume(ubi_num, vol_id, mode); |
248 | else | ||
249 | ret = ERR_PTR(-ENODEV); | ||
243 | 250 | ||
244 | ret = ubi_open_volume(ubi_num, vol_id, mode); | 251 | /* |
245 | 252 | * We should put the UBI device even in case of success, because | |
246 | out_put: | 253 | * 'ubi_open_volume()' took a reference as well. |
247 | module_put(THIS_MODULE); | 254 | */ |
255 | ubi_put_device(ubi); | ||
248 | return ret; | 256 | return ret; |
249 | } | 257 | } |
250 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | 258 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); |
@@ -256,10 +264,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | |||
256 | void ubi_close_volume(struct ubi_volume_desc *desc) | 264 | void ubi_close_volume(struct ubi_volume_desc *desc) |
257 | { | 265 | { |
258 | struct ubi_volume *vol = desc->vol; | 266 | struct ubi_volume *vol = desc->vol; |
267 | struct ubi_device *ubi = vol->ubi; | ||
259 | 268 | ||
260 | dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); | 269 | dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); |
261 | 270 | ||
262 | spin_lock(&vol->ubi->volumes_lock); | 271 | spin_lock(&ubi->volumes_lock); |
263 | switch (desc->mode) { | 272 | switch (desc->mode) { |
264 | case UBI_READONLY: | 273 | case UBI_READONLY: |
265 | vol->readers -= 1; | 274 | vol->readers -= 1; |
@@ -270,9 +279,12 @@ void ubi_close_volume(struct ubi_volume_desc *desc) | |||
270 | case UBI_EXCLUSIVE: | 279 | case UBI_EXCLUSIVE: |
271 | vol->exclusive = 0; | 280 | vol->exclusive = 0; |
272 | } | 281 | } |
273 | spin_unlock(&vol->ubi->volumes_lock); | 282 | vol->ref_count -= 1; |
283 | spin_unlock(&ubi->volumes_lock); | ||
274 | 284 | ||
275 | kfree(desc); | 285 | kfree(desc); |
286 | put_device(&vol->dev); | ||
287 | ubi_put_device(ubi); | ||
276 | module_put(THIS_MODULE); | 288 | module_put(THIS_MODULE); |
277 | } | 289 | } |
278 | EXPORT_SYMBOL_GPL(ubi_close_volume); | 290 | EXPORT_SYMBOL_GPL(ubi_close_volume); |
@@ -332,7 +344,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, | |||
332 | if (len == 0) | 344 | if (len == 0) |
333 | return 0; | 345 | return 0; |
334 | 346 | ||
335 | err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check); | 347 | err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); |
336 | if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { | 348 | if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { |
337 | ubi_warn("mark volume %d as corrupted", vol_id); | 349 | ubi_warn("mark volume %d as corrupted", vol_id); |
338 | vol->corrupted = 1; | 350 | vol->corrupted = 1; |
@@ -399,7 +411,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, | |||
399 | if (len == 0) | 411 | if (len == 0) |
400 | return 0; | 412 | return 0; |
401 | 413 | ||
402 | return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype); | 414 | return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype); |
403 | } | 415 | } |
404 | EXPORT_SYMBOL_GPL(ubi_leb_write); | 416 | EXPORT_SYMBOL_GPL(ubi_leb_write); |
405 | 417 | ||
@@ -448,7 +460,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, | |||
448 | if (len == 0) | 460 | if (len == 0) |
449 | return 0; | 461 | return 0; |
450 | 462 | ||
451 | return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype); | 463 | return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype); |
452 | } | 464 | } |
453 | EXPORT_SYMBOL_GPL(ubi_leb_change); | 465 | EXPORT_SYMBOL_GPL(ubi_leb_change); |
454 | 466 | ||
@@ -468,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) | |||
468 | { | 480 | { |
469 | struct ubi_volume *vol = desc->vol; | 481 | struct ubi_volume *vol = desc->vol; |
470 | struct ubi_device *ubi = vol->ubi; | 482 | struct ubi_device *ubi = vol->ubi; |
471 | int err, vol_id = vol->vol_id; | 483 | int err; |
472 | 484 | ||
473 | dbg_msg("erase LEB %d:%d", vol_id, lnum); | 485 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); |
474 | 486 | ||
475 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | 487 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) |
476 | return -EROFS; | 488 | return -EROFS; |
@@ -481,7 +493,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) | |||
481 | if (vol->upd_marker) | 493 | if (vol->upd_marker) |
482 | return -EBADF; | 494 | return -EBADF; |
483 | 495 | ||
484 | err = ubi_eba_unmap_leb(ubi, vol_id, lnum); | 496 | err = ubi_eba_unmap_leb(ubi, vol, lnum); |
485 | if (err) | 497 | if (err) |
486 | return err; | 498 | return err; |
487 | 499 | ||
@@ -529,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) | |||
529 | { | 541 | { |
530 | struct ubi_volume *vol = desc->vol; | 542 | struct ubi_volume *vol = desc->vol; |
531 | struct ubi_device *ubi = vol->ubi; | 543 | struct ubi_device *ubi = vol->ubi; |
532 | int vol_id = vol->vol_id; | ||
533 | 544 | ||
534 | dbg_msg("unmap LEB %d:%d", vol_id, lnum); | 545 | dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); |
535 | 546 | ||
536 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | 547 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) |
537 | return -EROFS; | 548 | return -EROFS; |
@@ -542,11 +553,55 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) | |||
542 | if (vol->upd_marker) | 553 | if (vol->upd_marker) |
543 | return -EBADF; | 554 | return -EBADF; |
544 | 555 | ||
545 | return ubi_eba_unmap_leb(ubi, vol_id, lnum); | 556 | return ubi_eba_unmap_leb(ubi, vol, lnum); |
546 | } | 557 | } |
547 | EXPORT_SYMBOL_GPL(ubi_leb_unmap); | 558 | EXPORT_SYMBOL_GPL(ubi_leb_unmap); |
548 | 559 | ||
549 | /** | 560 | /** |
561 | * ubi_leb_map - map logical erasblock to a physical eraseblock. | ||
562 | * @desc: volume descriptor | ||
563 | * @lnum: logical eraseblock number | ||
564 | * @dtype: expected data type | ||
565 | * | ||
566 | * This function maps an un-mapped logical eraseblock @lnum to a physical | ||
567 | * eraseblock. This means, that after a successfull invocation of this | ||
568 | * function the logical eraseblock @lnum will be empty (contain only %0xFF | ||
569 | * bytes) and be mapped to a physical eraseblock, even if an unclean reboot | ||
570 | * happens. | ||
571 | * | ||
572 | * This function returns zero in case of success, %-EBADF if the volume is | ||
573 | * damaged because of an interrupted update, %-EBADMSG if the logical | ||
574 | * eraseblock is already mapped, and other negative error codes in case of | ||
575 | * other failures. | ||
576 | */ | ||
577 | int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) | ||
578 | { | ||
579 | struct ubi_volume *vol = desc->vol; | ||
580 | struct ubi_device *ubi = vol->ubi; | ||
581 | |||
582 | dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); | ||
583 | |||
584 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | ||
585 | return -EROFS; | ||
586 | |||
587 | if (lnum < 0 || lnum >= vol->reserved_pebs) | ||
588 | return -EINVAL; | ||
589 | |||
590 | if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && | ||
591 | dtype != UBI_UNKNOWN) | ||
592 | return -EINVAL; | ||
593 | |||
594 | if (vol->upd_marker) | ||
595 | return -EBADF; | ||
596 | |||
597 | if (vol->eba_tbl[lnum] >= 0) | ||
598 | return -EBADMSG; | ||
599 | |||
600 | return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); | ||
601 | } | ||
602 | EXPORT_SYMBOL_GPL(ubi_leb_map); | ||
603 | |||
604 | /** | ||
550 | * ubi_is_mapped - check if logical eraseblock is mapped. | 605 | * ubi_is_mapped - check if logical eraseblock is mapped. |
551 | * @desc: volume descriptor | 606 | * @desc: volume descriptor |
552 | * @lnum: logical eraseblock number | 607 | * @lnum: logical eraseblock number |