diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent_io.c | 48 |
1 files changed, 37 insertions, 11 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d74e6af9b53a..6e3b326346a7 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -3104,6 +3104,39 @@ static void __free_extent_buffer(struct extent_buffer *eb) | |||
3104 | kmem_cache_free(extent_buffer_cache, eb); | 3104 | kmem_cache_free(extent_buffer_cache, eb); |
3105 | } | 3105 | } |
3106 | 3106 | ||
3107 | /* | ||
3108 | * Helper for releasing extent buffer page. | ||
3109 | */ | ||
3110 | static void btrfs_release_extent_buffer_page(struct extent_buffer *eb, | ||
3111 | unsigned long start_idx) | ||
3112 | { | ||
3113 | unsigned long index; | ||
3114 | struct page *page; | ||
3115 | |||
3116 | if (!eb->first_page) | ||
3117 | return; | ||
3118 | |||
3119 | index = num_extent_pages(eb->start, eb->len); | ||
3120 | if (start_idx >= index) | ||
3121 | return; | ||
3122 | |||
3123 | do { | ||
3124 | index--; | ||
3125 | page = extent_buffer_page(eb, index); | ||
3126 | if (page) | ||
3127 | page_cache_release(page); | ||
3128 | } while (index != start_idx); | ||
3129 | } | ||
3130 | |||
3131 | /* | ||
3132 | * Helper for releasing the extent buffer. | ||
3133 | */ | ||
3134 | static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) | ||
3135 | { | ||
3136 | btrfs_release_extent_buffer_page(eb, 0); | ||
3137 | __free_extent_buffer(eb); | ||
3138 | } | ||
3139 | |||
3107 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | 3140 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, |
3108 | u64 start, unsigned long len, | 3141 | u64 start, unsigned long len, |
3109 | struct page *page0, | 3142 | struct page *page0, |
@@ -3181,10 +3214,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
3181 | free_eb: | 3214 | free_eb: |
3182 | if (!atomic_dec_and_test(&eb->refs)) | 3215 | if (!atomic_dec_and_test(&eb->refs)) |
3183 | return exists; | 3216 | return exists; |
3184 | for (index = 1; index < i; index++) | 3217 | btrfs_release_extent_buffer(eb); |
3185 | page_cache_release(extent_buffer_page(eb, index)); | ||
3186 | page_cache_release(extent_buffer_page(eb, 0)); | ||
3187 | __free_extent_buffer(eb); | ||
3188 | return exists; | 3218 | return exists; |
3189 | } | 3219 | } |
3190 | 3220 | ||
@@ -3838,8 +3868,6 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) | |||
3838 | u64 start = page_offset(page); | 3868 | u64 start = page_offset(page); |
3839 | struct extent_buffer *eb; | 3869 | struct extent_buffer *eb; |
3840 | int ret = 1; | 3870 | int ret = 1; |
3841 | unsigned long i; | ||
3842 | unsigned long num_pages; | ||
3843 | 3871 | ||
3844 | spin_lock(&tree->buffer_lock); | 3872 | spin_lock(&tree->buffer_lock); |
3845 | eb = buffer_search(tree, start); | 3873 | eb = buffer_search(tree, start); |
@@ -3854,12 +3882,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) | |||
3854 | ret = 0; | 3882 | ret = 0; |
3855 | goto out; | 3883 | goto out; |
3856 | } | 3884 | } |
3857 | /* at this point we can safely release the extent buffer */ | 3885 | |
3858 | num_pages = num_extent_pages(eb->start, eb->len); | ||
3859 | for (i = 0; i < num_pages; i++) | ||
3860 | page_cache_release(extent_buffer_page(eb, i)); | ||
3861 | rb_erase(&eb->rb_node, &tree->buffer); | 3886 | rb_erase(&eb->rb_node, &tree->buffer); |
3862 | __free_extent_buffer(eb); | 3887 | /* at this point we can safely release the extent buffer */ |
3888 | btrfs_release_extent_buffer(eb); | ||
3863 | out: | 3889 | out: |
3864 | spin_unlock(&tree->buffer_lock); | 3890 | spin_unlock(&tree->buffer_lock); |
3865 | return ret; | 3891 | return ret; |