1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#ifdef UBI_LINUX
24#include <linux/module.h>
25#include <linux/err.h>
26#include <asm/div64.h>
27#endif
28
29#include <ubi_uboot.h>
30#include "ubi.h"
31
32
33
34
35
36
37
38
39
40int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
41{
42 struct ubi_device *ubi;
43
44 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
45 return -EINVAL;
46
47 ubi = ubi_get_device(ubi_num);
48 if (!ubi)
49 return -ENODEV;
50
51 di->ubi_num = ubi->ubi_num;
52 di->leb_size = ubi->leb_size;
53 di->min_io_size = ubi->min_io_size;
54 di->ro_mode = ubi->ro_mode;
55 di->cdev = ubi->cdev.dev;
56
57 ubi_put_device(ubi);
58 return 0;
59}
60EXPORT_SYMBOL_GPL(ubi_get_device_info);
61
62
63
64
65
66
67void ubi_get_volume_info(struct ubi_volume_desc *desc,
68 struct ubi_volume_info *vi)
69{
70 const struct ubi_volume *vol = desc->vol;
71 const struct ubi_device *ubi = vol->ubi;
72
73 vi->vol_id = vol->vol_id;
74 vi->ubi_num = ubi->ubi_num;
75 vi->size = vol->reserved_pebs;
76 vi->used_bytes = vol->used_bytes;
77 vi->vol_type = vol->vol_type;
78 vi->corrupted = vol->corrupted;
79 vi->upd_marker = vol->upd_marker;
80 vi->alignment = vol->alignment;
81 vi->usable_leb_size = vol->usable_leb_size;
82 vi->name_len = vol->name_len;
83 vi->name = vol->name;
84 vi->cdev = vol->cdev.dev;
85}
86EXPORT_SYMBOL_GPL(ubi_get_volume_info);
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
107{
108 int err;
109 struct ubi_volume_desc *desc;
110 struct ubi_device *ubi;
111 struct ubi_volume *vol;
112
113 dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
114
115 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
116 return ERR_PTR(-EINVAL);
117
118 if (mode != UBI_READONLY && mode != UBI_READWRITE &&
119 mode != UBI_EXCLUSIVE)
120 return ERR_PTR(-EINVAL);
121
122
123
124
125 ubi = ubi_get_device(ubi_num);
126 if (!ubi)
127 return ERR_PTR(-ENODEV);
128
129 if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
130 err = -EINVAL;
131 goto out_put_ubi;
132 }
133
134 desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
135 if (!desc) {
136 err = -ENOMEM;
137 goto out_put_ubi;
138 }
139
140 err = -ENODEV;
141 if (!try_module_get(THIS_MODULE))
142 goto out_free;
143
144 spin_lock(&ubi->volumes_lock);
145 vol = ubi->volumes[vol_id];
146 if (!vol)
147 goto out_unlock;
148
149 err = -EBUSY;
150 switch (mode) {
151 case UBI_READONLY:
152 if (vol->exclusive)
153 goto out_unlock;
154 vol->readers += 1;
155 break;
156
157 case UBI_READWRITE:
158 if (vol->exclusive || vol->writers > 0)
159 goto out_unlock;
160 vol->writers += 1;
161 break;
162
163 case UBI_EXCLUSIVE:
164 if (vol->exclusive || vol->writers || vol->readers)
165 goto out_unlock;
166 vol->exclusive = 1;
167 break;
168 }
169 get_device(&vol->dev);
170 vol->ref_count += 1;
171 spin_unlock(&ubi->volumes_lock);
172
173 desc->vol = vol;
174 desc->mode = mode;
175
176 mutex_lock(&ubi->ckvol_mutex);
177 if (!vol->checked) {
178
179 err = ubi_check_volume(ubi, vol_id);
180 if (err < 0) {
181 mutex_unlock(&ubi->ckvol_mutex);
182 ubi_close_volume(desc);
183 return ERR_PTR(err);
184 }
185 if (err == 1) {
186 ubi_warn("volume %d on UBI device %d is corrupted",
187 vol_id, ubi->ubi_num);
188 vol->corrupted = 1;
189 }
190 vol->checked = 1;
191 }
192 mutex_unlock(&ubi->ckvol_mutex);
193
194 return desc;
195
196out_unlock:
197 spin_unlock(&ubi->volumes_lock);
198 module_put(THIS_MODULE);
199out_free:
200 kfree(desc);
201out_put_ubi:
202 ubi_put_device(ubi);
203 return ERR_PTR(err);
204}
205EXPORT_SYMBOL_GPL(ubi_open_volume);
206
207
208
209
210
211
212
213
214
215struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
216 int mode)
217{
218 int i, vol_id = -1, len;
219 struct ubi_device *ubi;
220 struct ubi_volume_desc *ret;
221
222 dbg_msg("open volume %s, mode %d", name, mode);
223
224 if (!name)
225 return ERR_PTR(-EINVAL);
226
227 len = strnlen(name, UBI_VOL_NAME_MAX + 1);
228 if (len > UBI_VOL_NAME_MAX)
229 return ERR_PTR(-EINVAL);
230
231 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
232 return ERR_PTR(-EINVAL);
233
234 ubi = ubi_get_device(ubi_num);
235 if (!ubi)
236 return ERR_PTR(-ENODEV);
237
238 spin_lock(&ubi->volumes_lock);
239
240 for (i = 0; i < ubi->vtbl_slots; i++) {
241 struct ubi_volume *vol = ubi->volumes[i];
242
243 if (vol && len == vol->name_len && !strcmp(name, vol->name)) {
244 vol_id = i;
245 break;
246 }
247 }
248 spin_unlock(&ubi->volumes_lock);
249
250 if (vol_id >= 0)
251 ret = ubi_open_volume(ubi_num, vol_id, mode);
252 else
253 ret = ERR_PTR(-ENODEV);
254
255
256
257
258
259 ubi_put_device(ubi);
260 return ret;
261}
262EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
263
264
265
266
267
268void ubi_close_volume(struct ubi_volume_desc *desc)
269{
270 struct ubi_volume *vol = desc->vol;
271 struct ubi_device *ubi = vol->ubi;
272
273 dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
274
275 spin_lock(&ubi->volumes_lock);
276 switch (desc->mode) {
277 case UBI_READONLY:
278 vol->readers -= 1;
279 break;
280 case UBI_READWRITE:
281 vol->writers -= 1;
282 break;
283 case UBI_EXCLUSIVE:
284 vol->exclusive = 0;
285 }
286 vol->ref_count -= 1;
287 spin_unlock(&ubi->volumes_lock);
288
289 kfree(desc);
290 put_device(&vol->dev);
291 ubi_put_device(ubi);
292 module_put(THIS_MODULE);
293}
294EXPORT_SYMBOL_GPL(ubi_close_volume);
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
324 int len, int check)
325{
326 struct ubi_volume *vol = desc->vol;
327 struct ubi_device *ubi = vol->ubi;
328 int err, vol_id = vol->vol_id;
329
330 dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
331
332 if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
333 lnum >= vol->used_ebs || offset < 0 || len < 0 ||
334 offset + len > vol->usable_leb_size)
335 return -EINVAL;
336
337 if (vol->vol_type == UBI_STATIC_VOLUME) {
338 if (vol->used_ebs == 0)
339
340 return 0;
341 if (lnum == vol->used_ebs - 1 &&
342 offset + len > vol->last_eb_bytes)
343 return -EINVAL;
344 }
345
346 if (vol->upd_marker)
347 return -EBADF;
348 if (len == 0)
349 return 0;
350
351 err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
352 if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
353 ubi_warn("mark volume %d as corrupted", vol_id);
354 vol->corrupted = 1;
355 }
356
357 return err;
358}
359EXPORT_SYMBOL_GPL(ubi_leb_read);
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
389 int offset, int len, int dtype)
390{
391 struct ubi_volume *vol = desc->vol;
392 struct ubi_device *ubi = vol->ubi;
393 int vol_id = vol->vol_id;
394
395 dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
396
397 if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
398 return -EINVAL;
399
400 if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
401 return -EROFS;
402
403 if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
404 offset + len > vol->usable_leb_size ||
405 offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
406 return -EINVAL;
407
408 if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
409 dtype != UBI_UNKNOWN)
410 return -EINVAL;
411
412 if (vol->upd_marker)
413 return -EBADF;
414
415 if (len == 0)
416 return 0;
417
418 return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
419}
420EXPORT_SYMBOL_GPL(ubi_leb_write);
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
439 int len, int dtype)
440{
441 struct ubi_volume *vol = desc->vol;
442 struct ubi_device *ubi = vol->ubi;
443 int vol_id = vol->vol_id;
444
445 dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
446
447 if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
448 return -EINVAL;
449
450 if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
451 return -EROFS;
452
453 if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
454 len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
455 return -EINVAL;
456
457 if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
458 dtype != UBI_UNKNOWN)
459 return -EINVAL;
460
461 if (vol->upd_marker)
462 return -EBADF;
463
464 if (len == 0)
465 return 0;
466
467 return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
468}
469EXPORT_SYMBOL_GPL(ubi_leb_change);
470
471
472
473
474
475
476
477
478
479
480
481
482
483int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
484{
485 struct ubi_volume *vol = desc->vol;
486 struct ubi_device *ubi = vol->ubi;
487 int err;
488
489 dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
490
491 if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
492 return -EROFS;
493
494 if (lnum < 0 || lnum >= vol->reserved_pebs)
495 return -EINVAL;
496
497 if (vol->upd_marker)
498 return -EBADF;
499
500 err = ubi_eba_unmap_leb(ubi, vol, lnum);
501 if (err)
502 return err;
503
504 return ubi_wl_flush(ubi);
505}
506EXPORT_SYMBOL_GPL(ubi_leb_erase);
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
545{
546 struct ubi_volume *vol = desc->vol;
547 struct ubi_device *ubi = vol->ubi;
548
549 dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
550
551 if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
552 return -EROFS;
553
554 if (lnum < 0 || lnum >= vol->reserved_pebs)
555 return -EINVAL;
556
557 if (vol->upd_marker)
558 return -EBADF;
559
560 return ubi_eba_unmap_leb(ubi, vol, lnum);
561}
562EXPORT_SYMBOL_GPL(ubi_leb_unmap);
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
582{
583 struct ubi_volume *vol = desc->vol;
584 struct ubi_device *ubi = vol->ubi;
585
586 dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
587
588 if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
589 return -EROFS;
590
591 if (lnum < 0 || lnum >= vol->reserved_pebs)
592 return -EINVAL;
593
594 if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
595 dtype != UBI_UNKNOWN)
596 return -EINVAL;
597
598 if (vol->upd_marker)
599 return -EBADF;
600
601 if (vol->eba_tbl[lnum] >= 0)
602 return -EBADMSG;
603
604 return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
605}
606EXPORT_SYMBOL_GPL(ubi_leb_map);
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
625{
626 struct ubi_volume *vol = desc->vol;
627
628 dbg_msg("test LEB %d:%d", vol->vol_id, lnum);
629
630 if (lnum < 0 || lnum >= vol->reserved_pebs)
631 return -EINVAL;
632
633 if (vol->upd_marker)
634 return -EBADF;
635
636 return vol->eba_tbl[lnum] >= 0;
637}
638EXPORT_SYMBOL_GPL(ubi_is_mapped);
639