aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-01-16 08:44:24 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-01-25 09:41:24 -0500
commit4ccf8cffa963c7b5bdc6d455ea9417084ee49aa8 (patch)
treea7281874dc9298b3d7eca2d1e4cb22c326625382 /drivers/mtd
parent896c0c06aa30147630e9a75949b6ae2014c841fc (diff)
UBI: add auto-resize feature
The problem: NAND flashes have different amount of initial bad physical eraseblocks (marked as bad by the manufacturer). For example, for 256MiB Samsung OneNAND flash there might be from 0 to 40 bad initial eraseblocks, which is about 2%. When UBI is used as the base system, one needs to know the exact amount of good physical eraseblocks, because this number is needed to create the UBI image which is put to the devices during production. But this number is not know, which forces us to use the minimum number of good physical eraseblocks. And UBI additionally reserves some percentage of physical eraseblocks for bad block handling (default is 1%), so we have 1-3% of PEBs reserved at the end, depending on the amount of initial bad PEBs. But it is desired to always have 1% (or more, depending on the configuration). Solution: this patch adds an "auto-resize" flag to the volume table. The volume which has the "auto-resize" flag will automatically be re-sized (enlarged) on the first UBI initialization. UBI clears the flag when the volume is re-sized. Only one volume may have the "auto-resize" flag. So, the production UBI image may have one volume with "auto-resize" flag set, and its size is automatically adjusted on the first boot of the device. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/ubi/build.c69
-rw-r--r--drivers/mtd/ubi/eba.c15
-rw-r--r--drivers/mtd/ubi/ubi.h6
-rw-r--r--drivers/mtd/ubi/vmt.c2
-rw-r--r--drivers/mtd/ubi/vtbl.c11
-rw-r--r--drivers/mtd/ubi/wl.c1
6 files changed, 80 insertions, 24 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 8b4573559dfe..4e761e957de8 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 */
633static 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 7c05c6e1abc7..1f951e39c535 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 90cdcad83cbb..a8cdbd0364fb 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 221ce70be569..a3ca2257e601 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 7a1a8a1da610..2fd9cf4cea7e 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 1142aabcfc8c..8bfb7434c993 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