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 | |
| 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>
| -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, |
