aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-07-25 07:22:36 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:04:35 -0400
commit9974090bdd7ac310d99a8ce6da7d6a19b3099ff9 (patch)
treed5560cd2d7d698737b358afc718b36fdec7aa1dd /fs/btrfs/extent_io.c
parent883d0de485222715929f7b7e2a9a34dc9b9b2be2 (diff)
Btrfs: batch the extent state operation when reading pages
In the past, we cached the checksum value in the extent state object, so we had to split the extent state object by the block size, or we had no space to keep this checksum value. But it increased the lock contention of the extent state tree. Now we removed this limit by caching the checksum into the bio object, so it is unnecessary to do the extent state operations by the block size, we can do it in batches, in this way, we can reduce the lock contention of the extent state tree. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r--fs/btrfs/extent_io.c135
1 files changed, 107 insertions, 28 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 0a77b48c93e5..0d40d082f0c7 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2726,11 +2726,11 @@ void set_page_extent_mapped(struct page *page)
2726 * handlers) 2726 * handlers)
2727 * XXX JDM: This needs looking at to ensure proper page locking 2727 * XXX JDM: This needs looking at to ensure proper page locking
2728 */ 2728 */
2729static int __extent_read_full_page(struct extent_io_tree *tree, 2729static int __do_readpage(struct extent_io_tree *tree,
2730 struct page *page, 2730 struct page *page,
2731 get_extent_t *get_extent, 2731 get_extent_t *get_extent,
2732 struct bio **bio, int mirror_num, 2732 struct bio **bio, int mirror_num,
2733 unsigned long *bio_flags, int rw) 2733 unsigned long *bio_flags, int rw)
2734{ 2734{
2735 struct inode *inode = page->mapping->host; 2735 struct inode *inode = page->mapping->host;
2736 u64 start = page_offset(page); 2736 u64 start = page_offset(page);
@@ -2744,7 +2744,6 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
2744 sector_t sector; 2744 sector_t sector;
2745 struct extent_map *em; 2745 struct extent_map *em;
2746 struct block_device *bdev; 2746 struct block_device *bdev;
2747 struct btrfs_ordered_extent *ordered;
2748 int ret; 2747 int ret;
2749 int nr = 0; 2748 int nr = 0;
2750 size_t pg_offset = 0; 2749 size_t pg_offset = 0;
@@ -2755,24 +2754,15 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
2755 2754
2756 set_page_extent_mapped(page); 2755 set_page_extent_mapped(page);
2757 2756
2757 end = page_end;
2758 if (!PageUptodate(page)) { 2758 if (!PageUptodate(page)) {
2759 if (cleancache_get_page(page) == 0) { 2759 if (cleancache_get_page(page) == 0) {
2760 BUG_ON(blocksize != PAGE_SIZE); 2760 BUG_ON(blocksize != PAGE_SIZE);
2761 unlock_extent(tree, start, end);
2761 goto out; 2762 goto out;
2762 } 2763 }
2763 } 2764 }
2764 2765
2765 end = page_end;
2766 while (1) {
2767 lock_extent(tree, start, end);
2768 ordered = btrfs_lookup_ordered_extent(inode, start);
2769 if (!ordered)
2770 break;
2771 unlock_extent(tree, start, end);
2772 btrfs_start_ordered_extent(inode, ordered, 1);
2773 btrfs_put_ordered_extent(ordered);
2774 }
2775
2776 if (page->index == last_byte >> PAGE_CACHE_SHIFT) { 2766 if (page->index == last_byte >> PAGE_CACHE_SHIFT) {
2777 char *userpage; 2767 char *userpage;
2778 size_t zero_offset = last_byte & (PAGE_CACHE_SIZE - 1); 2768 size_t zero_offset = last_byte & (PAGE_CACHE_SIZE - 1);
@@ -2901,6 +2891,101 @@ out:
2901 return 0; 2891 return 0;
2902} 2892}
2903 2893
2894static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
2895 struct page *pages[], int nr_pages,
2896 u64 start, u64 end,
2897 get_extent_t *get_extent,
2898 struct bio **bio, int mirror_num,
2899 unsigned long *bio_flags, int rw)
2900{
2901 struct inode *inode;
2902 struct btrfs_ordered_extent *ordered;
2903 int index;
2904
2905 inode = pages[0]->mapping->host;
2906 while (1) {
2907 lock_extent(tree, start, end);
2908 ordered = btrfs_lookup_ordered_range(inode, start,
2909 end - start + 1);
2910 if (!ordered)
2911 break;
2912 unlock_extent(tree, start, end);
2913 btrfs_start_ordered_extent(inode, ordered, 1);
2914 btrfs_put_ordered_extent(ordered);
2915 }
2916
2917 for (index = 0; index < nr_pages; index++) {
2918 __do_readpage(tree, pages[index], get_extent, bio, mirror_num,
2919 bio_flags, rw);
2920 page_cache_release(pages[index]);
2921 }
2922}
2923
2924static void __extent_readpages(struct extent_io_tree *tree,
2925 struct page *pages[],
2926 int nr_pages, get_extent_t *get_extent,
2927 struct bio **bio, int mirror_num,
2928 unsigned long *bio_flags, int rw)
2929{
2930 u64 start;
2931 u64 end = 0;
2932 u64 page_start;
2933 int index;
2934 int first_index;
2935
2936 for (index = 0; index < nr_pages; index++) {
2937 page_start = page_offset(pages[index]);
2938 if (!end) {
2939 start = page_start;
2940 end = start + PAGE_CACHE_SIZE - 1;
2941 first_index = index;
2942 } else if (end + 1 == page_start) {
2943 end += PAGE_CACHE_SIZE;
2944 } else {
2945 __do_contiguous_readpages(tree, &pages[first_index],
2946 index - first_index, start,
2947 end, get_extent, bio,
2948 mirror_num, bio_flags, rw);
2949 start = page_start;
2950 end = start + PAGE_CACHE_SIZE - 1;
2951 first_index = index;
2952 }
2953 }
2954
2955 if (end)
2956 __do_contiguous_readpages(tree, &pages[first_index],
2957 index - first_index, start,
2958 end, get_extent, bio,
2959 mirror_num, bio_flags, rw);
2960}
2961
2962static int __extent_read_full_page(struct extent_io_tree *tree,
2963 struct page *page,
2964 get_extent_t *get_extent,
2965 struct bio **bio, int mirror_num,
2966 unsigned long *bio_flags, int rw)
2967{
2968 struct inode *inode = page->mapping->host;
2969 struct btrfs_ordered_extent *ordered;
2970 u64 start = page_offset(page);
2971 u64 end = start + PAGE_CACHE_SIZE - 1;
2972 int ret;
2973
2974 while (1) {
2975 lock_extent(tree, start, end);
2976 ordered = btrfs_lookup_ordered_extent(inode, start);
2977 if (!ordered)
2978 break;
2979 unlock_extent(tree, start, end);
2980 btrfs_start_ordered_extent(inode, ordered, 1);
2981 btrfs_put_ordered_extent(ordered);
2982 }
2983
2984 ret = __do_readpage(tree, page, get_extent, bio, mirror_num, bio_flags,
2985 rw);
2986 return ret;
2987}
2988
2904int extent_read_full_page(struct extent_io_tree *tree, struct page *page, 2989int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
2905 get_extent_t *get_extent, int mirror_num) 2990 get_extent_t *get_extent, int mirror_num)
2906{ 2991{
@@ -3751,7 +3836,6 @@ int extent_readpages(struct extent_io_tree *tree,
3751 unsigned long bio_flags = 0; 3836 unsigned long bio_flags = 0;
3752 struct page *pagepool[16]; 3837 struct page *pagepool[16];
3753 struct page *page; 3838 struct page *page;
3754 int i = 0;
3755 int nr = 0; 3839 int nr = 0;
3756 3840
3757 for (page_idx = 0; page_idx < nr_pages; page_idx++) { 3841 for (page_idx = 0; page_idx < nr_pages; page_idx++) {
@@ -3768,18 +3852,13 @@ int extent_readpages(struct extent_io_tree *tree,
3768 pagepool[nr++] = page; 3852 pagepool[nr++] = page;
3769 if (nr < ARRAY_SIZE(pagepool)) 3853 if (nr < ARRAY_SIZE(pagepool))
3770 continue; 3854 continue;
3771 for (i = 0; i < nr; i++) { 3855 __extent_readpages(tree, pagepool, nr, get_extent,
3772 __extent_read_full_page(tree, pagepool[i], get_extent, 3856 &bio, 0, &bio_flags, READ);
3773 &bio, 0, &bio_flags, READ);
3774 page_cache_release(pagepool[i]);
3775 }
3776 nr = 0; 3857 nr = 0;
3777 } 3858 }
3778 for (i = 0; i < nr; i++) { 3859 if (nr)
3779 __extent_read_full_page(tree, pagepool[i], get_extent, 3860 __extent_readpages(tree, pagepool, nr, get_extent,
3780 &bio, 0, &bio_flags, READ); 3861 &bio, 0, &bio_flags, READ);
3781 page_cache_release(pagepool[i]);
3782 }
3783 3862
3784 BUG_ON(!list_empty(pages)); 3863 BUG_ON(!list_empty(pages));
3785 if (bio) 3864 if (bio)