diff options
| author | Li Zefan <lizefan@huawei.com> | 2012-06-11 04:03:35 -0400 |
|---|---|---|
| committer | Chris Mason <chris.mason@oracle.com> | 2012-06-14 21:30:55 -0400 |
| commit | 6c282eb40ed6f64a51ff447707714df551d85b8e (patch) | |
| tree | 97d8a780a577d21c0f237f2140f3a129f40096bf | |
| parent | 7ddf5a42d311d74fd9f7373cb56def0843c219f8 (diff) | |
Btrfs: fix defrag regression
If a file has 3 small extents:
| ext1 | ext2 | ext3 |
Running "btrfs fi defrag" will only defrag the last two extents, if those
extent mappings hasn't been read into memory from disk.
This bug was introduced by commit 17ce6ef8d731af5edac8c39e806db4c7e1f6956f
("Btrfs: add a check to decide if we should defrag the range")
The cause is, that commit looked into previous and next extents using
lookup_extent_mapping() only.
While at it, remove the code that checks the previous extent, since
it's sufficient to check the next extent.
Signed-off-by: Li Zefan <lizefan@huawei.com>
| -rw-r--r-- | fs/btrfs/ioctl.c | 97 |
1 files changed, 49 insertions, 48 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index c5254dde1f0f..a98f7d252829 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -786,39 +786,57 @@ none: | |||
| 786 | return -ENOENT; | 786 | return -ENOENT; |
| 787 | } | 787 | } |
| 788 | 788 | ||
| 789 | /* | 789 | static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start) |
| 790 | * Validaty check of prev em and next em: | ||
| 791 | * 1) no prev/next em | ||
| 792 | * 2) prev/next em is an hole/inline extent | ||
| 793 | */ | ||
| 794 | static int check_adjacent_extents(struct inode *inode, struct extent_map *em) | ||
| 795 | { | 790 | { |
| 796 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 791 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
| 797 | struct extent_map *prev = NULL, *next = NULL; | 792 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
| 798 | int ret = 0; | 793 | struct extent_map *em; |
| 794 | u64 len = PAGE_CACHE_SIZE; | ||
| 799 | 795 | ||
| 796 | /* | ||
| 797 | * hopefully we have this extent in the tree already, try without | ||
| 798 | * the full extent lock | ||
| 799 | */ | ||
| 800 | read_lock(&em_tree->lock); | 800 | read_lock(&em_tree->lock); |
| 801 | prev = lookup_extent_mapping(em_tree, em->start - 1, (u64)-1); | 801 | em = lookup_extent_mapping(em_tree, start, len); |
| 802 | next = lookup_extent_mapping(em_tree, em->start + em->len, (u64)-1); | ||
| 803 | read_unlock(&em_tree->lock); | 802 | read_unlock(&em_tree->lock); |
| 804 | 803 | ||
| 805 | if ((!prev || prev->block_start >= EXTENT_MAP_LAST_BYTE) && | 804 | if (!em) { |
| 806 | (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)) | 805 | /* get the big lock and read metadata off disk */ |
| 807 | ret = 1; | 806 | lock_extent(io_tree, start, start + len - 1); |
| 808 | free_extent_map(prev); | 807 | em = btrfs_get_extent(inode, NULL, 0, start, len, 0); |
| 809 | free_extent_map(next); | 808 | unlock_extent(io_tree, start, start + len - 1); |
| 810 | 809 | ||
| 810 | if (IS_ERR(em)) | ||
| 811 | return NULL; | ||
| 812 | } | ||
| 813 | |||
| 814 | return em; | ||
| 815 | } | ||
| 816 | |||
| 817 | static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) | ||
| 818 | { | ||
| 819 | struct extent_map *next; | ||
| 820 | bool ret = true; | ||
| 821 | |||
| 822 | /* this is the last extent */ | ||
| 823 | if (em->start + em->len >= i_size_read(inode)) | ||
| 824 | return false; | ||
| 825 | |||
| 826 | next = defrag_lookup_extent(inode, em->start + em->len); | ||
| 827 | if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE) | ||
| 828 | ret = false; | ||
| 829 | |||
| 830 | free_extent_map(next); | ||
| 811 | return ret; | 831 | return ret; |
| 812 | } | 832 | } |
| 813 | 833 | ||
| 814 | static int should_defrag_range(struct inode *inode, u64 start, u64 len, | 834 | static int should_defrag_range(struct inode *inode, u64 start, int thresh, |
| 815 | int thresh, u64 *last_len, u64 *skip, | 835 | u64 *last_len, u64 *skip, u64 *defrag_end) |
| 816 | u64 *defrag_end) | ||
| 817 | { | 836 | { |
| 818 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 837 | struct extent_map *em; |
| 819 | struct extent_map *em = NULL; | ||
| 820 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
| 821 | int ret = 1; | 838 | int ret = 1; |
| 839 | bool next_mergeable = true; | ||
| 822 | 840 | ||
| 823 | /* | 841 | /* |
| 824 | * make sure that once we start defragging an extent, we keep on | 842 | * make sure that once we start defragging an extent, we keep on |
| @@ -829,23 +847,9 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
| 829 | 847 | ||
| 830 | *skip = 0; | 848 | *skip = 0; |
| 831 | 849 | ||
| 832 | /* | 850 | em = defrag_lookup_extent(inode, start); |
| 833 | * hopefully we have this extent in the tree already, try without | 851 | if (!em) |
| 834 | * the full extent lock | 852 | return 0; |
| 835 | */ | ||
| 836 | read_lock(&em_tree->lock); | ||
| 837 | em = lookup_extent_mapping(em_tree, start, len); | ||
| 838 | read_unlock(&em_tree->lock); | ||
| 839 | |||
| 840 | if (!em) { | ||
| 841 | /* get the big lock and read metadata off disk */ | ||
| 842 | lock_extent(io_tree, start, start + len - 1); | ||
| 843 | em = btrfs_get_extent(inode, NULL, 0, start, len, 0); | ||
| 844 | unlock_extent(io_tree, start, start + len - 1); | ||
| 845 | |||
| 846 | if (IS_ERR(em)) | ||
| 847 | return 0; | ||
| 848 | } | ||
| 849 | 853 | ||
| 850 | /* this will cover holes, and inline extents */ | 854 | /* this will cover holes, and inline extents */ |
| 851 | if (em->block_start >= EXTENT_MAP_LAST_BYTE) { | 855 | if (em->block_start >= EXTENT_MAP_LAST_BYTE) { |
| @@ -853,18 +857,15 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
| 853 | goto out; | 857 | goto out; |
| 854 | } | 858 | } |
| 855 | 859 | ||
| 856 | /* If we have nothing to merge with us, just skip. */ | 860 | next_mergeable = defrag_check_next_extent(inode, em); |
| 857 | if (check_adjacent_extents(inode, em)) { | ||
| 858 | ret = 0; | ||
| 859 | goto out; | ||
| 860 | } | ||
| 861 | 861 | ||
| 862 | /* | 862 | /* |
| 863 | * we hit a real extent, if it is big don't bother defragging it again | 863 | * we hit a real extent, if it is big or the next extent is not a |
| 864 | * real extent, don't bother defragging it | ||
| 864 | */ | 865 | */ |
| 865 | if ((*last_len == 0 || *last_len >= thresh) && em->len >= thresh) | 866 | if ((*last_len == 0 || *last_len >= thresh) && |
| 867 | (em->len >= thresh || !next_mergeable)) | ||
| 866 | ret = 0; | 868 | ret = 0; |
| 867 | |||
| 868 | out: | 869 | out: |
| 869 | /* | 870 | /* |
| 870 | * last_len ends up being a counter of how many bytes we've defragged. | 871 | * last_len ends up being a counter of how many bytes we've defragged. |
| @@ -1143,8 +1144,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
| 1143 | break; | 1144 | break; |
| 1144 | 1145 | ||
| 1145 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | 1146 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, |
| 1146 | PAGE_CACHE_SIZE, extent_thresh, | 1147 | extent_thresh, &last_len, &skip, |
| 1147 | &last_len, &skip, &defrag_end)) { | 1148 | &defrag_end)) { |
| 1148 | unsigned long next; | 1149 | unsigned long next; |
| 1149 | /* | 1150 | /* |
| 1150 | * the should_defrag function tells us how much to skip | 1151 | * the should_defrag function tells us how much to skip |
