diff options
Diffstat (limited to 'drivers/mtd/ubi/vmt.c')
-rw-r--r-- | drivers/mtd/ubi/vmt.c | 809 |
1 files changed, 809 insertions, 0 deletions
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c new file mode 100644 index 000000000000..622d0d18952c --- /dev/null +++ b/drivers/mtd/ubi/vmt.c | |||
@@ -0,0 +1,809 @@ | |||
1 | /* | ||
2 | * Copyright (c) International Business Machines Corp., 2006 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
12 | * the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Author: Artem Bityutskiy (Битюцкий Артём) | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * This file contains implementation of volume creation, deletion, updating and | ||
23 | * resizing. | ||
24 | */ | ||
25 | |||
26 | #include <linux/err.h> | ||
27 | #include <asm/div64.h> | ||
28 | #include "ubi.h" | ||
29 | |||
30 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID | ||
31 | static void paranoid_check_volumes(struct ubi_device *ubi); | ||
32 | #else | ||
33 | #define paranoid_check_volumes(ubi) | ||
34 | #endif | ||
35 | |||
36 | static ssize_t vol_attribute_show(struct device *dev, | ||
37 | struct device_attribute *attr, char *buf); | ||
38 | |||
39 | /* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */ | ||
40 | static struct device_attribute vol_reserved_ebs = | ||
41 | __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); | ||
42 | static struct device_attribute vol_type = | ||
43 | __ATTR(type, S_IRUGO, vol_attribute_show, NULL); | ||
44 | static struct device_attribute vol_name = | ||
45 | __ATTR(name, S_IRUGO, vol_attribute_show, NULL); | ||
46 | static struct device_attribute vol_corrupted = | ||
47 | __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); | ||
48 | static struct device_attribute vol_alignment = | ||
49 | __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); | ||
50 | static struct device_attribute vol_usable_eb_size = | ||
51 | __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); | ||
52 | static struct device_attribute vol_data_bytes = | ||
53 | __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); | ||
54 | static struct device_attribute vol_upd_marker = | ||
55 | __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); | ||
56 | |||
57 | /* | ||
58 | * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'. | ||
59 | * | ||
60 | * Consider a situation: | ||
61 | * A. process 1 opens a sysfs file related to volume Y, say | ||
62 | * /<sysfs>/class/ubi/ubiX_Y/reserved_ebs; | ||
63 | * B. process 2 removes volume Y; | ||
64 | * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file; | ||
65 | * | ||
66 | * What we want to do in a situation like that is to return error when the file | ||
67 | * is read. This is done by means of the 'removed' flag and the 'vol_lock' of | ||
68 | * the UBI volume description object. | ||
69 | */ | ||
70 | static ssize_t vol_attribute_show(struct device *dev, | ||
71 | struct device_attribute *attr, char *buf) | ||
72 | { | ||
73 | int ret; | ||
74 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); | ||
75 | |||
76 | spin_lock(&vol->ubi->volumes_lock); | ||
77 | if (vol->removed) { | ||
78 | spin_unlock(&vol->ubi->volumes_lock); | ||
79 | return -ENODEV; | ||
80 | } | ||
81 | if (attr == &vol_reserved_ebs) | ||
82 | ret = sprintf(buf, "%d\n", vol->reserved_pebs); | ||
83 | else if (attr == &vol_type) { | ||
84 | const char *tp; | ||
85 | tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static"; | ||
86 | ret = sprintf(buf, "%s\n", tp); | ||
87 | } else if (attr == &vol_name) | ||
88 | ret = sprintf(buf, "%s\n", vol->name); | ||
89 | else if (attr == &vol_corrupted) | ||
90 | ret = sprintf(buf, "%d\n", vol->corrupted); | ||
91 | else if (attr == &vol_alignment) | ||
92 | ret = sprintf(buf, "%d\n", vol->alignment); | ||
93 | else if (attr == &vol_usable_eb_size) { | ||
94 | ret = sprintf(buf, "%d\n", vol->usable_leb_size); | ||
95 | } else if (attr == &vol_data_bytes) | ||
96 | ret = sprintf(buf, "%lld\n", vol->used_bytes); | ||
97 | else if (attr == &vol_upd_marker) | ||
98 | ret = sprintf(buf, "%d\n", vol->upd_marker); | ||
99 | else | ||
100 | BUG(); | ||
101 | spin_unlock(&vol->ubi->volumes_lock); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | /* Release method for volume devices */ | ||
106 | static void vol_release(struct device *dev) | ||
107 | { | ||
108 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); | ||
109 | ubi_assert(vol->removed); | ||
110 | kfree(vol); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * volume_sysfs_init - initialize sysfs for new volume. | ||
115 | * @ubi: UBI device description object | ||
116 | * @vol: volume description object | ||
117 | * | ||
118 | * This function returns zero in case of success and a negative error code in | ||
119 | * case of failure. | ||
120 | * | ||
121 | * Note, this function does not free allocated resources in case of failure - | ||
122 | * the caller does it. This is because this would cause release() here and the | ||
123 | * caller would oops. | ||
124 | */ | ||
125 | static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) | ||
126 | { | ||
127 | int err; | ||
128 | |||
129 | err = device_create_file(&vol->dev, &vol_reserved_ebs); | ||
130 | if (err) | ||
131 | return err; | ||
132 | err = device_create_file(&vol->dev, &vol_type); | ||
133 | if (err) | ||
134 | return err; | ||
135 | err = device_create_file(&vol->dev, &vol_name); | ||
136 | if (err) | ||
137 | return err; | ||
138 | err = device_create_file(&vol->dev, &vol_corrupted); | ||
139 | if (err) | ||
140 | return err; | ||
141 | err = device_create_file(&vol->dev, &vol_alignment); | ||
142 | if (err) | ||
143 | return err; | ||
144 | err = device_create_file(&vol->dev, &vol_usable_eb_size); | ||
145 | if (err) | ||
146 | return err; | ||
147 | err = device_create_file(&vol->dev, &vol_data_bytes); | ||
148 | if (err) | ||
149 | return err; | ||
150 | err = device_create_file(&vol->dev, &vol_upd_marker); | ||
151 | if (err) | ||
152 | return err; | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * volume_sysfs_close - close sysfs for a volume. | ||
158 | * @vol: volume description object | ||
159 | */ | ||
160 | static void volume_sysfs_close(struct ubi_volume *vol) | ||
161 | { | ||
162 | device_remove_file(&vol->dev, &vol_upd_marker); | ||
163 | device_remove_file(&vol->dev, &vol_data_bytes); | ||
164 | device_remove_file(&vol->dev, &vol_usable_eb_size); | ||
165 | device_remove_file(&vol->dev, &vol_alignment); | ||
166 | device_remove_file(&vol->dev, &vol_corrupted); | ||
167 | device_remove_file(&vol->dev, &vol_name); | ||
168 | device_remove_file(&vol->dev, &vol_type); | ||
169 | device_remove_file(&vol->dev, &vol_reserved_ebs); | ||
170 | device_unregister(&vol->dev); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * ubi_create_volume - create volume. | ||
175 | * @ubi: UBI device description object | ||
176 | * @req: volume creation request | ||
177 | * | ||
178 | * This function creates volume described by @req. If @req->vol_id id | ||
179 | * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume | ||
180 | * and saves it in @req->vol_id. Returns zero in case of success and a negative | ||
181 | * error code in case of failure. | ||
182 | */ | ||
183 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | ||
184 | { | ||
185 | int i, err, vol_id = req->vol_id; | ||
186 | struct ubi_volume *vol; | ||
187 | struct ubi_vtbl_record vtbl_rec; | ||
188 | uint64_t bytes; | ||
189 | |||
190 | if (ubi->ro_mode) | ||
191 | return -EROFS; | ||
192 | |||
193 | vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); | ||
194 | if (!vol) | ||
195 | return -ENOMEM; | ||
196 | |||
197 | spin_lock(&ubi->volumes_lock); | ||
198 | |||
199 | if (vol_id == UBI_VOL_NUM_AUTO) { | ||
200 | /* Find unused volume ID */ | ||
201 | dbg_msg("search for vacant volume ID"); | ||
202 | for (i = 0; i < ubi->vtbl_slots; i++) | ||
203 | if (!ubi->volumes[i]) { | ||
204 | vol_id = i; | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | if (vol_id == UBI_VOL_NUM_AUTO) { | ||
209 | dbg_err("out of volume IDs"); | ||
210 | err = -ENFILE; | ||
211 | goto out_unlock; | ||
212 | } | ||
213 | req->vol_id = vol_id; | ||
214 | } | ||
215 | |||
216 | dbg_msg("volume ID %d, %llu bytes, type %d, name %s", | ||
217 | vol_id, (unsigned long long)req->bytes, | ||
218 | (int)req->vol_type, req->name); | ||
219 | |||
220 | /* Ensure that this volume does not exist */ | ||
221 | err = -EEXIST; | ||
222 | if (ubi->volumes[vol_id]) { | ||
223 | dbg_err("volume %d already exists", vol_id); | ||
224 | goto out_unlock; | ||
225 | } | ||
226 | |||
227 | /* Ensure that the name is unique */ | ||
228 | for (i = 0; i < ubi->vtbl_slots; i++) | ||
229 | if (ubi->volumes[i] && | ||
230 | ubi->volumes[i]->name_len == req->name_len && | ||
231 | strcmp(ubi->volumes[i]->name, req->name) == 0) { | ||
232 | dbg_err("volume \"%s\" exists (ID %d)", req->name, i); | ||
233 | goto out_unlock; | ||
234 | } | ||
235 | |||
236 | /* Calculate how many eraseblocks are requested */ | ||
237 | vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; | ||
238 | bytes = req->bytes; | ||
239 | if (do_div(bytes, vol->usable_leb_size)) | ||
240 | vol->reserved_pebs = 1; | ||
241 | vol->reserved_pebs += bytes; | ||
242 | |||
243 | /* Reserve physical eraseblocks */ | ||
244 | if (vol->reserved_pebs > ubi->avail_pebs) { | ||
245 | dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); | ||
246 | spin_unlock(&ubi->volumes_lock); | ||
247 | err = -ENOSPC; | ||
248 | goto out_unlock; | ||
249 | } | ||
250 | ubi->avail_pebs -= vol->reserved_pebs; | ||
251 | ubi->rsvd_pebs += vol->reserved_pebs; | ||
252 | |||
253 | vol->vol_id = vol_id; | ||
254 | vol->alignment = req->alignment; | ||
255 | vol->data_pad = ubi->leb_size % vol->alignment; | ||
256 | vol->vol_type = req->vol_type; | ||
257 | vol->name_len = req->name_len; | ||
258 | memcpy(vol->name, req->name, vol->name_len + 1); | ||
259 | vol->exclusive = 1; | ||
260 | vol->ubi = ubi; | ||
261 | ubi->volumes[vol_id] = vol; | ||
262 | spin_unlock(&ubi->volumes_lock); | ||
263 | |||
264 | /* | ||
265 | * Finish all pending erases because there may be some LEBs belonging | ||
266 | * to the same volume ID. | ||
267 | */ | ||
268 | err = ubi_wl_flush(ubi); | ||
269 | if (err) | ||
270 | goto out_acc; | ||
271 | |||
272 | vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL); | ||
273 | if (!vol->eba_tbl) { | ||
274 | err = -ENOMEM; | ||
275 | goto out_acc; | ||
276 | } | ||
277 | |||
278 | for (i = 0; i < vol->reserved_pebs; i++) | ||
279 | vol->eba_tbl[i] = UBI_LEB_UNMAPPED; | ||
280 | |||
281 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { | ||
282 | vol->used_ebs = vol->reserved_pebs; | ||
283 | vol->last_eb_bytes = vol->usable_leb_size; | ||
284 | vol->used_bytes = vol->used_ebs * vol->usable_leb_size; | ||
285 | } else { | ||
286 | bytes = vol->used_bytes; | ||
287 | vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); | ||
288 | vol->used_ebs = bytes; | ||
289 | if (vol->last_eb_bytes) | ||
290 | vol->used_ebs += 1; | ||
291 | else | ||
292 | vol->last_eb_bytes = vol->usable_leb_size; | ||
293 | } | ||
294 | |||
295 | /* Register character device for the volume */ | ||
296 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); | ||
297 | vol->cdev.owner = THIS_MODULE; | ||
298 | err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1); | ||
299 | if (err) { | ||
300 | ubi_err("cannot add character device for volume %d", vol_id); | ||
301 | goto out_mapping; | ||
302 | } | ||
303 | |||
304 | err = ubi_create_gluebi(ubi, vol); | ||
305 | if (err) | ||
306 | goto out_cdev; | ||
307 | |||
308 | vol->dev.release = vol_release; | ||
309 | vol->dev.parent = &ubi->dev; | ||
310 | vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); | ||
311 | vol->dev.class = ubi_class; | ||
312 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); | ||
313 | err = device_register(&vol->dev); | ||
314 | if (err) | ||
315 | goto out_gluebi; | ||
316 | |||
317 | err = volume_sysfs_init(ubi, vol); | ||
318 | if (err) | ||
319 | goto out_sysfs; | ||
320 | |||
321 | /* Fill volume table record */ | ||
322 | memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); | ||
323 | vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs); | ||
324 | vtbl_rec.alignment = cpu_to_ubi32(vol->alignment); | ||
325 | vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad); | ||
326 | vtbl_rec.name_len = cpu_to_ubi16(vol->name_len); | ||
327 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) | ||
328 | vtbl_rec.vol_type = UBI_VID_DYNAMIC; | ||
329 | else | ||
330 | vtbl_rec.vol_type = UBI_VID_STATIC; | ||
331 | memcpy(vtbl_rec.name, vol->name, vol->name_len + 1); | ||
332 | |||
333 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); | ||
334 | if (err) | ||
335 | goto out_sysfs; | ||
336 | |||
337 | spin_lock(&ubi->volumes_lock); | ||
338 | ubi->vol_count += 1; | ||
339 | vol->exclusive = 0; | ||
340 | spin_unlock(&ubi->volumes_lock); | ||
341 | |||
342 | paranoid_check_volumes(ubi); | ||
343 | return 0; | ||
344 | |||
345 | out_gluebi: | ||
346 | err = ubi_destroy_gluebi(vol); | ||
347 | out_cdev: | ||
348 | cdev_del(&vol->cdev); | ||
349 | out_mapping: | ||
350 | kfree(vol->eba_tbl); | ||
351 | out_acc: | ||
352 | spin_lock(&ubi->volumes_lock); | ||
353 | ubi->rsvd_pebs -= vol->reserved_pebs; | ||
354 | ubi->avail_pebs += vol->reserved_pebs; | ||
355 | out_unlock: | ||
356 | spin_unlock(&ubi->volumes_lock); | ||
357 | kfree(vol); | ||
358 | return err; | ||
359 | |||
360 | /* | ||
361 | * We are registered, so @vol is destroyed in the release function and | ||
362 | * we have to de-initialize differently. | ||
363 | */ | ||
364 | out_sysfs: | ||
365 | err = ubi_destroy_gluebi(vol); | ||
366 | cdev_del(&vol->cdev); | ||
367 | kfree(vol->eba_tbl); | ||
368 | spin_lock(&ubi->volumes_lock); | ||
369 | ubi->rsvd_pebs -= vol->reserved_pebs; | ||
370 | ubi->avail_pebs += vol->reserved_pebs; | ||
371 | spin_unlock(&ubi->volumes_lock); | ||
372 | volume_sysfs_close(vol); | ||
373 | return err; | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * ubi_remove_volume - remove volume. | ||
378 | * @desc: volume descriptor | ||
379 | * | ||
380 | * This function removes volume described by @desc. The volume has to be opened | ||
381 | * in "exclusive" mode. Returns zero in case of success and a negative error | ||
382 | * code in case of failure. | ||
383 | */ | ||
384 | int ubi_remove_volume(struct ubi_volume_desc *desc) | ||
385 | { | ||
386 | struct ubi_volume *vol = desc->vol; | ||
387 | struct ubi_device *ubi = vol->ubi; | ||
388 | int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; | ||
389 | |||
390 | dbg_msg("remove UBI volume %d", vol_id); | ||
391 | ubi_assert(desc->mode == UBI_EXCLUSIVE); | ||
392 | ubi_assert(vol == ubi->volumes[vol_id]); | ||
393 | |||
394 | if (ubi->ro_mode) | ||
395 | return -EROFS; | ||
396 | |||
397 | err = ubi_destroy_gluebi(vol); | ||
398 | if (err) | ||
399 | return err; | ||
400 | |||
401 | err = ubi_change_vtbl_record(ubi, vol_id, NULL); | ||
402 | if (err) | ||
403 | return err; | ||
404 | |||
405 | for (i = 0; i < vol->reserved_pebs; i++) { | ||
406 | err = ubi_eba_unmap_leb(ubi, vol_id, i); | ||
407 | if (err) | ||
408 | return err; | ||
409 | } | ||
410 | |||
411 | spin_lock(&ubi->volumes_lock); | ||
412 | vol->removed = 1; | ||
413 | ubi->volumes[vol_id] = NULL; | ||
414 | spin_unlock(&ubi->volumes_lock); | ||
415 | |||
416 | kfree(vol->eba_tbl); | ||
417 | vol->eba_tbl = NULL; | ||
418 | cdev_del(&vol->cdev); | ||
419 | volume_sysfs_close(vol); | ||
420 | kfree(desc); | ||
421 | |||
422 | spin_lock(&ubi->volumes_lock); | ||
423 | ubi->rsvd_pebs -= reserved_pebs; | ||
424 | ubi->avail_pebs += reserved_pebs; | ||
425 | i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; | ||
426 | if (i > 0) { | ||
427 | i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; | ||
428 | ubi->avail_pebs -= i; | ||
429 | ubi->rsvd_pebs += i; | ||
430 | ubi->beb_rsvd_pebs += i; | ||
431 | if (i > 0) | ||
432 | ubi_msg("reserve more %d PEBs", i); | ||
433 | } | ||
434 | ubi->vol_count -= 1; | ||
435 | spin_unlock(&ubi->volumes_lock); | ||
436 | |||
437 | paranoid_check_volumes(ubi); | ||
438 | module_put(THIS_MODULE); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /** | ||
443 | * ubi_resize_volume - re-size volume. | ||
444 | * @desc: volume descriptor | ||
445 | * @reserved_pebs: new size in physical eraseblocks | ||
446 | * | ||
447 | * This function returns zero in case of success, and a negative error code in | ||
448 | * case of failure. | ||
449 | */ | ||
450 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | ||
451 | { | ||
452 | int i, err, pebs, *new_mapping; | ||
453 | struct ubi_volume *vol = desc->vol; | ||
454 | struct ubi_device *ubi = vol->ubi; | ||
455 | struct ubi_vtbl_record vtbl_rec; | ||
456 | int vol_id = vol->vol_id; | ||
457 | |||
458 | if (ubi->ro_mode) | ||
459 | return -EROFS; | ||
460 | |||
461 | dbg_msg("re-size volume %d to from %d to %d PEBs", | ||
462 | vol_id, vol->reserved_pebs, reserved_pebs); | ||
463 | ubi_assert(desc->mode == UBI_EXCLUSIVE); | ||
464 | ubi_assert(vol == ubi->volumes[vol_id]); | ||
465 | |||
466 | if (vol->vol_type == UBI_STATIC_VOLUME && | ||
467 | reserved_pebs < vol->used_ebs) { | ||
468 | dbg_err("too small size %d, %d LEBs contain data", | ||
469 | reserved_pebs, vol->used_ebs); | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | /* If the size is the same, we have nothing to do */ | ||
474 | if (reserved_pebs == vol->reserved_pebs) | ||
475 | return 0; | ||
476 | |||
477 | new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL); | ||
478 | if (!new_mapping) | ||
479 | return -ENOMEM; | ||
480 | |||
481 | for (i = 0; i < reserved_pebs; i++) | ||
482 | new_mapping[i] = UBI_LEB_UNMAPPED; | ||
483 | |||
484 | /* Reserve physical eraseblocks */ | ||
485 | pebs = reserved_pebs - vol->reserved_pebs; | ||
486 | if (pebs > 0) { | ||
487 | spin_lock(&ubi->volumes_lock); | ||
488 | if (pebs > ubi->avail_pebs) { | ||
489 | dbg_err("not enough PEBs: requested %d, available %d", | ||
490 | pebs, ubi->avail_pebs); | ||
491 | spin_unlock(&ubi->volumes_lock); | ||
492 | err = -ENOSPC; | ||
493 | goto out_free; | ||
494 | } | ||
495 | ubi->avail_pebs -= pebs; | ||
496 | ubi->rsvd_pebs += pebs; | ||
497 | for (i = 0; i < vol->reserved_pebs; i++) | ||
498 | new_mapping[i] = vol->eba_tbl[i]; | ||
499 | kfree(vol->eba_tbl); | ||
500 | vol->eba_tbl = new_mapping; | ||
501 | spin_unlock(&ubi->volumes_lock); | ||
502 | } | ||
503 | |||
504 | /* Change volume table record */ | ||
505 | memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); | ||
506 | vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs); | ||
507 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); | ||
508 | if (err) | ||
509 | goto out_acc; | ||
510 | |||
511 | if (pebs < 0) { | ||
512 | for (i = 0; i < -pebs; i++) { | ||
513 | err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i); | ||
514 | if (err) | ||
515 | goto out_acc; | ||
516 | } | ||
517 | spin_lock(&ubi->volumes_lock); | ||
518 | ubi->rsvd_pebs += pebs; | ||
519 | ubi->avail_pebs -= pebs; | ||
520 | pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; | ||
521 | if (pebs > 0) { | ||
522 | pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs; | ||
523 | ubi->avail_pebs -= pebs; | ||
524 | ubi->rsvd_pebs += pebs; | ||
525 | ubi->beb_rsvd_pebs += pebs; | ||
526 | if (pebs > 0) | ||
527 | ubi_msg("reserve more %d PEBs", pebs); | ||
528 | } | ||
529 | for (i = 0; i < reserved_pebs; i++) | ||
530 | new_mapping[i] = vol->eba_tbl[i]; | ||
531 | kfree(vol->eba_tbl); | ||
532 | vol->eba_tbl = new_mapping; | ||
533 | spin_unlock(&ubi->volumes_lock); | ||
534 | } | ||
535 | |||
536 | vol->reserved_pebs = reserved_pebs; | ||
537 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { | ||
538 | vol->used_ebs = reserved_pebs; | ||
539 | vol->last_eb_bytes = vol->usable_leb_size; | ||
540 | vol->used_bytes = vol->used_ebs * vol->usable_leb_size; | ||
541 | } | ||
542 | |||
543 | paranoid_check_volumes(ubi); | ||
544 | return 0; | ||
545 | |||
546 | out_acc: | ||
547 | if (pebs > 0) { | ||
548 | spin_lock(&ubi->volumes_lock); | ||
549 | ubi->rsvd_pebs -= pebs; | ||
550 | ubi->avail_pebs += pebs; | ||
551 | spin_unlock(&ubi->volumes_lock); | ||
552 | } | ||
553 | out_free: | ||
554 | kfree(new_mapping); | ||
555 | return err; | ||
556 | } | ||
557 | |||
558 | /** | ||
559 | * ubi_add_volume - add volume. | ||
560 | * @ubi: UBI device description object | ||
561 | * @vol_id: volume ID | ||
562 | * | ||
563 | * This function adds an existin volume and initializes all its data | ||
564 | * structures. Returnes zero in case of success and a negative error code in | ||
565 | * case of failure. | ||
566 | */ | ||
567 | int ubi_add_volume(struct ubi_device *ubi, int vol_id) | ||
568 | { | ||
569 | int err; | ||
570 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
571 | |||
572 | dbg_msg("add volume %d", vol_id); | ||
573 | ubi_dbg_dump_vol_info(vol); | ||
574 | ubi_assert(vol); | ||
575 | |||
576 | /* Register character device for the volume */ | ||
577 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); | ||
578 | vol->cdev.owner = THIS_MODULE; | ||
579 | err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1); | ||
580 | if (err) { | ||
581 | ubi_err("cannot add character device for volume %d", vol_id); | ||
582 | return err; | ||
583 | } | ||
584 | |||
585 | err = ubi_create_gluebi(ubi, vol); | ||
586 | if (err) | ||
587 | goto out_cdev; | ||
588 | |||
589 | vol->dev.release = vol_release; | ||
590 | vol->dev.parent = &ubi->dev; | ||
591 | vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); | ||
592 | vol->dev.class = ubi_class; | ||
593 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); | ||
594 | err = device_register(&vol->dev); | ||
595 | if (err) | ||
596 | goto out_gluebi; | ||
597 | |||
598 | err = volume_sysfs_init(ubi, vol); | ||
599 | if (err) { | ||
600 | cdev_del(&vol->cdev); | ||
601 | err = ubi_destroy_gluebi(vol); | ||
602 | volume_sysfs_close(vol); | ||
603 | return err; | ||
604 | } | ||
605 | |||
606 | paranoid_check_volumes(ubi); | ||
607 | return 0; | ||
608 | |||
609 | out_gluebi: | ||
610 | err = ubi_destroy_gluebi(vol); | ||
611 | out_cdev: | ||
612 | cdev_del(&vol->cdev); | ||
613 | return err; | ||
614 | } | ||
615 | |||
616 | /** | ||
617 | * ubi_free_volume - free volume. | ||
618 | * @ubi: UBI device description object | ||
619 | * @vol_id: volume ID | ||
620 | * | ||
621 | * This function frees all resources for volume @vol_id but does not remove it. | ||
622 | * Used only when the UBI device is detached. | ||
623 | */ | ||
624 | void ubi_free_volume(struct ubi_device *ubi, int vol_id) | ||
625 | { | ||
626 | int err; | ||
627 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
628 | |||
629 | dbg_msg("free volume %d", vol_id); | ||
630 | ubi_assert(vol); | ||
631 | |||
632 | vol->removed = 1; | ||
633 | err = ubi_destroy_gluebi(vol); | ||
634 | ubi->volumes[vol_id] = NULL; | ||
635 | cdev_del(&vol->cdev); | ||
636 | volume_sysfs_close(vol); | ||
637 | } | ||
638 | |||
639 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID | ||
640 | |||
641 | /** | ||
642 | * paranoid_check_volume - check volume information. | ||
643 | * @ubi: UBI device description object | ||
644 | * @vol_id: volume ID | ||
645 | */ | ||
646 | static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id) | ||
647 | { | ||
648 | int idx = vol_id2idx(ubi, vol_id); | ||
649 | int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; | ||
650 | const struct ubi_volume *vol = ubi->volumes[idx]; | ||
651 | long long n; | ||
652 | const char *name; | ||
653 | |||
654 | reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); | ||
655 | |||
656 | if (!vol) { | ||
657 | if (reserved_pebs) { | ||
658 | ubi_err("no volume info, but volume exists"); | ||
659 | goto fail; | ||
660 | } | ||
661 | return; | ||
662 | } | ||
663 | |||
664 | if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || | ||
665 | vol->name_len < 0) { | ||
666 | ubi_err("negative values"); | ||
667 | goto fail; | ||
668 | } | ||
669 | if (vol->alignment > ubi->leb_size || vol->alignment == 0) { | ||
670 | ubi_err("bad alignment"); | ||
671 | goto fail; | ||
672 | } | ||
673 | |||
674 | n = vol->alignment % ubi->min_io_size; | ||
675 | if (vol->alignment != 1 && n) { | ||
676 | ubi_err("alignment is not multiple of min I/O unit"); | ||
677 | goto fail; | ||
678 | } | ||
679 | |||
680 | n = ubi->leb_size % vol->alignment; | ||
681 | if (vol->data_pad != n) { | ||
682 | ubi_err("bad data_pad, has to be %lld", n); | ||
683 | goto fail; | ||
684 | } | ||
685 | |||
686 | if (vol->vol_type != UBI_DYNAMIC_VOLUME && | ||
687 | vol->vol_type != UBI_STATIC_VOLUME) { | ||
688 | ubi_err("bad vol_type"); | ||
689 | goto fail; | ||
690 | } | ||
691 | |||
692 | if (vol->upd_marker != 0 && vol->upd_marker != 1) { | ||
693 | ubi_err("bad upd_marker"); | ||
694 | goto fail; | ||
695 | } | ||
696 | |||
697 | if (vol->upd_marker && vol->corrupted) { | ||
698 | dbg_err("update marker and corrupted simultaneously"); | ||
699 | goto fail; | ||
700 | } | ||
701 | |||
702 | if (vol->reserved_pebs > ubi->good_peb_count) { | ||
703 | ubi_err("too large reserved_pebs"); | ||
704 | goto fail; | ||
705 | } | ||
706 | |||
707 | n = ubi->leb_size - vol->data_pad; | ||
708 | if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { | ||
709 | ubi_err("bad usable_leb_size, has to be %lld", n); | ||
710 | goto fail; | ||
711 | } | ||
712 | |||
713 | if (vol->name_len > UBI_VOL_NAME_MAX) { | ||
714 | ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); | ||
715 | goto fail; | ||
716 | } | ||
717 | |||
718 | if (!vol->name) { | ||
719 | ubi_err("NULL volume name"); | ||
720 | goto fail; | ||
721 | } | ||
722 | |||
723 | n = strnlen(vol->name, vol->name_len + 1); | ||
724 | if (n != vol->name_len) { | ||
725 | ubi_err("bad name_len %lld", n); | ||
726 | goto fail; | ||
727 | } | ||
728 | |||
729 | n = vol->used_ebs * vol->usable_leb_size; | ||
730 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { | ||
731 | if (vol->corrupted != 0) { | ||
732 | ubi_err("corrupted dynamic volume"); | ||
733 | goto fail; | ||
734 | } | ||
735 | if (vol->used_ebs != vol->reserved_pebs) { | ||
736 | ubi_err("bad used_ebs"); | ||
737 | goto fail; | ||
738 | } | ||
739 | if (vol->last_eb_bytes != vol->usable_leb_size) { | ||
740 | ubi_err("bad last_eb_bytes"); | ||
741 | goto fail; | ||
742 | } | ||
743 | if (vol->used_bytes != n) { | ||
744 | ubi_err("bad used_bytes"); | ||
745 | goto fail; | ||
746 | } | ||
747 | } else { | ||
748 | if (vol->corrupted != 0 && vol->corrupted != 1) { | ||
749 | ubi_err("bad corrupted"); | ||
750 | goto fail; | ||
751 | } | ||
752 | if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { | ||
753 | ubi_err("bad used_ebs"); | ||
754 | goto fail; | ||
755 | } | ||
756 | if (vol->last_eb_bytes < 0 || | ||
757 | vol->last_eb_bytes > vol->usable_leb_size) { | ||
758 | ubi_err("bad last_eb_bytes"); | ||
759 | goto fail; | ||
760 | } | ||
761 | if (vol->used_bytes < 0 || vol->used_bytes > n || | ||
762 | vol->used_bytes < n - vol->usable_leb_size) { | ||
763 | ubi_err("bad used_bytes"); | ||
764 | goto fail; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment); | ||
769 | data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad); | ||
770 | name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len); | ||
771 | upd_marker = ubi->vtbl[vol_id].upd_marker; | ||
772 | name = &ubi->vtbl[vol_id].name[0]; | ||
773 | if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) | ||
774 | vol_type = UBI_DYNAMIC_VOLUME; | ||
775 | else | ||
776 | vol_type = UBI_STATIC_VOLUME; | ||
777 | |||
778 | if (alignment != vol->alignment || data_pad != vol->data_pad || | ||
779 | upd_marker != vol->upd_marker || vol_type != vol->vol_type || | ||
780 | name_len!= vol->name_len || strncmp(name, vol->name, name_len)) { | ||
781 | ubi_err("volume info is different"); | ||
782 | goto fail; | ||
783 | } | ||
784 | |||
785 | return; | ||
786 | |||
787 | fail: | ||
788 | ubi_err("paranoid check failed"); | ||
789 | ubi_dbg_dump_vol_info(vol); | ||
790 | ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); | ||
791 | BUG(); | ||
792 | } | ||
793 | |||
794 | /** | ||
795 | * paranoid_check_volumes - check information about all volumes. | ||
796 | * @ubi: UBI device description object | ||
797 | */ | ||
798 | static void paranoid_check_volumes(struct ubi_device *ubi) | ||
799 | { | ||
800 | int i; | ||
801 | |||
802 | mutex_lock(&ubi->vtbl_mutex); | ||
803 | spin_lock(&ubi->volumes_lock); | ||
804 | for (i = 0; i < ubi->vtbl_slots; i++) | ||
805 | paranoid_check_volume(ubi, i); | ||
806 | spin_unlock(&ubi->volumes_lock); | ||
807 | mutex_unlock(&ubi->vtbl_mutex); | ||
808 | } | ||
809 | #endif | ||