diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
| -rw-r--r-- | fs/btrfs/extent_io.c | 168 |
1 files changed, 83 insertions, 85 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d74e6af9b53a..eac10e3260a9 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -104,7 +104,7 @@ void extent_io_tree_init(struct extent_io_tree *tree, | |||
| 104 | struct address_space *mapping, gfp_t mask) | 104 | struct address_space *mapping, gfp_t mask) |
| 105 | { | 105 | { |
| 106 | tree->state = RB_ROOT; | 106 | tree->state = RB_ROOT; |
| 107 | tree->buffer = RB_ROOT; | 107 | INIT_RADIX_TREE(&tree->buffer, GFP_ATOMIC); |
| 108 | tree->ops = NULL; | 108 | tree->ops = NULL; |
| 109 | tree->dirty_bytes = 0; | 109 | tree->dirty_bytes = 0; |
| 110 | spin_lock_init(&tree->lock); | 110 | spin_lock_init(&tree->lock); |
| @@ -235,50 +235,6 @@ static inline struct rb_node *tree_search(struct extent_io_tree *tree, | |||
| 235 | return ret; | 235 | return ret; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static struct extent_buffer *buffer_tree_insert(struct extent_io_tree *tree, | ||
| 239 | u64 offset, struct rb_node *node) | ||
| 240 | { | ||
| 241 | struct rb_root *root = &tree->buffer; | ||
| 242 | struct rb_node **p = &root->rb_node; | ||
| 243 | struct rb_node *parent = NULL; | ||
| 244 | struct extent_buffer *eb; | ||
| 245 | |||
| 246 | while (*p) { | ||
| 247 | parent = *p; | ||
| 248 | eb = rb_entry(parent, struct extent_buffer, rb_node); | ||
| 249 | |||
| 250 | if (offset < eb->start) | ||
| 251 | p = &(*p)->rb_left; | ||
| 252 | else if (offset > eb->start) | ||
| 253 | p = &(*p)->rb_right; | ||
| 254 | else | ||
| 255 | return eb; | ||
| 256 | } | ||
| 257 | |||
| 258 | rb_link_node(node, parent, p); | ||
| 259 | rb_insert_color(node, root); | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | static struct extent_buffer *buffer_search(struct extent_io_tree *tree, | ||
| 264 | u64 offset) | ||
| 265 | { | ||
| 266 | struct rb_root *root = &tree->buffer; | ||
| 267 | struct rb_node *n = root->rb_node; | ||
| 268 | struct extent_buffer *eb; | ||
| 269 | |||
| 270 | while (n) { | ||
| 271 | eb = rb_entry(n, struct extent_buffer, rb_node); | ||
| 272 | if (offset < eb->start) | ||
| 273 | n = n->rb_left; | ||
| 274 | else if (offset > eb->start) | ||
| 275 | n = n->rb_right; | ||
| 276 | else | ||
| 277 | return eb; | ||
| 278 | } | ||
| 279 | return NULL; | ||
| 280 | } | ||
| 281 | |||
| 282 | static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, | 238 | static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, |
| 283 | struct extent_state *other) | 239 | struct extent_state *other) |
| 284 | { | 240 | { |
| @@ -1901,10 +1857,8 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, | |||
| 1901 | struct page *page = bvec->bv_page; | 1857 | struct page *page = bvec->bv_page; |
| 1902 | struct extent_io_tree *tree = bio->bi_private; | 1858 | struct extent_io_tree *tree = bio->bi_private; |
| 1903 | u64 start; | 1859 | u64 start; |
| 1904 | u64 end; | ||
| 1905 | 1860 | ||
| 1906 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + bvec->bv_offset; | 1861 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + bvec->bv_offset; |
| 1907 | end = start + bvec->bv_len - 1; | ||
| 1908 | 1862 | ||
| 1909 | bio->bi_private = NULL; | 1863 | bio->bi_private = NULL; |
| 1910 | 1864 | ||
| @@ -2204,7 +2158,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2204 | u64 last_byte = i_size_read(inode); | 2158 | u64 last_byte = i_size_read(inode); |
| 2205 | u64 block_start; | 2159 | u64 block_start; |
| 2206 | u64 iosize; | 2160 | u64 iosize; |
| 2207 | u64 unlock_start; | ||
| 2208 | sector_t sector; | 2161 | sector_t sector; |
| 2209 | struct extent_state *cached_state = NULL; | 2162 | struct extent_state *cached_state = NULL; |
| 2210 | struct extent_map *em; | 2163 | struct extent_map *em; |
| @@ -2329,7 +2282,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2329 | if (tree->ops && tree->ops->writepage_end_io_hook) | 2282 | if (tree->ops && tree->ops->writepage_end_io_hook) |
| 2330 | tree->ops->writepage_end_io_hook(page, start, | 2283 | tree->ops->writepage_end_io_hook(page, start, |
| 2331 | page_end, NULL, 1); | 2284 | page_end, NULL, 1); |
| 2332 | unlock_start = page_end + 1; | ||
| 2333 | goto done; | 2285 | goto done; |
| 2334 | } | 2286 | } |
| 2335 | 2287 | ||
| @@ -2340,7 +2292,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2340 | if (tree->ops && tree->ops->writepage_end_io_hook) | 2292 | if (tree->ops && tree->ops->writepage_end_io_hook) |
| 2341 | tree->ops->writepage_end_io_hook(page, cur, | 2293 | tree->ops->writepage_end_io_hook(page, cur, |
| 2342 | page_end, NULL, 1); | 2294 | page_end, NULL, 1); |
| 2343 | unlock_start = page_end + 1; | ||
| 2344 | break; | 2295 | break; |
| 2345 | } | 2296 | } |
| 2346 | em = epd->get_extent(inode, page, pg_offset, cur, | 2297 | em = epd->get_extent(inode, page, pg_offset, cur, |
| @@ -2387,7 +2338,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2387 | 2338 | ||
| 2388 | cur += iosize; | 2339 | cur += iosize; |
| 2389 | pg_offset += iosize; | 2340 | pg_offset += iosize; |
| 2390 | unlock_start = cur; | ||
| 2391 | continue; | 2341 | continue; |
| 2392 | } | 2342 | } |
| 2393 | /* leave this out until we have a page_mkwrite call */ | 2343 | /* leave this out until we have a page_mkwrite call */ |
| @@ -2473,7 +2423,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, | |||
| 2473 | pgoff_t index; | 2423 | pgoff_t index; |
| 2474 | pgoff_t end; /* Inclusive */ | 2424 | pgoff_t end; /* Inclusive */ |
| 2475 | int scanned = 0; | 2425 | int scanned = 0; |
| 2476 | int range_whole = 0; | ||
| 2477 | 2426 | ||
| 2478 | pagevec_init(&pvec, 0); | 2427 | pagevec_init(&pvec, 0); |
| 2479 | if (wbc->range_cyclic) { | 2428 | if (wbc->range_cyclic) { |
| @@ -2482,8 +2431,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, | |||
| 2482 | } else { | 2431 | } else { |
| 2483 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | 2432 | index = wbc->range_start >> PAGE_CACHE_SHIFT; |
| 2484 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | 2433 | end = wbc->range_end >> PAGE_CACHE_SHIFT; |
| 2485 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | ||
| 2486 | range_whole = 1; | ||
| 2487 | scanned = 1; | 2434 | scanned = 1; |
| 2488 | } | 2435 | } |
| 2489 | retry: | 2436 | retry: |
| @@ -2823,6 +2770,8 @@ int extent_prepare_write(struct extent_io_tree *tree, | |||
| 2823 | NULL, 1, | 2770 | NULL, 1, |
| 2824 | end_bio_extent_preparewrite, 0, | 2771 | end_bio_extent_preparewrite, 0, |
| 2825 | 0, 0); | 2772 | 0, 0); |
| 2773 | if (ret && !err) | ||
| 2774 | err = ret; | ||
| 2826 | iocount++; | 2775 | iocount++; |
| 2827 | block_start = block_start + iosize; | 2776 | block_start = block_start + iosize; |
| 2828 | } else { | 2777 | } else { |
| @@ -3104,6 +3053,39 @@ static void __free_extent_buffer(struct extent_buffer *eb) | |||
| 3104 | kmem_cache_free(extent_buffer_cache, eb); | 3053 | kmem_cache_free(extent_buffer_cache, eb); |
| 3105 | } | 3054 | } |
| 3106 | 3055 | ||
| 3056 | /* | ||
| 3057 | * Helper for releasing extent buffer page. | ||
| 3058 | */ | ||
| 3059 | static void btrfs_release_extent_buffer_page(struct extent_buffer *eb, | ||
| 3060 | unsigned long start_idx) | ||
| 3061 | { | ||
| 3062 | unsigned long index; | ||
| 3063 | struct page *page; | ||
| 3064 | |||
| 3065 | if (!eb->first_page) | ||
| 3066 | return; | ||
| 3067 | |||
| 3068 | index = num_extent_pages(eb->start, eb->len); | ||
| 3069 | if (start_idx >= index) | ||
| 3070 | return; | ||
| 3071 | |||
| 3072 | do { | ||
| 3073 | index--; | ||
| 3074 | page = extent_buffer_page(eb, index); | ||
| 3075 | if (page) | ||
| 3076 | page_cache_release(page); | ||
| 3077 | } while (index != start_idx); | ||
| 3078 | } | ||
| 3079 | |||
| 3080 | /* | ||
| 3081 | * Helper for releasing the extent buffer. | ||
| 3082 | */ | ||
| 3083 | static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) | ||
| 3084 | { | ||
| 3085 | btrfs_release_extent_buffer_page(eb, 0); | ||
| 3086 | __free_extent_buffer(eb); | ||
| 3087 | } | ||
| 3088 | |||
| 3107 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | 3089 | struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, |
| 3108 | u64 start, unsigned long len, | 3090 | u64 start, unsigned long len, |
| 3109 | struct page *page0, | 3091 | struct page *page0, |
| @@ -3117,16 +3099,16 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
| 3117 | struct page *p; | 3099 | struct page *p; |
| 3118 | struct address_space *mapping = tree->mapping; | 3100 | struct address_space *mapping = tree->mapping; |
| 3119 | int uptodate = 1; | 3101 | int uptodate = 1; |
| 3102 | int ret; | ||
| 3120 | 3103 | ||
| 3121 | spin_lock(&tree->buffer_lock); | 3104 | rcu_read_lock(); |
| 3122 | eb = buffer_search(tree, start); | 3105 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3123 | if (eb) { | 3106 | if (eb && atomic_inc_not_zero(&eb->refs)) { |
| 3124 | atomic_inc(&eb->refs); | 3107 | rcu_read_unlock(); |
| 3125 | spin_unlock(&tree->buffer_lock); | ||
| 3126 | mark_page_accessed(eb->first_page); | 3108 | mark_page_accessed(eb->first_page); |
| 3127 | return eb; | 3109 | return eb; |
| 3128 | } | 3110 | } |
| 3129 | spin_unlock(&tree->buffer_lock); | 3111 | rcu_read_unlock(); |
| 3130 | 3112 | ||
| 3131 | eb = __alloc_extent_buffer(tree, start, len, mask); | 3113 | eb = __alloc_extent_buffer(tree, start, len, mask); |
| 3132 | if (!eb) | 3114 | if (!eb) |
| @@ -3165,26 +3147,31 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
| 3165 | if (uptodate) | 3147 | if (uptodate) |
| 3166 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); | 3148 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); |
| 3167 | 3149 | ||
| 3150 | ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); | ||
| 3151 | if (ret) | ||
| 3152 | goto free_eb; | ||
| 3153 | |||
| 3168 | spin_lock(&tree->buffer_lock); | 3154 | spin_lock(&tree->buffer_lock); |
| 3169 | exists = buffer_tree_insert(tree, start, &eb->rb_node); | 3155 | ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb); |
| 3170 | if (exists) { | 3156 | if (ret == -EEXIST) { |
| 3157 | exists = radix_tree_lookup(&tree->buffer, | ||
| 3158 | start >> PAGE_CACHE_SHIFT); | ||
| 3171 | /* add one reference for the caller */ | 3159 | /* add one reference for the caller */ |
| 3172 | atomic_inc(&exists->refs); | 3160 | atomic_inc(&exists->refs); |
| 3173 | spin_unlock(&tree->buffer_lock); | 3161 | spin_unlock(&tree->buffer_lock); |
| 3162 | radix_tree_preload_end(); | ||
| 3174 | goto free_eb; | 3163 | goto free_eb; |
| 3175 | } | 3164 | } |
| 3176 | /* add one reference for the tree */ | 3165 | /* add one reference for the tree */ |
| 3177 | atomic_inc(&eb->refs); | 3166 | atomic_inc(&eb->refs); |
| 3178 | spin_unlock(&tree->buffer_lock); | 3167 | spin_unlock(&tree->buffer_lock); |
| 3168 | radix_tree_preload_end(); | ||
| 3179 | return eb; | 3169 | return eb; |
| 3180 | 3170 | ||
| 3181 | free_eb: | 3171 | free_eb: |
| 3182 | if (!atomic_dec_and_test(&eb->refs)) | 3172 | if (!atomic_dec_and_test(&eb->refs)) |
| 3183 | return exists; | 3173 | return exists; |
| 3184 | for (index = 1; index < i; index++) | 3174 | 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; | 3175 | return exists; |
| 3189 | } | 3176 | } |
| 3190 | 3177 | ||
| @@ -3194,16 +3181,16 @@ struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, | |||
| 3194 | { | 3181 | { |
| 3195 | struct extent_buffer *eb; | 3182 | struct extent_buffer *eb; |
| 3196 | 3183 | ||
| 3197 | spin_lock(&tree->buffer_lock); | 3184 | rcu_read_lock(); |
| 3198 | eb = buffer_search(tree, start); | 3185 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3199 | if (eb) | 3186 | if (eb && atomic_inc_not_zero(&eb->refs)) { |
| 3200 | atomic_inc(&eb->refs); | 3187 | rcu_read_unlock(); |
| 3201 | spin_unlock(&tree->buffer_lock); | ||
| 3202 | |||
| 3203 | if (eb) | ||
| 3204 | mark_page_accessed(eb->first_page); | 3188 | mark_page_accessed(eb->first_page); |
| 3189 | return eb; | ||
| 3190 | } | ||
| 3191 | rcu_read_unlock(); | ||
| 3205 | 3192 | ||
| 3206 | return eb; | 3193 | return NULL; |
| 3207 | } | 3194 | } |
| 3208 | 3195 | ||
| 3209 | void free_extent_buffer(struct extent_buffer *eb) | 3196 | void free_extent_buffer(struct extent_buffer *eb) |
| @@ -3833,34 +3820,45 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, | |||
| 3833 | } | 3820 | } |
| 3834 | } | 3821 | } |
| 3835 | 3822 | ||
| 3823 | static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head) | ||
| 3824 | { | ||
| 3825 | struct extent_buffer *eb = | ||
| 3826 | container_of(head, struct extent_buffer, rcu_head); | ||
| 3827 | |||
| 3828 | btrfs_release_extent_buffer(eb); | ||
| 3829 | } | ||
| 3830 | |||
| 3836 | int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) | 3831 | int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) |
| 3837 | { | 3832 | { |
| 3838 | u64 start = page_offset(page); | 3833 | u64 start = page_offset(page); |
| 3839 | struct extent_buffer *eb; | 3834 | struct extent_buffer *eb; |
| 3840 | int ret = 1; | 3835 | int ret = 1; |
| 3841 | unsigned long i; | ||
| 3842 | unsigned long num_pages; | ||
| 3843 | 3836 | ||
| 3844 | spin_lock(&tree->buffer_lock); | 3837 | spin_lock(&tree->buffer_lock); |
| 3845 | eb = buffer_search(tree, start); | 3838 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 3846 | if (!eb) | 3839 | if (!eb) |
| 3847 | goto out; | 3840 | goto out; |
| 3848 | 3841 | ||
| 3849 | if (atomic_read(&eb->refs) > 1) { | 3842 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { |
| 3850 | ret = 0; | 3843 | ret = 0; |
| 3851 | goto out; | 3844 | goto out; |
| 3852 | } | 3845 | } |
| 3853 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { | 3846 | |
| 3847 | /* | ||
| 3848 | * set @eb->refs to 0 if it is already 1, and then release the @eb. | ||
| 3849 | * Or go back. | ||
| 3850 | */ | ||
| 3851 | if (atomic_cmpxchg(&eb->refs, 1, 0) != 1) { | ||
| 3854 | ret = 0; | 3852 | ret = 0; |
| 3855 | goto out; | 3853 | goto out; |
| 3856 | } | 3854 | } |
| 3857 | /* at this point we can safely release the extent buffer */ | 3855 | |
| 3858 | num_pages = num_extent_pages(eb->start, eb->len); | 3856 | radix_tree_delete(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
| 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); | ||
| 3862 | __free_extent_buffer(eb); | ||
| 3863 | out: | 3857 | out: |
| 3864 | spin_unlock(&tree->buffer_lock); | 3858 | spin_unlock(&tree->buffer_lock); |
| 3859 | |||
| 3860 | /* at this point we can safely release the extent buffer */ | ||
| 3861 | if (atomic_read(&eb->refs) == 0) | ||
| 3862 | call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu); | ||
| 3865 | return ret; | 3863 | return ret; |
| 3866 | } | 3864 | } |
