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