diff options
author | Matthew L. Creech <mlcreech@gmail.com> | 2011-05-06 18:58:22 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-05-16 07:12:15 -0400 |
commit | 6554a6578131a217d4ea6d779a62f120081a2e8b (patch) | |
tree | 6be11a0c552de1cc91af01e0011badc4ca185b39 /fs/ubifs | |
parent | 9f58d3503a1368673609db1962e4a584261b62eb (diff) |
UBIFS: add the fixup function
This patch adds the 'ubifs_fixup_free_space()' function which scans all
LEBs in the filesystem for those that are in-use but have one or more
empty pages, then re-maps the LEBs in order to erase the empty portions.
Afterward it removes the "space_fixup" flag from the UBIFS superblock.
Artem: massaged the patch
Signed-off-by: Matthew L. Creech <mlcreech@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'fs/ubifs')
-rw-r--r-- | fs/ubifs/sb.c | 149 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 1 |
2 files changed, 150 insertions, 0 deletions
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index 93d69289d6f4..c606f010e8df 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c | |||
@@ -652,3 +652,152 @@ out: | |||
652 | kfree(sup); | 652 | kfree(sup); |
653 | return err; | 653 | return err; |
654 | } | 654 | } |
655 | |||
656 | /** | ||
657 | * fixup_leb - fixup/unmap an LEB containing free space. | ||
658 | * @c: UBIFS file-system description object | ||
659 | * @lnum: the LEB number to fix up | ||
660 | * @len: number of used bytes in LEB (starting at offset 0) | ||
661 | * | ||
662 | * This function reads the contents of the given LEB number @lnum, then fixes | ||
663 | * it up, so that empty min. I/O units in the end of LEB are actually erased on | ||
664 | * flash (rather than being just all-0xff real data). If the LEB is completely | ||
665 | * empty, it is simply unmapped. | ||
666 | */ | ||
667 | static int fixup_leb(struct ubifs_info *c, int lnum, int len) | ||
668 | { | ||
669 | int err; | ||
670 | |||
671 | ubifs_assert(len >= 0); | ||
672 | ubifs_assert(len % c->min_io_size == 0); | ||
673 | ubifs_assert(len < c->leb_size); | ||
674 | |||
675 | if (len == 0) { | ||
676 | dbg_mnt("unmap empty LEB %d", lnum); | ||
677 | return ubi_leb_unmap(c->ubi, lnum); | ||
678 | } | ||
679 | |||
680 | dbg_mnt("fixup LEB %d, data len %d", lnum, len); | ||
681 | err = ubi_read(c->ubi, lnum, c->sbuf, 0, len); | ||
682 | if (err) | ||
683 | return err; | ||
684 | |||
685 | return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * fixup_free_space - find & remap all LEBs containing free space. | ||
690 | * @c: UBIFS file-system description object | ||
691 | * | ||
692 | * This function walks through all LEBs in the filesystem and fiexes up those | ||
693 | * containing free/empty space. | ||
694 | */ | ||
695 | static int fixup_free_space(struct ubifs_info *c) | ||
696 | { | ||
697 | int lnum, err = 0; | ||
698 | struct ubifs_lprops *lprops; | ||
699 | |||
700 | ubifs_get_lprops(c); | ||
701 | |||
702 | /* Fixup LEBs in the master area */ | ||
703 | for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) { | ||
704 | err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz); | ||
705 | if (err) | ||
706 | goto out; | ||
707 | } | ||
708 | |||
709 | /* Unmap unused log LEBs */ | ||
710 | lnum = ubifs_next_log_lnum(c, c->lhead_lnum); | ||
711 | while (lnum != c->ltail_lnum) { | ||
712 | err = fixup_leb(c, lnum, 0); | ||
713 | if (err) | ||
714 | goto out; | ||
715 | lnum = ubifs_next_log_lnum(c, lnum); | ||
716 | } | ||
717 | |||
718 | /* Fixup the current log head */ | ||
719 | err = fixup_leb(c, c->lhead_lnum, c->lhead_offs); | ||
720 | if (err) | ||
721 | goto out; | ||
722 | |||
723 | /* Fixup LEBs in the LPT area */ | ||
724 | for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) { | ||
725 | int free = c->ltab[lnum - c->lpt_first].free; | ||
726 | |||
727 | if (free > 0) { | ||
728 | err = fixup_leb(c, lnum, c->leb_size - free); | ||
729 | if (err) | ||
730 | goto out; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | /* Unmap LEBs in the orphans area */ | ||
735 | for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { | ||
736 | err = fixup_leb(c, lnum, 0); | ||
737 | if (err) | ||
738 | goto out; | ||
739 | } | ||
740 | |||
741 | /* Fixup LEBs in the main area */ | ||
742 | for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) { | ||
743 | lprops = ubifs_lpt_lookup(c, lnum); | ||
744 | if (IS_ERR(lprops)) { | ||
745 | err = PTR_ERR(lprops); | ||
746 | goto out; | ||
747 | } | ||
748 | |||
749 | if (lprops->free > 0) { | ||
750 | err = fixup_leb(c, lnum, c->leb_size - lprops->free); | ||
751 | if (err) | ||
752 | goto out; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | out: | ||
757 | ubifs_release_lprops(c); | ||
758 | return err; | ||
759 | } | ||
760 | |||
761 | /** | ||
762 | * ubifs_fixup_free_space - find & fix all LEBs with free space. | ||
763 | * @c: UBIFS file-system description object | ||
764 | * | ||
765 | * This function fixes up LEBs containing free space on first mount, if the | ||
766 | * appropriate flag was set when the FS was created. Each LEB with one or more | ||
767 | * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure | ||
768 | * the free space is actually erased. E.g., this is necessary for some NAND | ||
769 | * chips, since the free space may have been programmed like real "0xff" data | ||
770 | * (generating a non-0xff ECC), causing future writes to the not-really-erased | ||
771 | * NAND pages to behave badly. After the space is fixed up, the superblock flag | ||
772 | * is cleared, so that this is skipped for all future mounts. | ||
773 | */ | ||
774 | int ubifs_fixup_free_space(struct ubifs_info *c) | ||
775 | { | ||
776 | int err; | ||
777 | struct ubifs_sb_node *sup; | ||
778 | |||
779 | ubifs_assert(c->space_fixup); | ||
780 | ubifs_assert(!c->ro_mount); | ||
781 | |||
782 | ubifs_msg("start fixing up free space"); | ||
783 | |||
784 | err = fixup_free_space(c); | ||
785 | if (err) | ||
786 | return err; | ||
787 | |||
788 | sup = ubifs_read_sb_node(c); | ||
789 | if (IS_ERR(sup)) | ||
790 | return PTR_ERR(sup); | ||
791 | |||
792 | /* Free-space fixup is no longer required */ | ||
793 | c->space_fixup = 0; | ||
794 | sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP); | ||
795 | |||
796 | err = ubifs_write_sb_node(c, sup); | ||
797 | kfree(sup); | ||
798 | if (err) | ||
799 | return err; | ||
800 | |||
801 | ubifs_msg("free space fixup complete"); | ||
802 | return err; | ||
803 | } | ||
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 8e27553e9655..93d1412a06f0 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -1633,6 +1633,7 @@ int ubifs_write_master(struct ubifs_info *c); | |||
1633 | int ubifs_read_superblock(struct ubifs_info *c); | 1633 | int ubifs_read_superblock(struct ubifs_info *c); |
1634 | struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); | 1634 | struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); |
1635 | int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); | 1635 | int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); |
1636 | int ubifs_fixup_free_space(struct ubifs_info *c); | ||
1636 | 1637 | ||
1637 | /* replay.c */ | 1638 | /* replay.c */ |
1638 | int ubifs_validate_entry(struct ubifs_info *c, | 1639 | int ubifs_validate_entry(struct ubifs_info *c, |