diff options
-rw-r--r-- | drivers/mtd/ubi/build.c | 69 | ||||
-rw-r--r-- | drivers/mtd/ubi/eba.c | 15 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 6 | ||||
-rw-r--r-- | drivers/mtd/ubi/vmt.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/vtbl.c | 11 | ||||
-rw-r--r-- | drivers/mtd/ubi/wl.c | 1 | ||||
-rw-r--r-- | include/mtd/ubi-header.h | 43 |
7 files changed, 121 insertions, 26 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8b4573559df..4e761e957de 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -366,9 +366,6 @@ static int uif_init(struct ubi_device *ubi) | |||
366 | int i, err; | 366 | int i, err; |
367 | dev_t dev; | 367 | dev_t dev; |
368 | 368 | ||
369 | mutex_init(&ubi->volumes_mutex); | ||
370 | spin_lock_init(&ubi->volumes_lock); | ||
371 | |||
372 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); | 369 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); |
373 | 370 | ||
374 | /* | 371 | /* |
@@ -624,6 +621,58 @@ static int io_init(struct ubi_device *ubi) | |||
624 | } | 621 | } |
625 | 622 | ||
626 | /** | 623 | /** |
624 | * autoresize - re-size the volume which has the "auto-resize" flag set. | ||
625 | * @ubi: UBI device description object | ||
626 | * @vol_id: ID of the volume to re-size | ||
627 | * | ||
628 | * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in | ||
629 | * the volume table to the largest possible size. See comments in ubi-header.h | ||
630 | * for more description of the flag. Returns zero in case of success and a | ||
631 | * negative error code in case of failure. | ||
632 | */ | ||
633 | static int autoresize(struct ubi_device *ubi, int vol_id) | ||
634 | { | ||
635 | struct ubi_volume_desc desc; | ||
636 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
637 | int err, old_reserved_pebs = vol->reserved_pebs; | ||
638 | |||
639 | /* | ||
640 | * Clear the auto-resize flag in the volume in-memory copy of the | ||
641 | * volume table, and 'ubi_resize_volume()' will propogate this change | ||
642 | * to the flash. | ||
643 | */ | ||
644 | ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; | ||
645 | |||
646 | if (ubi->avail_pebs == 0) { | ||
647 | struct ubi_vtbl_record vtbl_rec; | ||
648 | |||
649 | /* | ||
650 | * No avalilable PEBs to re-size the volume, clear the flag on | ||
651 | * flash and exit. | ||
652 | */ | ||
653 | memcpy(&vtbl_rec, &ubi->vtbl[vol_id], | ||
654 | sizeof(struct ubi_vtbl_record)); | ||
655 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); | ||
656 | if (err) | ||
657 | ubi_err("cannot clean auto-resize flag for volume %d", | ||
658 | vol_id); | ||
659 | } else { | ||
660 | desc.vol = vol; | ||
661 | err = ubi_resize_volume(&desc, | ||
662 | old_reserved_pebs + ubi->avail_pebs); | ||
663 | if (err) | ||
664 | ubi_err("cannot auto-resize volume %d", vol_id); | ||
665 | } | ||
666 | |||
667 | if (err) | ||
668 | return err; | ||
669 | |||
670 | ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, | ||
671 | vol->name, old_reserved_pebs, vol->reserved_pebs); | ||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | /** | ||
627 | * ubi_attach_mtd_dev - attach an MTD device. | 676 | * ubi_attach_mtd_dev - attach an MTD device. |
628 | * @mtd_dev: MTD device description object | 677 | * @mtd_dev: MTD device description object |
629 | * @ubi_num: number to assign to the new UBI device | 678 | * @ubi_num: number to assign to the new UBI device |
@@ -699,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
699 | ubi->mtd = mtd; | 748 | ubi->mtd = mtd; |
700 | ubi->ubi_num = ubi_num; | 749 | ubi->ubi_num = ubi_num; |
701 | ubi->vid_hdr_offset = vid_hdr_offset; | 750 | ubi->vid_hdr_offset = vid_hdr_offset; |
751 | ubi->autoresize_vol_id = -1; | ||
752 | |||
753 | mutex_init(&ubi->buf_mutex); | ||
754 | mutex_init(&ubi->ckvol_mutex); | ||
755 | mutex_init(&ubi->volumes_mutex); | ||
756 | spin_lock_init(&ubi->volumes_lock); | ||
702 | 757 | ||
703 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", | 758 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", |
704 | mtd->index, ubi_num, vid_hdr_offset); | 759 | mtd->index, ubi_num, vid_hdr_offset); |
@@ -707,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
707 | if (err) | 762 | if (err) |
708 | goto out_free; | 763 | goto out_free; |
709 | 764 | ||
710 | mutex_init(&ubi->buf_mutex); | ||
711 | mutex_init(&ubi->ckvol_mutex); | ||
712 | ubi->peb_buf1 = vmalloc(ubi->peb_size); | 765 | ubi->peb_buf1 = vmalloc(ubi->peb_size); |
713 | if (!ubi->peb_buf1) | 766 | if (!ubi->peb_buf1) |
714 | goto out_free; | 767 | goto out_free; |
@@ -730,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
730 | goto out_free; | 783 | goto out_free; |
731 | } | 784 | } |
732 | 785 | ||
786 | if (ubi->autoresize_vol_id != -1) { | ||
787 | err = autoresize(ubi, ubi->autoresize_vol_id); | ||
788 | if (err) | ||
789 | goto out_detach; | ||
790 | } | ||
791 | |||
733 | err = uif_init(ubi); | 792 | err = uif_init(ubi); |
734 | if (err) | 793 | if (err) |
735 | goto out_detach; | 794 | goto out_detach; |
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c05c6e1abc..1f951e39c53 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -341,9 +341,6 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, | |||
341 | { | 341 | { |
342 | int err, pnum, vol_id = vol->vol_id; | 342 | int err, pnum, vol_id = vol->vol_id; |
343 | 343 | ||
344 | ubi_assert(ubi->ref_count > 0); | ||
345 | ubi_assert(vol->ref_count > 0); | ||
346 | |||
347 | if (ubi->ro_mode) | 344 | if (ubi->ro_mode) |
348 | return -EROFS; | 345 | return -EROFS; |
349 | 346 | ||
@@ -392,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, | |||
392 | struct ubi_vid_hdr *vid_hdr; | 389 | struct ubi_vid_hdr *vid_hdr; |
393 | uint32_t uninitialized_var(crc); | 390 | uint32_t uninitialized_var(crc); |
394 | 391 | ||
395 | ubi_assert(ubi->ref_count > 0); | ||
396 | ubi_assert(vol->ref_count > 0); | ||
397 | |||
398 | err = leb_read_lock(ubi, vol_id, lnum); | 392 | err = leb_read_lock(ubi, vol_id, lnum); |
399 | if (err) | 393 | if (err) |
400 | return err; | 394 | return err; |
@@ -618,9 +612,6 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, | |||
618 | int err, pnum, tries = 0, vol_id = vol->vol_id; | 612 | int err, pnum, tries = 0, vol_id = vol->vol_id; |
619 | struct ubi_vid_hdr *vid_hdr; | 613 | struct ubi_vid_hdr *vid_hdr; |
620 | 614 | ||
621 | ubi_assert(ubi->ref_count > 0); | ||
622 | ubi_assert(vol->ref_count > 0); | ||
623 | |||
624 | if (ubi->ro_mode) | 615 | if (ubi->ro_mode) |
625 | return -EROFS; | 616 | return -EROFS; |
626 | 617 | ||
@@ -754,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, | |||
754 | struct ubi_vid_hdr *vid_hdr; | 745 | struct ubi_vid_hdr *vid_hdr; |
755 | uint32_t crc; | 746 | uint32_t crc; |
756 | 747 | ||
757 | ubi_assert(ubi->ref_count > 0); | ||
758 | ubi_assert(vol->ref_count > 0); | ||
759 | |||
760 | if (ubi->ro_mode) | 748 | if (ubi->ro_mode) |
761 | return -EROFS; | 749 | return -EROFS; |
762 | 750 | ||
@@ -871,9 +859,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, | |||
871 | struct ubi_vid_hdr *vid_hdr; | 859 | struct ubi_vid_hdr *vid_hdr; |
872 | uint32_t crc; | 860 | uint32_t crc; |
873 | 861 | ||
874 | ubi_assert(ubi->ref_count > 0); | ||
875 | ubi_assert(vol->ref_count > 0); | ||
876 | |||
877 | if (ubi->ro_mode) | 862 | if (ubi->ro_mode) |
878 | return -EROFS; | 863 | return -EROFS; |
879 | 864 | ||
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 90cdcad83cb..a8cdbd0364f 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
@@ -250,9 +250,11 @@ struct ubi_wl_entry; | |||
250 | * @rsvd_pebs: count of reserved physical eraseblocks | 250 | * @rsvd_pebs: count of reserved physical eraseblocks |
251 | * @avail_pebs: count of available physical eraseblocks | 251 | * @avail_pebs: count of available physical eraseblocks |
252 | * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB | 252 | * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB |
253 | * handling | 253 | * handling |
254 | * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling | 254 | * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling |
255 | * | 255 | * |
256 | * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end | ||
257 | * of UBI ititializetion | ||
256 | * @vtbl_slots: how many slots are available in the volume table | 258 | * @vtbl_slots: how many slots are available in the volume table |
257 | * @vtbl_size: size of the volume table in bytes | 259 | * @vtbl_size: size of the volume table in bytes |
258 | * @vtbl: in-RAM volume table copy | 260 | * @vtbl: in-RAM volume table copy |
@@ -333,12 +335,14 @@ struct ubi_device { | |||
333 | int beb_rsvd_pebs; | 335 | int beb_rsvd_pebs; |
334 | int beb_rsvd_level; | 336 | int beb_rsvd_level; |
335 | 337 | ||
338 | int autoresize_vol_id; | ||
336 | int vtbl_slots; | 339 | int vtbl_slots; |
337 | int vtbl_size; | 340 | int vtbl_size; |
338 | struct ubi_vtbl_record *vtbl; | 341 | struct ubi_vtbl_record *vtbl; |
339 | struct mutex volumes_mutex; | 342 | struct mutex volumes_mutex; |
340 | 343 | ||
341 | int max_ec; | 344 | int max_ec; |
345 | /* TODO: mean_ec is not updated run-time, fix */ | ||
342 | int mean_ec; | 346 | int mean_ec; |
343 | 347 | ||
344 | /* EBA unit's stuff */ | 348 | /* EBA unit's stuff */ |
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 221ce70be56..a3ca2257e60 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c | |||
@@ -497,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | |||
497 | 497 | ||
498 | dbg_msg("re-size volume %d to from %d to %d PEBs", | 498 | dbg_msg("re-size volume %d to from %d to %d PEBs", |
499 | vol_id, vol->reserved_pebs, reserved_pebs); | 499 | vol_id, vol->reserved_pebs, reserved_pebs); |
500 | ubi_assert(desc->mode == UBI_EXCLUSIVE); | ||
501 | ubi_assert(vol == ubi->volumes[vol_id]); | ||
502 | 500 | ||
503 | if (vol->vol_type == UBI_STATIC_VOLUME && | 501 | if (vol->vol_type == UBI_STATIC_VOLUME && |
504 | reserved_pebs < vol->used_ebs) { | 502 | reserved_pebs < vol->used_ebs) { |
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 7a1a8a1da61..2fd9cf4cea7 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
@@ -514,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, | |||
514 | vol->name[vol->name_len] = '\0'; | 514 | vol->name[vol->name_len] = '\0'; |
515 | vol->vol_id = i; | 515 | vol->vol_id = i; |
516 | 516 | ||
517 | if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { | ||
518 | /* Auto re-size flag may be set only for one volume */ | ||
519 | if (ubi->autoresize_vol_id != -1) { | ||
520 | ubi_err("more then one auto-resize volume (%d " | ||
521 | "and %d)", ubi->autoresize_vol_id, i); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | ubi->autoresize_vol_id = i; | ||
526 | } | ||
527 | |||
517 | ubi_assert(!ubi->volumes[i]); | 528 | ubi_assert(!ubi->volumes[i]); |
518 | ubi->volumes[i] = vol; | 529 | ubi->volumes[i] = vol; |
519 | ubi->vol_count += 1; | 530 | ubi->vol_count += 1; |
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 1142aabcfc8..8bfb7434c99 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c | |||
@@ -1303,7 +1303,6 @@ int ubi_wl_flush(struct ubi_device *ubi) | |||
1303 | * Make sure all the works which have been done in parallel are | 1303 | * Make sure all the works which have been done in parallel are |
1304 | * finished. | 1304 | * finished. |
1305 | */ | 1305 | */ |
1306 | ubi_assert(ubi->ref_count > 0); | ||
1307 | down_write(&ubi->work_sem); | 1306 | down_write(&ubi->work_sem); |
1308 | up_write(&ubi->work_sem); | 1307 | up_write(&ubi->work_sem); |
1309 | 1308 | ||
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h index 74efa776347..69d5d7e2289 100644 --- a/include/mtd/ubi-header.h +++ b/include/mtd/ubi-header.h | |||
@@ -58,6 +58,43 @@ enum { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Volume flags used in the volume table record. | ||
62 | * | ||
63 | * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume | ||
64 | * | ||
65 | * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume | ||
66 | * table. UBI automatically re-sizes the volume which has this flag and makes | ||
67 | * the volume to be of largest possible size. This means that if after the | ||
68 | * initialization UBI finds out that there are available physical eraseblocks | ||
69 | * present on the device, it automatically appends all of them to the volume | ||
70 | * (the physical eraseblocks reserved for bad eraseblocks handling and other | ||
71 | * reserved physical eraseblocks are not taken). So, if there is a volume with | ||
72 | * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical | ||
73 | * eraseblocks will be zero after UBI is loaded, because all of them will be | ||
74 | * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared | ||
75 | * after the volume had been initialized. | ||
76 | * | ||
77 | * The auto-resize feature is useful for device production purposes. For | ||
78 | * example, different NAND flash chips may have different amount of initial bad | ||
79 | * eraseblocks, depending of particular chip instance. Manufacturers of NAND | ||
80 | * chips usually guarantee that the amount of initial bad eraseblocks does not | ||
81 | * exceed certain percent, e.g. 2%. When one creates an UBI image which will be | ||
82 | * flashed to the end devices in production, he does not know the exact amount | ||
83 | * of good physical eraseblocks the NAND chip on the device will have, but this | ||
84 | * number is required to calculate the volume sized and put them to the volume | ||
85 | * table of the UBI image. In this case, one of the volumes (e.g., the one | ||
86 | * which will store the root file system) is marked as "auto-resizable", and | ||
87 | * UBI will adjust its size on the first boot if needed. | ||
88 | * | ||
89 | * Note, first UBI reserves some amount of physical eraseblocks for bad | ||
90 | * eraseblock handling, and then re-sizes the volume, not vice-versa. This | ||
91 | * means that the pool of reserved physical eraseblocks will always be present. | ||
92 | */ | ||
93 | enum { | ||
94 | UBI_VTBL_AUTORESIZE_FLG = 0x01, | ||
95 | }; | ||
96 | |||
97 | /* | ||
61 | * Compatibility constants used by internal volumes. | 98 | * Compatibility constants used by internal volumes. |
62 | * | 99 | * |
63 | * @UBI_COMPAT_DELETE: delete this internal volume before anything is written | 100 | * @UBI_COMPAT_DELETE: delete this internal volume before anything is written |
@@ -289,7 +326,8 @@ struct ubi_vid_hdr { | |||
289 | * @upd_marker: if volume update was started but not finished | 326 | * @upd_marker: if volume update was started but not finished |
290 | * @name_len: volume name length | 327 | * @name_len: volume name length |
291 | * @name: the volume name | 328 | * @name: the volume name |
292 | * @padding2: reserved, zeroes | 329 | * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) |
330 | * @padding: reserved, zeroes | ||
293 | * @crc: a CRC32 checksum of the record | 331 | * @crc: a CRC32 checksum of the record |
294 | * | 332 | * |
295 | * The volume table records are stored in the volume table, which is stored in | 333 | * The volume table records are stored in the volume table, which is stored in |
@@ -324,7 +362,8 @@ struct ubi_vtbl_record { | |||
324 | __u8 upd_marker; | 362 | __u8 upd_marker; |
325 | __be16 name_len; | 363 | __be16 name_len; |
326 | __u8 name[UBI_VOL_NAME_MAX+1]; | 364 | __u8 name[UBI_VOL_NAME_MAX+1]; |
327 | __u8 padding2[24]; | 365 | __u8 flags; |
366 | __u8 padding[23]; | ||
328 | __be32 crc; | 367 | __be32 crc; |
329 | } __attribute__ ((packed)); | 368 | } __attribute__ ((packed)); |
330 | 369 | ||