Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[pandora-kernel.git] / fs / btrfs / extent_io.c
index 7073cbb..d2d0368 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/slab.h>
 #include <linux/bio.h>
 #include <linux/mm.h>
-#include <linux/gfp.h>
 #include <linux/pagemap.h>
 #include <linux/page-flags.h>
 #include <linux/module.h>
@@ -513,7 +512,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        u64 last_end;
        int err;
        int set = 0;
+       int clear = 0;
 
+       if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY))
+               clear = 1;
 again:
        if (!prealloc && (mask & __GFP_WAIT)) {
                prealloc = alloc_extent_state(mask);
@@ -524,14 +526,20 @@ again:
        spin_lock(&tree->lock);
        if (cached_state) {
                cached = *cached_state;
-               *cached_state = NULL;
-               cached_state = NULL;
+
+               if (clear) {
+                       *cached_state = NULL;
+                       cached_state = NULL;
+               }
+
                if (cached && cached->tree && cached->start == start) {
-                       atomic_dec(&cached->refs);
+                       if (clear)
+                               atomic_dec(&cached->refs);
                        state = cached;
                        goto hit_next;
                }
-               free_extent_state(cached);
+               if (clear)
+                       free_extent_state(cached);
        }
        /*
         * this search will find the extents that end after
@@ -946,11 +954,11 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 }
 
 int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
-                    gfp_t mask)
+                       struct extent_state **cached_state, gfp_t mask)
 {
        return set_extent_bit(tree, start, end,
                              EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE,
-                             0, NULL, NULL, mask);
+                             0, NULL, cached_state, mask);
 }
 
 int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
@@ -984,10 +992,11 @@ int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
 }
 
 static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
-                                u64 end, gfp_t mask)
+                                u64 end, struct extent_state **cached_state,
+                                gfp_t mask)
 {
        return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
-                               NULL, mask);
+                               cached_state, mask);
 }
 
 int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
@@ -1171,7 +1180,8 @@ out:
  * 1 is returned if we find something, 0 if nothing was in the tree
  */
 static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
-                                       u64 *start, u64 *end, u64 max_bytes)
+                                       u64 *start, u64 *end, u64 max_bytes,
+                                       struct extent_state **cached_state)
 {
        struct rb_node *node;
        struct extent_state *state;
@@ -1203,8 +1213,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
                                *end = state->end;
                        goto out;
                }
-               if (!found)
+               if (!found) {
                        *start = state->start;
+                       *cached_state = state;
+                       atomic_inc(&state->refs);
+               }
                found++;
                *end = state->end;
                cur_start = state->end + 1;
@@ -1336,10 +1349,11 @@ again:
        delalloc_start = *start;
        delalloc_end = 0;
        found = find_delalloc_range(tree, &delalloc_start, &delalloc_end,
-                                   max_bytes);
+                                   max_bytes, &cached_state);
        if (!found || delalloc_end <= *start) {
                *start = delalloc_start;
                *end = delalloc_end;
+               free_extent_state(cached_state);
                return found;
        }
 
@@ -1722,7 +1736,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
                }
 
                if (!uptodate) {
-                       clear_extent_uptodate(tree, start, end, GFP_NOFS);
+                       clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
                        ClearPageUptodate(page);
                        SetPageError(page);
                }
@@ -1750,7 +1764,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
 static void end_bio_extent_readpage(struct bio *bio, int err)
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec = bio->bi_io_vec;
        struct extent_io_tree *tree;
        u64 start;
        u64 end;
@@ -1773,7 +1788,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                else
                        whole_page = 0;
 
-               if (--bvec >= bio->bi_io_vec)
+               if (++bvec <= bvec_end)
                        prefetchw(&bvec->bv_page->flags);
 
                if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
@@ -1818,7 +1833,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                        }
                        check_page_locked(tree, page);
                }
-       } while (bvec >= bio->bi_io_vec);
+       } while (bvec <= bvec_end);
 
        bio_put(bio);
 }
@@ -2663,33 +2678,20 @@ int extent_readpages(struct extent_io_tree *tree,
 {
        struct bio *bio = NULL;
        unsigned page_idx;
-       struct pagevec pvec;
        unsigned long bio_flags = 0;
 
-       pagevec_init(&pvec, 0);
        for (page_idx = 0; page_idx < nr_pages; page_idx++) {
                struct page *page = list_entry(pages->prev, struct page, lru);
 
                prefetchw(&page->flags);
                list_del(&page->lru);
-               /*
-                * what we want to do here is call add_to_page_cache_lru,
-                * but that isn't exported, so we reproduce it here
-                */
-               if (!add_to_page_cache(page, mapping,
+               if (!add_to_page_cache_lru(page, mapping,
                                        page->index, GFP_KERNEL)) {
-
-                       /* open coding of lru_cache_add, also not exported */
-                       page_cache_get(page);
-                       if (!pagevec_add(&pvec, page))
-                               __pagevec_lru_add_file(&pvec);
                        __extent_read_full_page(tree, page, get_extent,
                                                &bio, 0, &bio_flags);
                }
                page_cache_release(page);
        }
-       if (pagevec_count(&pvec))
-               __pagevec_lru_add_file(&pvec);
        BUG_ON(!list_empty(pages));
        if (bio)
                submit_one_bio(READ, bio, 0, bio_flags);
@@ -2704,6 +2706,7 @@ int extent_readpages(struct extent_io_tree *tree,
 int extent_invalidatepage(struct extent_io_tree *tree,
                          struct page *page, unsigned long offset)
 {
+       struct extent_state *cached_state = NULL;
        u64 start = ((u64)page->index << PAGE_CACHE_SHIFT);
        u64 end = start + PAGE_CACHE_SIZE - 1;
        size_t blocksize = page->mapping->host->i_sb->s_blocksize;
@@ -2712,12 +2715,12 @@ int extent_invalidatepage(struct extent_io_tree *tree,
        if (start > end)
                return 0;
 
-       lock_extent(tree, start, end, GFP_NOFS);
+       lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS);
        wait_on_page_writeback(page);
        clear_extent_bit(tree, start, end,
                         EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
                         EXTENT_DO_ACCOUNTING,
-                        1, 1, NULL, GFP_NOFS);
+                        1, 1, &cached_state, GFP_NOFS);
        return 0;
 }
 
@@ -2920,16 +2923,17 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
                get_extent_t *get_extent)
 {
        struct inode *inode = mapping->host;
+       struct extent_state *cached_state = NULL;
        u64 start = iblock << inode->i_blkbits;
        sector_t sector = 0;
        size_t blksize = (1 << inode->i_blkbits);
        struct extent_map *em;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
-                   GFP_NOFS);
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
+                        0, &cached_state, GFP_NOFS);
        em = get_extent(inode, NULL, 0, start, blksize, 0);
-       unlock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
-                     GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, start,
+                            start + blksize - 1, &cached_state, GFP_NOFS);
        if (!em || IS_ERR(em))
                return 0;
 
@@ -2951,6 +2955,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        u32 flags = 0;
        u64 disko = 0;
        struct extent_map *em = NULL;
+       struct extent_state *cached_state = NULL;
        int end = 0;
        u64 em_start = 0, em_len = 0;
        unsigned long emflags;
@@ -2959,8 +2964,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        if (len == 0)
                return -EINVAL;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
-               GFP_NOFS);
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
+                        &cached_state, GFP_NOFS);
        em = get_extent(inode, NULL, 0, off, max - off, 0);
        if (!em)
                goto out;
@@ -3023,8 +3028,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 out_free:
        free_extent_map(em);
 out:
-       unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
-                       GFP_NOFS);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len,
+                            &cached_state, GFP_NOFS);
        return ret;
 }
 
@@ -3264,7 +3269,8 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
 }
 
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-                               struct extent_buffer *eb)
+                               struct extent_buffer *eb,
+                               struct extent_state **cached_state)
 {
        unsigned long i;
        struct page *page;
@@ -3274,7 +3280,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
        clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 
        clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-                             GFP_NOFS);
+                             cached_state, GFP_NOFS);
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                if (page)
@@ -3334,7 +3340,8 @@ int extent_range_uptodate(struct extent_io_tree *tree,
 }
 
 int extent_buffer_uptodate(struct extent_io_tree *tree,
-                          struct extent_buffer *eb)
+                          struct extent_buffer *eb,
+                          struct extent_state *cached_state)
 {
        int ret = 0;
        unsigned long num_pages;
@@ -3346,7 +3353,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
                return 1;
 
        ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-                          EXTENT_UPTODATE, 1, NULL);
+                          EXTENT_UPTODATE, 1, cached_state);
        if (ret)
                return ret;