diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 8b4573559dfebaeb0c2661393b993faab18043d4..4e761e957de8d928384446c7e9382162248a577f 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) int i, err; dev_t dev; - mutex_init(&ubi->volumes_mutex); - spin_lock_init(&ubi->volumes_lock); - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); /* @@ -623,6 +620,58 @@ static int io_init(struct ubi_device *ubi) return 0; } +/** + * autoresize - re-size the volume which has the "auto-resize" flag set. + * @ubi: UBI device description object + * @vol_id: ID of the volume to re-size + * + * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in + * the volume table to the largest possible size. See comments in ubi-header.h + * for more description of the flag. Returns zero in case of success and a + * negative error code in case of failure. + */ +static int autoresize(struct ubi_device *ubi, int vol_id) +{ + struct ubi_volume_desc desc; + struct ubi_volume *vol = ubi->volumes[vol_id]; + int err, old_reserved_pebs = vol->reserved_pebs; + + /* + * Clear the auto-resize flag in the volume in-memory copy of the + * volume table, and 'ubi_resize_volume()' will propogate this change + * to the flash. + */ + ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; + + if (ubi->avail_pebs == 0) { + struct ubi_vtbl_record vtbl_rec; + + /* + * No avalilable PEBs to re-size the volume, clear the flag on + * flash and exit. + */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], + sizeof(struct ubi_vtbl_record)); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + ubi_err("cannot clean auto-resize flag for volume %d", + vol_id); + } else { + desc.vol = vol; + err = ubi_resize_volume(&desc, + old_reserved_pebs + ubi->avail_pebs); + if (err) + ubi_err("cannot auto-resize volume %d", vol_id); + } + + if (err) + return err; + + ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + vol->name, old_reserved_pebs, vol->reserved_pebs); + return 0; +} + /** * ubi_attach_mtd_dev - attach an MTD device. * @mtd_dev: MTD device description object @@ -699,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi->mtd = mtd; ubi->ubi_num = ubi_num; ubi->vid_hdr_offset = vid_hdr_offset; + ubi->autoresize_vol_id = -1; + + mutex_init(&ubi->buf_mutex); + mutex_init(&ubi->ckvol_mutex); + mutex_init(&ubi->volumes_mutex); + spin_lock_init(&ubi->volumes_lock); dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", 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) if (err) goto out_free; - mutex_init(&ubi->buf_mutex); - mutex_init(&ubi->ckvol_mutex); ubi->peb_buf1 = vmalloc(ubi->peb_size); if (!ubi->peb_buf1) goto out_free; @@ -730,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) goto out_free; } + if (ubi->autoresize_vol_id != -1) { + err = autoresize(ubi, ubi->autoresize_vol_id); + if (err) + goto out_detach; + } + err = uif_init(ubi); if (err) goto out_detach; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c05c6e1abc7de001ec26fb1ed9535347b77a337..1f951e39c535669dc2f0ca323c229b4c98d68a64 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, { int err, pnum, vol_id = vol->vol_id; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -392,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, struct ubi_vid_hdr *vid_hdr; uint32_t uninitialized_var(crc); - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - err = leb_read_lock(ubi, vol_id, lnum); if (err) return err; @@ -618,9 +612,6 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, int err, pnum, tries = 0, vol_id = vol->vol_id; struct ubi_vid_hdr *vid_hdr; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -754,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, struct ubi_vid_hdr *vid_hdr; uint32_t crc; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; @@ -871,9 +859,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, struct ubi_vid_hdr *vid_hdr; uint32_t crc; - ubi_assert(ubi->ref_count > 0); - ubi_assert(vol->ref_count > 0); - if (ubi->ro_mode) return -EROFS; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 90cdcad83cbb71a91440c401248622ee60e2c1ea..a8cdbd0364fb7b44fa91f8a46fc6e6bb16c08a32 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -250,9 +250,11 @@ struct ubi_wl_entry; * @rsvd_pebs: count of reserved physical eraseblocks * @avail_pebs: count of available physical eraseblocks * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB - * handling + * handling * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling * + * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end + * of UBI ititializetion * @vtbl_slots: how many slots are available in the volume table * @vtbl_size: size of the volume table in bytes * @vtbl: in-RAM volume table copy @@ -333,12 +335,14 @@ struct ubi_device { int beb_rsvd_pebs; int beb_rsvd_level; + int autoresize_vol_id; int vtbl_slots; int vtbl_size; struct ubi_vtbl_record *vtbl; struct mutex volumes_mutex; int max_ec; + /* TODO: mean_ec is not updated run-time, fix */ int mean_ec; /* EBA unit's stuff */ diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 221ce70be569faf6718546aaa0073f5357d0a2d8..a3ca2257e6015e586ddcbfa513acb760b01afb08 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) dbg_msg("re-size volume %d to from %d to %d PEBs", vol_id, vol->reserved_pebs, reserved_pebs); - ubi_assert(desc->mode == UBI_EXCLUSIVE); - ubi_assert(vol == ubi->volumes[vol_id]); if (vol->vol_type == UBI_STATIC_VOLUME && reserved_pebs < vol->used_ebs) { diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 7a1a8a1da6103c67e77b0ff1bd17a5133acf5727..2fd9cf4cea7e4dfac93cdc36727ee983df9b8919 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, vol->name[vol->name_len] = '\0'; vol->vol_id = i; + if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { + /* Auto re-size flag may be set only for one volume */ + if (ubi->autoresize_vol_id != -1) { + ubi_err("more then one auto-resize volume (%d " + "and %d)", ubi->autoresize_vol_id, i); + return -EINVAL; + } + + ubi->autoresize_vol_id = i; + } + ubi_assert(!ubi->volumes[i]); ubi->volumes[i] = vol; ubi->vol_count += 1; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 1142aabcfc8ced0818224239bdb189f14a0928cb..8bfb7434c99300aa27abdc85c92530e1f68e4059 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) * Make sure all the works which have been done in parallel are * finished. */ - ubi_assert(ubi->ref_count > 0); down_write(&ubi->work_sem); up_write(&ubi->work_sem); diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h index 74efa77634790f6ab0ad4c1395f543f13211c304..69d5d7e22899133b8a6a59687e0b8508cbec2bdf 100644 --- a/include/mtd/ubi-header.h +++ b/include/mtd/ubi-header.h @@ -57,6 +57,43 @@ enum { UBI_VID_STATIC = 2 }; +/* + * Volume flags used in the volume table record. + * + * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume + * + * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume + * table. UBI automatically re-sizes the volume which has this flag and makes + * the volume to be of largest possible size. This means that if after the + * initialization UBI finds out that there are available physical eraseblocks + * present on the device, it automatically appends all of them to the volume + * (the physical eraseblocks reserved for bad eraseblocks handling and other + * reserved physical eraseblocks are not taken). So, if there is a volume with + * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical + * eraseblocks will be zero after UBI is loaded, because all of them will be + * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared + * after the volume had been initialized. + * + * The auto-resize feature is useful for device production purposes. For + * example, different NAND flash chips may have different amount of initial bad + * eraseblocks, depending of particular chip instance. Manufacturers of NAND + * chips usually guarantee that the amount of initial bad eraseblocks does not + * exceed certain percent, e.g. 2%. When one creates an UBI image which will be + * flashed to the end devices in production, he does not know the exact amount + * of good physical eraseblocks the NAND chip on the device will have, but this + * number is required to calculate the volume sized and put them to the volume + * table of the UBI image. In this case, one of the volumes (e.g., the one + * which will store the root file system) is marked as "auto-resizable", and + * UBI will adjust its size on the first boot if needed. + * + * Note, first UBI reserves some amount of physical eraseblocks for bad + * eraseblock handling, and then re-sizes the volume, not vice-versa. This + * means that the pool of reserved physical eraseblocks will always be present. + */ +enum { + UBI_VTBL_AUTORESIZE_FLG = 0x01, +}; + /* * Compatibility constants used by internal volumes. * @@ -289,7 +326,8 @@ struct ubi_vid_hdr { * @upd_marker: if volume update was started but not finished * @name_len: volume name length * @name: the volume name - * @padding2: reserved, zeroes + * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) + * @padding: reserved, zeroes * @crc: a CRC32 checksum of the record * * The volume table records are stored in the volume table, which is stored in @@ -324,7 +362,8 @@ struct ubi_vtbl_record { __u8 upd_marker; __be16 name_len; __u8 name[UBI_VOL_NAME_MAX+1]; - __u8 padding2[24]; + __u8 flags; + __u8 padding[23]; __be32 crc; } __attribute__ ((packed));