diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index bc5bd5abb28a..e444b99e02da 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -283,6 +283,7 @@ static int btree_releasepage(struct page *page, gfp_t gfp_flags) map = &BTRFS_I(page->mapping->host)->extent_tree; ret = try_release_extent_mapping(map, tree, page, gfp_flags); if (ret == 1) { + invalidate_extent_lru(tree, page_offset(page), PAGE_CACHE_SIZE); ClearPagePrivate(page); set_page_private(page, 0); page_cache_release(page); @@ -376,7 +377,6 @@ int btrfs_verify_block_csum(struct btrfs_root *root, buf->flags |= EXTENT_CSUM; return 0; } - lock_extent(io_tree, buf->start, end, GFP_NOFS); if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { @@ -384,6 +384,7 @@ int btrfs_verify_block_csum(struct btrfs_root *root, ret = 0; goto out_unlock; } +WARN_ON(buf->flags & EXTENT_CSUM); ret = csum_tree_block(root, buf, 1); set_extent_bits(io_tree, buf->start, end, EXTENT_CSUM, GFP_NOFS); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 776c33f1e6fe..13cc2360e375 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2592,6 +2592,33 @@ static inline struct page *extent_buffer_page(struct extent_buffer *eb, return p; } +int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, + unsigned long len) +{ + struct list_head *lru = &tree->buffer_lru; + struct list_head *cur = lru->next; + struct extent_buffer *eb; + int found = 0; + + spin_lock(&tree->lru_lock); + if (list_empty(lru)) + goto out; + + do { + eb = list_entry(cur, struct extent_buffer, lru); + if (eb->start <= start && eb->start + eb->len > start) { + eb->flags &= ~EXTENT_UPTODATE; + } + if (eb->start == start) { + eb->flags &= ~EXTENT_CSUM; + } + cur = cur->next; + } while (cur != lru); +out: + spin_unlock(&tree->lru_lock); + return found; +} + static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, u64 start, unsigned long len, @@ -2909,10 +2936,32 @@ EXPORT_SYMBOL(set_extent_buffer_uptodate); int extent_buffer_uptodate(struct extent_io_tree *tree, struct extent_buffer *eb) { + int ret = 0; + int ret2; + int num_pages; + int i; + struct page *page; + int pg_uptodate = 1; + if (eb->flags & EXTENT_UPTODATE) - return 1; - return test_range_bit(tree, eb->start, eb->start + eb->len - 1, + ret = 1; + + ret2 = test_range_bit(tree, eb->start, eb->start + eb->len - 1, EXTENT_UPTODATE, 1); + + num_pages = num_extent_pages(eb->start, eb->len); + for (i = 0; i < num_pages; i++) { + page = extent_buffer_page(eb, i); + if (!PageUptodate(page)) { + pg_uptodate = 0; + break; + } + } + if ((ret || ret2) && !pg_uptodate) { +printk("uptodate error2 eb %Lu ret %d ret2 %d pg_uptodate %d\n", eb->start, ret, ret2, pg_uptodate); + WARN_ON(1); + } + return (ret || ret2); } EXPORT_SYMBOL(extent_buffer_uptodate); @@ -2929,7 +2978,6 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, unsigned long num_pages; struct bio *bio = NULL; - if (eb->flags & EXTENT_UPTODATE) return 0; diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 16d67a61a25c..d9f5bc4dbd7f 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -216,4 +216,6 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, unsigned long *map_start, unsigned long *map_len, int km); void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); +int invalidate_extent_lru(struct extent_io_tree *tree, u64 start, + unsigned long len); #endif