mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Btrfs: Split the extent_map code into two parts
There is now extent_map for mapping offsets in the file to disk and extent_io for state tracking, IO submission and extent_bufers. The new extent_map code shifts from [start,end] pairs to [start,len], and pushes the locking out into the caller. This allows a few performance optimizations and is easier to use. A number of extent_map usage bugs were fixed, mostly with failing to remove extent_map entries when changing the file. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
		
							parent
							
								
									5f56406aab
								
							
						
					
					
						commit
						d1310b2e0c
					
				
					 14 changed files with 3614 additions and 3415 deletions
				
			
		| 
						 | 
				
			
			@ -5,7 +5,8 @@ obj-m  := btrfs.o
 | 
			
		|||
btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 | 
			
		||||
	   hash.o file-item.o inode-item.o inode-map.o disk-io.o \
 | 
			
		||||
	   transaction.o bit-radix.o inode.o file.o tree-defrag.o \
 | 
			
		||||
	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o
 | 
			
		||||
	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
 | 
			
		||||
	   extent_io.o
 | 
			
		||||
 | 
			
		||||
ifeq ($(CONFIG_FS_POSIX_ACL),y)
 | 
			
		||||
btrfs-y += acl.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#define __BTRFS_I__
 | 
			
		||||
 | 
			
		||||
#include "extent_map.h"
 | 
			
		||||
#include "extent_io.h"
 | 
			
		||||
 | 
			
		||||
/* in memory btrfs inode */
 | 
			
		||||
struct btrfs_inode {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +28,7 @@ struct btrfs_inode {
 | 
			
		|||
	struct btrfs_block_group_cache *block_group;
 | 
			
		||||
	struct btrfs_key location;
 | 
			
		||||
	struct extent_map_tree extent_tree;
 | 
			
		||||
	struct extent_io_tree io_tree;
 | 
			
		||||
	struct inode vfs_inode;
 | 
			
		||||
 | 
			
		||||
	u64 ordered_trans;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
#include <linux/completion.h>
 | 
			
		||||
#include <asm/kmap_types.h>
 | 
			
		||||
#include "bit-radix.h"
 | 
			
		||||
#include "extent_io.h"
 | 
			
		||||
#include "extent_map.h"
 | 
			
		||||
 | 
			
		||||
struct btrfs_trans_handle;
 | 
			
		||||
| 
						 | 
				
			
			@ -314,11 +315,11 @@ struct btrfs_fs_info {
 | 
			
		|||
	struct btrfs_root *tree_root;
 | 
			
		||||
	struct radix_tree_root fs_roots_radix;
 | 
			
		||||
 | 
			
		||||
	struct extent_map_tree free_space_cache;
 | 
			
		||||
	struct extent_map_tree block_group_cache;
 | 
			
		||||
	struct extent_map_tree pinned_extents;
 | 
			
		||||
	struct extent_map_tree pending_del;
 | 
			
		||||
	struct extent_map_tree extent_ins;
 | 
			
		||||
	struct extent_io_tree free_space_cache;
 | 
			
		||||
	struct extent_io_tree block_group_cache;
 | 
			
		||||
	struct extent_io_tree pinned_extents;
 | 
			
		||||
	struct extent_io_tree pending_del;
 | 
			
		||||
	struct extent_io_tree extent_ins;
 | 
			
		||||
 | 
			
		||||
	u64 generation;
 | 
			
		||||
	u64 last_trans_committed;
 | 
			
		||||
| 
						 | 
				
			
			@ -956,7 +957,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
 | 
			
		|||
				  u64 first_extent);
 | 
			
		||||
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
 | 
			
		||||
			 struct btrfs_root *root);
 | 
			
		||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy);
 | 
			
		||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
 | 
			
		||||
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
 | 
			
		||||
							 btrfs_fs_info *info,
 | 
			
		||||
							 u64 bytenr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1001,7 +1002,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
		      u64 owner_objectid, u64 owner_offset, int pin);
 | 
			
		||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       struct extent_map_tree *unpin);
 | 
			
		||||
			       struct extent_io_tree *unpin);
 | 
			
		||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 | 
			
		||||
				struct btrfs_root *root,
 | 
			
		||||
				u64 bytenr, u64 num_bytes,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,14 +43,14 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct extent_map_ops btree_extent_map_ops;
 | 
			
		||||
static struct extent_io_ops btree_extent_io_ops;
 | 
			
		||||
 | 
			
		||||
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
 | 
			
		||||
					    u64 bytenr, u32 blocksize)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	struct extent_buffer *eb;
 | 
			
		||||
	eb = find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
				bytenr, blocksize, GFP_NOFS);
 | 
			
		||||
	return eb;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -61,13 +61,13 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
 | 
			
		|||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	struct extent_buffer *eb;
 | 
			
		||||
 | 
			
		||||
	eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
				 bytenr, blocksize, NULL, GFP_NOFS);
 | 
			
		||||
	return eb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct extent_map *btree_get_extent(struct inode *inode, struct page *page,
 | 
			
		||||
				    size_t page_offset, u64 start, u64 end,
 | 
			
		||||
				    size_t page_offset, u64 start, u64 len,
 | 
			
		||||
				    int create)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,9 @@ struct extent_map *btree_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
	int ret;
 | 
			
		||||
 | 
			
		||||
again:
 | 
			
		||||
	em = lookup_extent_mapping(em_tree, start, end);
 | 
			
		||||
	spin_lock(&em_tree->lock);
 | 
			
		||||
	em = lookup_extent_mapping(em_tree, start, len);
 | 
			
		||||
	spin_unlock(&em_tree->lock);
 | 
			
		||||
	if (em) {
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -85,11 +87,14 @@ struct extent_map *btree_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	em->start = 0;
 | 
			
		||||
	em->end = (i_size_read(inode) & ~((u64)PAGE_CACHE_SIZE -1)) - 1;
 | 
			
		||||
	em->len = i_size_read(inode);
 | 
			
		||||
	em->block_start = 0;
 | 
			
		||||
	em->block_end = em->end;
 | 
			
		||||
	em->bdev = inode->i_sb->s_bdev;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&em_tree->lock);
 | 
			
		||||
	ret = add_extent_mapping(em_tree, em);
 | 
			
		||||
	spin_unlock(&em_tree->lock);
 | 
			
		||||
 | 
			
		||||
	if (ret == -EEXIST) {
 | 
			
		||||
		free_extent_map(em);
 | 
			
		||||
		em = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +180,13 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
 | 
			
		|||
 | 
			
		||||
int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
 | 
			
		||||
	u64 found_start;
 | 
			
		||||
	int found_level;
 | 
			
		||||
	unsigned long len;
 | 
			
		||||
	struct extent_buffer *eb;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
 | 
			
		||||
	if (page->private == EXTENT_PAGE_PRIVATE)
 | 
			
		||||
		goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,16 +235,16 @@ static int btree_writepage_io_hook(struct page *page, u64 start, u64 end)
 | 
			
		|||
 | 
			
		||||
static int btree_writepage(struct page *page, struct writeback_control *wbc)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	return extent_write_full_page(tree, page, btree_get_extent, wbc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btree_writepages(struct address_space *mapping,
 | 
			
		||||
			    struct writeback_control *wbc)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->io_tree;
 | 
			
		||||
	if (wbc->sync_mode == WB_SYNC_NONE) {
 | 
			
		||||
		u64 num_dirty;
 | 
			
		||||
		u64 start = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -264,18 +269,20 @@ static int btree_writepages(struct address_space *mapping,
 | 
			
		|||
 | 
			
		||||
int btree_readpage(struct file *file, struct page *page)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	return extent_read_full_page(tree, page, btree_get_extent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	struct extent_map_tree *map;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	ret = try_release_extent_mapping(tree, page);
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	map = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	ret = try_release_extent_mapping(map, tree, page);
 | 
			
		||||
	if (ret == 1) {
 | 
			
		||||
		ClearPagePrivate(page);
 | 
			
		||||
		set_page_private(page, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -286,8 +293,8 @@ static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags)
 | 
			
		|||
 | 
			
		||||
static void btree_invalidatepage(struct page *page, unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	extent_invalidatepage(tree, page, offset);
 | 
			
		||||
	btree_releasepage(page, GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -331,7 +338,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
 | 
			
		|||
	buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
 | 
			
		||||
	if (!buf)
 | 
			
		||||
		return 0;
 | 
			
		||||
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
				 buf, 0, 0);
 | 
			
		||||
	free_extent_buffer(buf);
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -342,40 +349,39 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
 | 
			
		|||
{
 | 
			
		||||
	struct extent_buffer *buf = NULL;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	struct extent_map_tree *extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree;
 | 
			
		||||
	u64 end;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	extent_tree = &BTRFS_I(btree_inode)->extent_tree;
 | 
			
		||||
	io_tree = &BTRFS_I(btree_inode)->io_tree;
 | 
			
		||||
 | 
			
		||||
	buf = btrfs_find_create_tree_block(root, bytenr, blocksize);
 | 
			
		||||
	if (!buf)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
				 buf, 0, 1);
 | 
			
		||||
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, 1);
 | 
			
		||||
 | 
			
		||||
	if (buf->flags & EXTENT_CSUM)
 | 
			
		||||
		return buf;
 | 
			
		||||
 | 
			
		||||
	end = buf->start + PAGE_CACHE_SIZE - 1;
 | 
			
		||||
	if (test_range_bit(extent_tree, buf->start, end, EXTENT_CSUM, 1)) {
 | 
			
		||||
	if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) {
 | 
			
		||||
		buf->flags |= EXTENT_CSUM;
 | 
			
		||||
		return buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lock_extent(extent_tree, buf->start, end, GFP_NOFS);
 | 
			
		||||
	lock_extent(io_tree, buf->start, end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	if (test_range_bit(extent_tree, buf->start, end, EXTENT_CSUM, 1)) {
 | 
			
		||||
	if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) {
 | 
			
		||||
		buf->flags |= EXTENT_CSUM;
 | 
			
		||||
		goto out_unlock;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = csum_tree_block(root, buf, 1);
 | 
			
		||||
	set_extent_bits(extent_tree, buf->start, end, EXTENT_CSUM, GFP_NOFS);
 | 
			
		||||
	set_extent_bits(io_tree, buf->start, end, EXTENT_CSUM, GFP_NOFS);
 | 
			
		||||
	buf->flags |= EXTENT_CSUM;
 | 
			
		||||
 | 
			
		||||
out_unlock:
 | 
			
		||||
	unlock_extent(extent_tree, buf->start, end, GFP_NOFS);
 | 
			
		||||
	unlock_extent(io_tree, buf->start, end, GFP_NOFS);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -385,7 +391,7 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 | 
			
		|||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	if (btrfs_header_generation(buf) ==
 | 
			
		||||
	    root->fs_info->running_transaction->transid)
 | 
			
		||||
		clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
		clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
					  buf);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -394,7 +400,7 @@ int wait_on_tree_block_writeback(struct btrfs_root *root,
 | 
			
		|||
				 struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
					buf);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -659,20 +665,23 @@ struct btrfs_root *open_ctree(struct super_block *sb)
 | 
			
		|||
	fs_info->btree_inode->i_nlink = 1;
 | 
			
		||||
	fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
 | 
			
		||||
	fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree,
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping,
 | 
			
		||||
			     GFP_NOFS);
 | 
			
		||||
	BTRFS_I(fs_info->btree_inode)->extent_tree.ops = &btree_extent_map_ops;
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree,
 | 
			
		||||
			     GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	extent_map_tree_init(&fs_info->free_space_cache,
 | 
			
		||||
	BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
 | 
			
		||||
 | 
			
		||||
	extent_io_tree_init(&fs_info->free_space_cache,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	extent_map_tree_init(&fs_info->block_group_cache,
 | 
			
		||||
	extent_io_tree_init(&fs_info->block_group_cache,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	extent_map_tree_init(&fs_info->pinned_extents,
 | 
			
		||||
	extent_io_tree_init(&fs_info->pinned_extents,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	extent_map_tree_init(&fs_info->pending_del,
 | 
			
		||||
	extent_io_tree_init(&fs_info->pending_del,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	extent_map_tree_init(&fs_info->extent_ins,
 | 
			
		||||
	extent_io_tree_init(&fs_info->extent_ins,
 | 
			
		||||
			     fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	fs_info->do_barriers = 1;
 | 
			
		||||
	fs_info->closing = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -787,7 +796,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
 | 
			
		||||
	if (!btrfs_test_opt(root, NOBARRIER))
 | 
			
		||||
		blkdev_issue_flush(sb->s_bdev, NULL);
 | 
			
		||||
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, super);
 | 
			
		||||
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, super);
 | 
			
		||||
	ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping,
 | 
			
		||||
				     super->start, super->len);
 | 
			
		||||
	if (!btrfs_test_opt(root, NOBARRIER))
 | 
			
		||||
| 
						 | 
				
			
			@ -864,12 +873,12 @@ int close_ctree(struct btrfs_root *root)
 | 
			
		|||
 | 
			
		||||
	filemap_write_and_wait(fs_info->btree_inode->i_mapping);
 | 
			
		||||
 | 
			
		||||
	extent_map_tree_empty_lru(&fs_info->free_space_cache);
 | 
			
		||||
	extent_map_tree_empty_lru(&fs_info->block_group_cache);
 | 
			
		||||
	extent_map_tree_empty_lru(&fs_info->pinned_extents);
 | 
			
		||||
	extent_map_tree_empty_lru(&fs_info->pending_del);
 | 
			
		||||
	extent_map_tree_empty_lru(&fs_info->extent_ins);
 | 
			
		||||
	extent_map_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->extent_tree);
 | 
			
		||||
	extent_io_tree_empty_lru(&fs_info->free_space_cache);
 | 
			
		||||
	extent_io_tree_empty_lru(&fs_info->block_group_cache);
 | 
			
		||||
	extent_io_tree_empty_lru(&fs_info->pinned_extents);
 | 
			
		||||
	extent_io_tree_empty_lru(&fs_info->pending_del);
 | 
			
		||||
	extent_io_tree_empty_lru(&fs_info->extent_ins);
 | 
			
		||||
	extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
 | 
			
		||||
 | 
			
		||||
	truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -892,13 +901,13 @@ int close_ctree(struct btrfs_root *root)
 | 
			
		|||
int btrfs_buffer_uptodate(struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *btree_inode = buf->first_page->mapping->host;
 | 
			
		||||
	return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf);
 | 
			
		||||
	return extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *btree_inode = buf->first_page->mapping->host;
 | 
			
		||||
	return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
					  buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -914,7 +923,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
 | 
			
		|||
			transid, root->fs_info->generation);
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
	}
 | 
			
		||||
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf);
 | 
			
		||||
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void btrfs_throttle(struct btrfs_root *root)
 | 
			
		||||
| 
						 | 
				
			
			@ -941,7 +950,7 @@ void btrfs_set_buffer_defrag(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
 | 
			
		||||
	set_extent_bits(&BTRFS_I(btree_inode)->io_tree, buf->start,
 | 
			
		||||
			buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -949,7 +958,7 @@ void btrfs_set_buffer_defrag_done(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
 | 
			
		||||
	set_extent_bits(&BTRFS_I(btree_inode)->io_tree, buf->start,
 | 
			
		||||
			buf->start + buf->len - 1, EXTENT_DEFRAG_DONE,
 | 
			
		||||
			GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -958,7 +967,7 @@ int btrfs_buffer_defrag(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return test_range_bit(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
		     buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -966,7 +975,7 @@ int btrfs_buffer_defrag_done(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return test_range_bit(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
		     buf->start, buf->start + buf->len - 1,
 | 
			
		||||
		     EXTENT_DEFRAG_DONE, 0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -975,7 +984,7 @@ int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return clear_extent_bits(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
		     buf->start, buf->start + buf->len - 1,
 | 
			
		||||
		     EXTENT_DEFRAG_DONE, GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -984,7 +993,7 @@ int btrfs_clear_buffer_defrag(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return clear_extent_bits(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
		     buf->start, buf->start + buf->len - 1,
 | 
			
		||||
		     EXTENT_DEFRAG, GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -993,10 +1002,10 @@ int btrfs_read_buffer(struct extent_buffer *buf)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
 | 
			
		||||
	return read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
					buf, 0, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct extent_map_ops btree_extent_map_ops = {
 | 
			
		||||
static struct extent_io_ops btree_extent_io_ops = {
 | 
			
		||||
	.writepage_io_hook = btree_writepage_io_hook,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ static int cache_block_group(struct btrfs_root *root,
 | 
			
		|||
	int ret;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
	struct extent_map_tree *free_space_cache;
 | 
			
		||||
	struct extent_io_tree *free_space_cache;
 | 
			
		||||
	int slot;
 | 
			
		||||
	u64 last = 0;
 | 
			
		||||
	u64 hole_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
 | 
			
		|||
							 btrfs_fs_info *info,
 | 
			
		||||
							 u64 bytenr)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_block_group_cache *block_group = NULL;
 | 
			
		||||
	u64 ptr;
 | 
			
		||||
	u64 start;
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +281,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
 | 
			
		|||
						 int data, int owner)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_block_group_cache *cache;
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_block_group_cache *found_group = NULL;
 | 
			
		||||
	struct btrfs_fs_info *info = root->fs_info;
 | 
			
		||||
	u64 used;
 | 
			
		||||
| 
						 | 
				
			
			@ -951,7 +951,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
 | 
			
		|||
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
 | 
			
		||||
				   struct btrfs_root *root)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_block_group_cache *cache;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1107,12 +1107,12 @@ static int update_pinned_extents(struct btrfs_root *root,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy)
 | 
			
		||||
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy)
 | 
			
		||||
{
 | 
			
		||||
	u64 last = 0;
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end;
 | 
			
		||||
	struct extent_map_tree *pinned_extents = &root->fs_info->pinned_extents;
 | 
			
		||||
	struct extent_io_tree *pinned_extents = &root->fs_info->pinned_extents;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1128,12 +1128,12 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy)
 | 
			
		|||
 | 
			
		||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       struct extent_map_tree *unpin)
 | 
			
		||||
			       struct extent_io_tree *unpin)
 | 
			
		||||
{
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end;
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct extent_map_tree *free_space_cache;
 | 
			
		||||
	struct extent_io_tree *free_space_cache;
 | 
			
		||||
	free_space_cache = &root->fs_info->free_space_cache;
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1329,8 +1329,8 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
 | 
			
		|||
	int err = 0;
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end;
 | 
			
		||||
	struct extent_map_tree *pending_del;
 | 
			
		||||
	struct extent_map_tree *pinned_extents;
 | 
			
		||||
	struct extent_io_tree *pending_del;
 | 
			
		||||
	struct extent_io_tree *pinned_extents;
 | 
			
		||||
 | 
			
		||||
	pending_del = &extent_root->fs_info->pending_del;
 | 
			
		||||
	pinned_extents = &extent_root->fs_info->pinned_extents;
 | 
			
		||||
| 
						 | 
				
			
			@ -1802,7 +1802,7 @@ struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
	set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
 | 
			
		||||
			 buf->start + buf->len - 1, GFP_NOFS);
 | 
			
		||||
	set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->extent_tree,
 | 
			
		||||
	set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->io_tree,
 | 
			
		||||
			buf->start, buf->start + buf->len - 1,
 | 
			
		||||
			EXTENT_CSUM, GFP_NOFS);
 | 
			
		||||
	buf->flags |= EXTENT_CSUM;
 | 
			
		||||
| 
						 | 
				
			
			@ -2166,7 +2166,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
 | 
			
		|||
	unsigned long i;
 | 
			
		||||
	struct page *page;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	struct file_ra_state *ra;
 | 
			
		||||
 | 
			
		||||
	ra = kzalloc(sizeof(*ra), GFP_NOFS);
 | 
			
		||||
| 
						 | 
				
			
			@ -2195,15 +2195,14 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
 | 
			
		|||
		page_start = (u64)page->index << PAGE_CACHE_SHIFT;
 | 
			
		||||
		page_end = page_start + PAGE_CACHE_SIZE - 1;
 | 
			
		||||
 | 
			
		||||
		lock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		lock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
		delalloc_start = page_start;
 | 
			
		||||
		existing_delalloc =
 | 
			
		||||
			count_range_bits(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
					 &delalloc_start, page_end,
 | 
			
		||||
					 PAGE_CACHE_SIZE, EXTENT_DELALLOC);
 | 
			
		||||
		existing_delalloc = count_range_bits(io_tree,
 | 
			
		||||
					     &delalloc_start, page_end,
 | 
			
		||||
					     PAGE_CACHE_SIZE, EXTENT_DELALLOC);
 | 
			
		||||
 | 
			
		||||
		set_extent_delalloc(em_tree, page_start,
 | 
			
		||||
		set_extent_delalloc(io_tree, page_start,
 | 
			
		||||
				    page_end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
		spin_lock(&root->fs_info->delalloc_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -2211,7 +2210,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
 | 
			
		|||
						 existing_delalloc;
 | 
			
		||||
		spin_unlock(&root->fs_info->delalloc_lock);
 | 
			
		||||
 | 
			
		||||
		unlock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		set_page_dirty(page);
 | 
			
		||||
		unlock_page(page);
 | 
			
		||||
		page_cache_release(page);
 | 
			
		||||
| 
						 | 
				
			
			@ -2379,7 +2378,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size)
 | 
			
		|||
	u64 cur_byte;
 | 
			
		||||
	u64 total_found;
 | 
			
		||||
	struct btrfs_fs_info *info = root->fs_info;
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
	struct btrfs_key found_key;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
| 
						 | 
				
			
			@ -2561,7 +2560,7 @@ int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_block_group_cache *cache;
 | 
			
		||||
	struct btrfs_block_group_item *item;
 | 
			
		||||
	struct btrfs_fs_info *info = root->fs_info;
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -2645,7 +2644,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
 | 
			
		|||
	int bit;
 | 
			
		||||
	struct btrfs_block_group_cache *cache;
 | 
			
		||||
	struct btrfs_fs_info *info = root->fs_info;
 | 
			
		||||
	struct extent_map_tree *block_group_cache;
 | 
			
		||||
	struct extent_io_tree *block_group_cache;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
	struct btrfs_key found_key;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3089
									
								
								fs/btrfs/extent_io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3089
									
								
								fs/btrfs/extent_io.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										193
									
								
								fs/btrfs/extent_io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								fs/btrfs/extent_io.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,193 @@
 | 
			
		|||
#ifndef __EXTENTIO__
 | 
			
		||||
#define __EXTENTIO__
 | 
			
		||||
 | 
			
		||||
#include <linux/rbtree.h>
 | 
			
		||||
 | 
			
		||||
/* bits for the extent state */
 | 
			
		||||
#define EXTENT_DIRTY 1
 | 
			
		||||
#define EXTENT_WRITEBACK (1 << 1)
 | 
			
		||||
#define EXTENT_UPTODATE (1 << 2)
 | 
			
		||||
#define EXTENT_LOCKED (1 << 3)
 | 
			
		||||
#define EXTENT_NEW (1 << 4)
 | 
			
		||||
#define EXTENT_DELALLOC (1 << 5)
 | 
			
		||||
#define EXTENT_DEFRAG (1 << 6)
 | 
			
		||||
#define EXTENT_DEFRAG_DONE (1 << 7)
 | 
			
		||||
#define EXTENT_BUFFER_FILLED (1 << 8)
 | 
			
		||||
#define EXTENT_CSUM (1 << 9)
 | 
			
		||||
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * page->private values.  Every page that is controlled by the extent
 | 
			
		||||
 * map has page->private set to one.
 | 
			
		||||
 */
 | 
			
		||||
#define EXTENT_PAGE_PRIVATE 1
 | 
			
		||||
#define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
 | 
			
		||||
 | 
			
		||||
struct extent_io_ops {
 | 
			
		||||
	int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
 | 
			
		||||
	int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	void (*writepage_end_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_io_tree {
 | 
			
		||||
	struct rb_root state;
 | 
			
		||||
	struct address_space *mapping;
 | 
			
		||||
	u64 dirty_bytes;
 | 
			
		||||
	rwlock_t lock;
 | 
			
		||||
	struct extent_io_ops *ops;
 | 
			
		||||
	spinlock_t lru_lock;
 | 
			
		||||
	struct list_head buffer_lru;
 | 
			
		||||
	int lru_size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_state {
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end; /* inclusive */
 | 
			
		||||
	int in_tree;
 | 
			
		||||
	struct rb_node rb_node;
 | 
			
		||||
	wait_queue_head_t wq;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
	unsigned long state;
 | 
			
		||||
 | 
			
		||||
	/* for use by the FS */
 | 
			
		||||
	u64 private;
 | 
			
		||||
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_buffer {
 | 
			
		||||
	u64 start;
 | 
			
		||||
	unsigned long len;
 | 
			
		||||
	char *map_token;
 | 
			
		||||
	char *kaddr;
 | 
			
		||||
	unsigned long map_start;
 | 
			
		||||
	unsigned long map_len;
 | 
			
		||||
	struct page *first_page;
 | 
			
		||||
	struct list_head lru;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
	int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_map_tree;
 | 
			
		||||
 | 
			
		||||
typedef struct extent_map *(get_extent_t)(struct inode *inode,
 | 
			
		||||
					  struct page *page,
 | 
			
		||||
					  size_t page_offset,
 | 
			
		||||
					  u64 start, u64 len,
 | 
			
		||||
					  int create);
 | 
			
		||||
 | 
			
		||||
void extent_io_tree_init(struct extent_io_tree *tree,
 | 
			
		||||
			  struct address_space *mapping, gfp_t mask);
 | 
			
		||||
void extent_io_tree_empty_lru(struct extent_io_tree *tree);
 | 
			
		||||
int try_release_extent_mapping(struct extent_map_tree *map,
 | 
			
		||||
			       struct extent_io_tree *tree, struct page *page);
 | 
			
		||||
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
 | 
			
		||||
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
 | 
			
		||||
int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
 | 
			
		||||
			  get_extent_t *get_extent);
 | 
			
		||||
int __init extent_io_init(void);
 | 
			
		||||
void extent_io_exit(void);
 | 
			
		||||
 | 
			
		||||
u64 count_range_bits(struct extent_io_tree *tree,
 | 
			
		||||
		     u64 *start, u64 search_end,
 | 
			
		||||
		     u64 max_bytes, unsigned long bits);
 | 
			
		||||
 | 
			
		||||
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		   int bits, int filled);
 | 
			
		||||
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		      int bits, gfp_t mask);
 | 
			
		||||
int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		    int bits, gfp_t mask);
 | 
			
		||||
int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
			gfp_t mask);
 | 
			
		||||
int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		   gfp_t mask);
 | 
			
		||||
int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		     gfp_t mask);
 | 
			
		||||
int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		       gfp_t mask);
 | 
			
		||||
int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
 | 
			
		||||
		     gfp_t mask);
 | 
			
		||||
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
 | 
			
		||||
			  u64 *start_ret, u64 *end_ret, int bits);
 | 
			
		||||
int extent_invalidatepage(struct extent_io_tree *tree,
 | 
			
		||||
			  struct page *page, unsigned long offset);
 | 
			
		||||
int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
 | 
			
		||||
			  get_extent_t *get_extent,
 | 
			
		||||
			  struct writeback_control *wbc);
 | 
			
		||||
int extent_writepages(struct extent_io_tree *tree,
 | 
			
		||||
		      struct address_space *mapping,
 | 
			
		||||
		      get_extent_t *get_extent,
 | 
			
		||||
		      struct writeback_control *wbc);
 | 
			
		||||
int extent_readpages(struct extent_io_tree *tree,
 | 
			
		||||
		     struct address_space *mapping,
 | 
			
		||||
		     struct list_head *pages, unsigned nr_pages,
 | 
			
		||||
		     get_extent_t get_extent);
 | 
			
		||||
int extent_prepare_write(struct extent_io_tree *tree,
 | 
			
		||||
			 struct inode *inode, struct page *page,
 | 
			
		||||
			 unsigned from, unsigned to, get_extent_t *get_extent);
 | 
			
		||||
int extent_commit_write(struct extent_io_tree *tree,
 | 
			
		||||
			struct inode *inode, struct page *page,
 | 
			
		||||
			unsigned from, unsigned to);
 | 
			
		||||
sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
 | 
			
		||||
		get_extent_t *get_extent);
 | 
			
		||||
int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end);
 | 
			
		||||
int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
 | 
			
		||||
int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
 | 
			
		||||
void set_page_extent_mapped(struct page *page);
 | 
			
		||||
 | 
			
		||||
struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
 | 
			
		||||
					  u64 start, unsigned long len,
 | 
			
		||||
					  struct page *page0,
 | 
			
		||||
					  gfp_t mask);
 | 
			
		||||
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
 | 
			
		||||
					 u64 start, unsigned long len,
 | 
			
		||||
					  gfp_t mask);
 | 
			
		||||
void free_extent_buffer(struct extent_buffer *eb);
 | 
			
		||||
int read_extent_buffer_pages(struct extent_io_tree *tree,
 | 
			
		||||
			     struct extent_buffer *eb, u64 start, int wait);
 | 
			
		||||
 | 
			
		||||
static inline void extent_buffer_get(struct extent_buffer *eb)
 | 
			
		||||
{
 | 
			
		||||
	atomic_inc(&eb->refs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
 | 
			
		||||
			  unsigned long start,
 | 
			
		||||
			  unsigned long len);
 | 
			
		||||
void read_extent_buffer(struct extent_buffer *eb, void *dst,
 | 
			
		||||
			unsigned long start,
 | 
			
		||||
			unsigned long len);
 | 
			
		||||
void write_extent_buffer(struct extent_buffer *eb, const void *src,
 | 
			
		||||
			 unsigned long start, unsigned long len);
 | 
			
		||||
void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
 | 
			
		||||
			unsigned long dst_offset, unsigned long src_offset,
 | 
			
		||||
			unsigned long len);
 | 
			
		||||
void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 | 
			
		||||
			   unsigned long src_offset, unsigned long len);
 | 
			
		||||
void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 | 
			
		||||
			   unsigned long src_offset, unsigned long len);
 | 
			
		||||
void memset_extent_buffer(struct extent_buffer *eb, char c,
 | 
			
		||||
			  unsigned long start, unsigned long len);
 | 
			
		||||
int wait_on_extent_buffer_writeback(struct extent_io_tree *tree,
 | 
			
		||||
				    struct extent_buffer *eb);
 | 
			
		||||
int clear_extent_buffer_dirty(struct extent_io_tree *tree,
 | 
			
		||||
			      struct extent_buffer *eb);
 | 
			
		||||
int set_extent_buffer_dirty(struct extent_io_tree *tree,
 | 
			
		||||
			     struct extent_buffer *eb);
 | 
			
		||||
int set_extent_buffer_uptodate(struct extent_io_tree *tree,
 | 
			
		||||
			       struct extent_buffer *eb);
 | 
			
		||||
int extent_buffer_uptodate(struct extent_io_tree *tree,
 | 
			
		||||
			   struct extent_buffer *eb);
 | 
			
		||||
int map_extent_buffer(struct extent_buffer *eb, unsigned long offset,
 | 
			
		||||
		      unsigned long min_len, char **token, char **map,
 | 
			
		||||
		      unsigned long *map_start,
 | 
			
		||||
		      unsigned long *map_len, int km);
 | 
			
		||||
int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
 | 
			
		||||
		      unsigned long min_len, char **token, char **map,
 | 
			
		||||
		      unsigned long *map_start,
 | 
			
		||||
		      unsigned long *map_len, int km);
 | 
			
		||||
void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km);
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -3,215 +3,53 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/rbtree.h>
 | 
			
		||||
 | 
			
		||||
#define EXTENT_MAP_LAST_BYTE (u64)-4
 | 
			
		||||
#define EXTENT_MAP_HOLE (u64)-3
 | 
			
		||||
#define EXTENT_MAP_INLINE (u64)-2
 | 
			
		||||
#define EXTENT_MAP_DELALLOC (u64)-1
 | 
			
		||||
 | 
			
		||||
/* bits for the extent state */
 | 
			
		||||
#define EXTENT_DIRTY 1
 | 
			
		||||
#define EXTENT_WRITEBACK (1 << 1)
 | 
			
		||||
#define EXTENT_UPTODATE (1 << 2)
 | 
			
		||||
#define EXTENT_LOCKED (1 << 3)
 | 
			
		||||
#define EXTENT_NEW (1 << 4)
 | 
			
		||||
#define EXTENT_DELALLOC (1 << 5)
 | 
			
		||||
#define EXTENT_DEFRAG (1 << 6)
 | 
			
		||||
#define EXTENT_DEFRAG_DONE (1 << 7)
 | 
			
		||||
#define EXTENT_BUFFER_FILLED (1 << 8)
 | 
			
		||||
#define EXTENT_CSUM (1 << 9)
 | 
			
		||||
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
 | 
			
		||||
struct extent_map {
 | 
			
		||||
	struct rb_node rb_node;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * page->private values.  Every page that is controlled by the extent
 | 
			
		||||
 * map has page->private set to one.
 | 
			
		||||
 */
 | 
			
		||||
#define EXTENT_PAGE_PRIVATE 1
 | 
			
		||||
#define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct extent_map_ops {
 | 
			
		||||
	int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
 | 
			
		||||
	int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	void (*writepage_end_io_hook)(struct page *page, u64 start, u64 end);
 | 
			
		||||
	/* all of these are in bytes */
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 len;
 | 
			
		||||
	u64 block_start;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct block_device *bdev;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
	int in_tree;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_map_tree {
 | 
			
		||||
	struct rb_root map;
 | 
			
		||||
	struct rb_root state;
 | 
			
		||||
	struct address_space *mapping;
 | 
			
		||||
	u64 dirty_bytes;
 | 
			
		||||
	rwlock_t lock;
 | 
			
		||||
	struct extent_map_ops *ops;
 | 
			
		||||
	spinlock_t lru_lock;
 | 
			
		||||
	struct list_head buffer_lru;
 | 
			
		||||
	int lru_size;
 | 
			
		||||
	struct extent_map *last;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* note, this must start with the same fields as fs/extent_map.c:tree_entry */
 | 
			
		||||
struct extent_map {
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end; /* inclusive */
 | 
			
		||||
	int in_tree;
 | 
			
		||||
	struct rb_node rb_node;
 | 
			
		||||
	/* block_start and block_end are in bytes */
 | 
			
		||||
	u64 block_start;
 | 
			
		||||
	u64 block_end; /* inclusive */
 | 
			
		||||
	struct block_device *bdev;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
};
 | 
			
		||||
static inline u64 extent_map_end(struct extent_map *em)
 | 
			
		||||
{
 | 
			
		||||
	if (em->start + em->len < em->start)
 | 
			
		||||
		return (u64)-1;
 | 
			
		||||
	return em->start + em->len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* note, this must start with the same fields as fs/extent_map.c:tree_entry */
 | 
			
		||||
struct extent_state {
 | 
			
		||||
	u64 start;
 | 
			
		||||
	u64 end; /* inclusive */
 | 
			
		||||
	int in_tree;
 | 
			
		||||
	struct rb_node rb_node;
 | 
			
		||||
	wait_queue_head_t wq;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
	unsigned long state;
 | 
			
		||||
static inline u64 extent_map_block_end(struct extent_map *em)
 | 
			
		||||
{
 | 
			
		||||
	if (em->block_start + em->len < em->block_start)
 | 
			
		||||
		return (u64)-1;
 | 
			
		||||
	return em->block_start + em->len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	/* for use by the FS */
 | 
			
		||||
	u64 private;
 | 
			
		||||
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct extent_buffer {
 | 
			
		||||
	u64 start;
 | 
			
		||||
	unsigned long len;
 | 
			
		||||
	char *map_token;
 | 
			
		||||
	char *kaddr;
 | 
			
		||||
	unsigned long map_start;
 | 
			
		||||
	unsigned long map_len;
 | 
			
		||||
	struct page *first_page;
 | 
			
		||||
	struct list_head lru;
 | 
			
		||||
	atomic_t refs;
 | 
			
		||||
	int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct extent_map *(get_extent_t)(struct inode *inode,
 | 
			
		||||
					  struct page *page,
 | 
			
		||||
					  size_t page_offset,
 | 
			
		||||
					  u64 start, u64 end,
 | 
			
		||||
					  int create);
 | 
			
		||||
 | 
			
		||||
void extent_map_tree_init(struct extent_map_tree *tree,
 | 
			
		||||
			  struct address_space *mapping, gfp_t mask);
 | 
			
		||||
void extent_map_tree_empty_lru(struct extent_map_tree *tree);
 | 
			
		||||
void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask);
 | 
			
		||||
struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
 | 
			
		||||
					 u64 start, u64 end);
 | 
			
		||||
					 u64 start, u64 len);
 | 
			
		||||
int add_extent_mapping(struct extent_map_tree *tree,
 | 
			
		||||
		       struct extent_map *em);
 | 
			
		||||
int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em);
 | 
			
		||||
int try_release_extent_mapping(struct extent_map_tree *tree, struct page *page);
 | 
			
		||||
int lock_extent(struct extent_map_tree *tree, u64 start, u64 end, gfp_t mask);
 | 
			
		||||
int unlock_extent(struct extent_map_tree *tree, u64 start, u64 end, gfp_t mask);
 | 
			
		||||
 | 
			
		||||
struct extent_map *alloc_extent_map(gfp_t mask);
 | 
			
		||||
void free_extent_map(struct extent_map *em);
 | 
			
		||||
int extent_read_full_page(struct extent_map_tree *tree, struct page *page,
 | 
			
		||||
			  get_extent_t *get_extent);
 | 
			
		||||
int __init extent_map_init(void);
 | 
			
		||||
void extent_map_exit(void);
 | 
			
		||||
 | 
			
		||||
u64 count_range_bits(struct extent_map_tree *tree,
 | 
			
		||||
		     u64 *start, u64 search_end,
 | 
			
		||||
		     u64 max_bytes, unsigned long bits);
 | 
			
		||||
 | 
			
		||||
int test_range_bit(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		   int bits, int filled);
 | 
			
		||||
int clear_extent_bits(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		      int bits, gfp_t mask);
 | 
			
		||||
int set_extent_bits(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		    int bits, gfp_t mask);
 | 
			
		||||
int set_extent_uptodate(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
			gfp_t mask);
 | 
			
		||||
int set_extent_new(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		   gfp_t mask);
 | 
			
		||||
int set_extent_dirty(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		     gfp_t mask);
 | 
			
		||||
int clear_extent_dirty(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		       gfp_t mask);
 | 
			
		||||
int set_extent_delalloc(struct extent_map_tree *tree, u64 start, u64 end,
 | 
			
		||||
		     gfp_t mask);
 | 
			
		||||
int find_first_extent_bit(struct extent_map_tree *tree, u64 start,
 | 
			
		||||
			  u64 *start_ret, u64 *end_ret, int bits);
 | 
			
		||||
int extent_invalidatepage(struct extent_map_tree *tree,
 | 
			
		||||
			  struct page *page, unsigned long offset);
 | 
			
		||||
int extent_write_full_page(struct extent_map_tree *tree, struct page *page,
 | 
			
		||||
			  get_extent_t *get_extent,
 | 
			
		||||
			  struct writeback_control *wbc);
 | 
			
		||||
int extent_writepages(struct extent_map_tree *tree,
 | 
			
		||||
		      struct address_space *mapping,
 | 
			
		||||
		      get_extent_t *get_extent,
 | 
			
		||||
		      struct writeback_control *wbc);
 | 
			
		||||
int extent_readpages(struct extent_map_tree *tree,
 | 
			
		||||
		     struct address_space *mapping,
 | 
			
		||||
		     struct list_head *pages, unsigned nr_pages,
 | 
			
		||||
		     get_extent_t get_extent);
 | 
			
		||||
int extent_prepare_write(struct extent_map_tree *tree,
 | 
			
		||||
			 struct inode *inode, struct page *page,
 | 
			
		||||
			 unsigned from, unsigned to, get_extent_t *get_extent);
 | 
			
		||||
int extent_commit_write(struct extent_map_tree *tree,
 | 
			
		||||
			struct inode *inode, struct page *page,
 | 
			
		||||
			unsigned from, unsigned to);
 | 
			
		||||
sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
 | 
			
		||||
		get_extent_t *get_extent);
 | 
			
		||||
int set_range_dirty(struct extent_map_tree *tree, u64 start, u64 end);
 | 
			
		||||
int set_state_private(struct extent_map_tree *tree, u64 start, u64 private);
 | 
			
		||||
int get_state_private(struct extent_map_tree *tree, u64 start, u64 *private);
 | 
			
		||||
void set_page_extent_mapped(struct page *page);
 | 
			
		||||
 | 
			
		||||
struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree,
 | 
			
		||||
					  u64 start, unsigned long len,
 | 
			
		||||
					  struct page *page0,
 | 
			
		||||
					  gfp_t mask);
 | 
			
		||||
struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree,
 | 
			
		||||
					 u64 start, unsigned long len,
 | 
			
		||||
					  gfp_t mask);
 | 
			
		||||
void free_extent_buffer(struct extent_buffer *eb);
 | 
			
		||||
int read_extent_buffer_pages(struct extent_map_tree *tree,
 | 
			
		||||
			     struct extent_buffer *eb, u64 start, int wait);
 | 
			
		||||
 | 
			
		||||
static inline void extent_buffer_get(struct extent_buffer *eb)
 | 
			
		||||
{
 | 
			
		||||
	atomic_inc(&eb->refs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
 | 
			
		||||
			  unsigned long start,
 | 
			
		||||
			  unsigned long len);
 | 
			
		||||
void read_extent_buffer(struct extent_buffer *eb, void *dst,
 | 
			
		||||
			unsigned long start,
 | 
			
		||||
			unsigned long len);
 | 
			
		||||
void write_extent_buffer(struct extent_buffer *eb, const void *src,
 | 
			
		||||
			 unsigned long start, unsigned long len);
 | 
			
		||||
void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
 | 
			
		||||
			unsigned long dst_offset, unsigned long src_offset,
 | 
			
		||||
			unsigned long len);
 | 
			
		||||
void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 | 
			
		||||
			   unsigned long src_offset, unsigned long len);
 | 
			
		||||
void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 | 
			
		||||
			   unsigned long src_offset, unsigned long len);
 | 
			
		||||
void memset_extent_buffer(struct extent_buffer *eb, char c,
 | 
			
		||||
			  unsigned long start, unsigned long len);
 | 
			
		||||
int wait_on_extent_buffer_writeback(struct extent_map_tree *tree,
 | 
			
		||||
				    struct extent_buffer *eb);
 | 
			
		||||
int clear_extent_buffer_dirty(struct extent_map_tree *tree,
 | 
			
		||||
			      struct extent_buffer *eb);
 | 
			
		||||
int set_extent_buffer_dirty(struct extent_map_tree *tree,
 | 
			
		||||
			     struct extent_buffer *eb);
 | 
			
		||||
int set_extent_buffer_uptodate(struct extent_map_tree *tree,
 | 
			
		||||
			       struct extent_buffer *eb);
 | 
			
		||||
int extent_buffer_uptodate(struct extent_map_tree *tree,
 | 
			
		||||
			   struct extent_buffer *eb);
 | 
			
		||||
int map_extent_buffer(struct extent_buffer *eb, unsigned long offset,
 | 
			
		||||
		      unsigned long min_len, char **token, char **map,
 | 
			
		||||
		      unsigned long *map_start,
 | 
			
		||||
		      unsigned long *map_len, int km);
 | 
			
		||||
int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
 | 
			
		||||
		      unsigned long min_len, char **token, char **map,
 | 
			
		||||
		      unsigned long *map_start,
 | 
			
		||||
		      unsigned long *map_len, int km);
 | 
			
		||||
void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -233,8 +233,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int err = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
	struct inode *inode = fdentry(file)->d_inode;
 | 
			
		||||
	struct extent_map *em;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	u64 hint_byte;
 | 
			
		||||
	u64 num_bytes;
 | 
			
		||||
	u64 start_pos;
 | 
			
		||||
| 
						 | 
				
			
			@ -242,11 +241,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
	u64 end_pos = pos + write_bytes;
 | 
			
		||||
	u64 inline_size;
 | 
			
		||||
	loff_t isize = i_size_read(inode);
 | 
			
		||||
	em = alloc_extent_map(GFP_NOFS);
 | 
			
		||||
	if (!em)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	em->bdev = inode->i_sb->s_bdev;
 | 
			
		||||
 | 
			
		||||
	start_pos = pos & ~((u64)root->sectorsize - 1);
 | 
			
		||||
	num_bytes = (write_bytes + pos - start_pos +
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +248,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
	end_of_last_block = start_pos + num_bytes - 1;
 | 
			
		||||
 | 
			
		||||
	lock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
	lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
	mutex_lock(&root->fs_info->fs_mutex);
 | 
			
		||||
	trans = btrfs_start_transaction(root, 1);
 | 
			
		||||
	if (!trans) {
 | 
			
		||||
| 
						 | 
				
			
			@ -268,7 +262,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
	if ((end_of_last_block & 4095) == 0) {
 | 
			
		||||
		printk("strange end of last %Lu %zu %Lu\n", start_pos, write_bytes, end_of_last_block);
 | 
			
		||||
	}
 | 
			
		||||
	set_extent_uptodate(em_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
	set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	/* FIXME...EIEIO, ENOSPC and more */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +287,8 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
						       inode->i_ino,
 | 
			
		||||
						       last_pos_in_file,
 | 
			
		||||
						       0, 0, hole_size);
 | 
			
		||||
			btrfs_drop_extent_cache(inode, last_pos_in_file,
 | 
			
		||||
					last_pos_in_file + hole_size -1);
 | 
			
		||||
			btrfs_check_file(root, inode);
 | 
			
		||||
		}
 | 
			
		||||
		if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -320,12 +316,12 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
		last_end += PAGE_CACHE_SIZE - 1;
 | 
			
		||||
		if (start_pos < isize) {
 | 
			
		||||
			u64 delalloc_start = start_pos;
 | 
			
		||||
			existing_delalloc = count_range_bits(em_tree,
 | 
			
		||||
			existing_delalloc = count_range_bits(io_tree,
 | 
			
		||||
					     &delalloc_start,
 | 
			
		||||
					     end_of_last_block, (u64)-1,
 | 
			
		||||
					     EXTENT_DELALLOC);
 | 
			
		||||
		}
 | 
			
		||||
		set_extent_delalloc(em_tree, start_pos, end_of_last_block,
 | 
			
		||||
		set_extent_delalloc(io_tree, start_pos, end_of_last_block,
 | 
			
		||||
				 GFP_NOFS);
 | 
			
		||||
		spin_lock(&root->fs_info->delalloc_lock);
 | 
			
		||||
		root->fs_info->delalloc_bytes += (end_of_last_block + 1 -
 | 
			
		||||
| 
						 | 
				
			
			@ -346,6 +342,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
		inline_size -= start_pos;
 | 
			
		||||
		err = insert_inline_extent(trans, root, inode, start_pos,
 | 
			
		||||
					   inline_size, pages, 0, num_pages);
 | 
			
		||||
		btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1);
 | 
			
		||||
		BUG_ON(err);
 | 
			
		||||
	}
 | 
			
		||||
	if (end_pos > isize) {
 | 
			
		||||
| 
						 | 
				
			
			@ -356,8 +353,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
 | 
			
		|||
	err = btrfs_end_transaction(trans, root);
 | 
			
		||||
out_unlock:
 | 
			
		||||
	mutex_unlock(&root->fs_info->fs_mutex);
 | 
			
		||||
	unlock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
	free_extent_map(em);
 | 
			
		||||
	unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -367,10 +363,15 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
		spin_lock(&em_tree->lock);
 | 
			
		||||
		em = lookup_extent_mapping(em_tree, start, end);
 | 
			
		||||
		if (!em)
 | 
			
		||||
		if (!em) {
 | 
			
		||||
			spin_unlock(&em_tree->lock);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		remove_extent_mapping(em_tree, em);
 | 
			
		||||
		spin_unlock(&em_tree->lock);
 | 
			
		||||
 | 
			
		||||
		/* once for us */
 | 
			
		||||
		free_extent_map(em);
 | 
			
		||||
		/* once for the tree*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										175
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							
							
						
						
									
										175
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -53,7 +53,7 @@ static struct inode_operations btrfs_file_inode_operations;
 | 
			
		|||
static struct address_space_operations btrfs_aops;
 | 
			
		||||
static struct address_space_operations btrfs_symlink_aops;
 | 
			
		||||
static struct file_operations btrfs_dir_file_operations;
 | 
			
		||||
static struct extent_map_ops btrfs_extent_map_ops;
 | 
			
		||||
static struct extent_io_ops btrfs_extent_io_ops;
 | 
			
		||||
 | 
			
		||||
static struct kmem_cache *btrfs_inode_cachep;
 | 
			
		||||
struct kmem_cache *btrfs_trans_handle_cachep;
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +104,8 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
	u64 num_bytes;
 | 
			
		||||
	u64 cur_alloc_size;
 | 
			
		||||
	u64 blocksize = root->sectorsize;
 | 
			
		||||
	u64 orig_start = start;
 | 
			
		||||
	u64 orig_num_bytes;
 | 
			
		||||
	struct btrfs_key ins;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +117,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
	num_bytes = max(blocksize,  num_bytes);
 | 
			
		||||
	ret = btrfs_drop_extents(trans, root, inode,
 | 
			
		||||
				 start, start + num_bytes, start, &alloc_hint);
 | 
			
		||||
	orig_num_bytes = num_bytes;
 | 
			
		||||
 | 
			
		||||
	if (alloc_hint == EXTENT_MAP_INLINE)
 | 
			
		||||
		goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +141,8 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
		alloc_hint = ins.objectid + ins.offset;
 | 
			
		||||
		start += cur_alloc_size;
 | 
			
		||||
	}
 | 
			
		||||
	btrfs_drop_extent_cache(inode, orig_start,
 | 
			
		||||
				orig_start + orig_num_bytes - 1);
 | 
			
		||||
	btrfs_add_ordered_inode(inode);
 | 
			
		||||
out:
 | 
			
		||||
	btrfs_end_transaction(trans, root);
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +302,7 @@ int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
 | 
			
		|||
	int ret = 0;
 | 
			
		||||
	struct inode *inode = page->mapping->host;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	struct btrfs_csum_item *item;
 | 
			
		||||
	struct btrfs_path *path = NULL;
 | 
			
		||||
	u32 csum;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,7 +322,7 @@ int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
 | 
			
		|||
	}
 | 
			
		||||
	read_extent_buffer(path->nodes[0], &csum, (unsigned long)item,
 | 
			
		||||
			   BTRFS_CRC32_SIZE);
 | 
			
		||||
	set_state_private(em_tree, start, csum);
 | 
			
		||||
	set_state_private(io_tree, start, csum);
 | 
			
		||||
out:
 | 
			
		||||
	if (path)
 | 
			
		||||
		btrfs_free_path(path);
 | 
			
		||||
| 
						 | 
				
			
			@ -329,17 +334,19 @@ int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end)
 | 
			
		|||
{
 | 
			
		||||
	size_t offset = start - ((u64)page->index << PAGE_CACHE_SHIFT);
 | 
			
		||||
	struct inode *inode = page->mapping->host;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	char *kaddr;
 | 
			
		||||
	u64 private;
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	u32 csum = ~(u32)0;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_test_opt(root, NODATASUM) ||
 | 
			
		||||
	    btrfs_test_flag(inode, NODATASUM))
 | 
			
		||||
		return 0;
 | 
			
		||||
	ret = get_state_private(em_tree, start, &private);
 | 
			
		||||
 | 
			
		||||
	ret = get_state_private(io_tree, start, &private);
 | 
			
		||||
	local_irq_save(flags);
 | 
			
		||||
	kaddr = kmap_atomic(page, KM_IRQ0);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +435,7 @@ void btrfs_read_locked_inode(struct inode *inode)
 | 
			
		|||
	switch (inode->i_mode & S_IFMT) {
 | 
			
		||||
	case S_IFREG:
 | 
			
		||||
		inode->i_mapping->a_ops = &btrfs_aops;
 | 
			
		||||
		BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
 | 
			
		||||
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
		inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
		inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			@ -873,7 +880,7 @@ static int btrfs_cow_one_page(struct inode *inode, struct page *page,
 | 
			
		|||
			      size_t zero_start)
 | 
			
		||||
{
 | 
			
		||||
	char *kaddr;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	u64 page_start = (u64)page->index << PAGE_CACHE_SHIFT;
 | 
			
		||||
	u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -884,12 +891,12 @@ static int btrfs_cow_one_page(struct inode *inode, struct page *page,
 | 
			
		|||
	WARN_ON(!PageLocked(page));
 | 
			
		||||
	set_page_extent_mapped(page);
 | 
			
		||||
 | 
			
		||||
	lock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
	lock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
	delalloc_start = page_start;
 | 
			
		||||
	existing_delalloc = count_range_bits(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
	existing_delalloc = count_range_bits(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
					     &delalloc_start, page_end,
 | 
			
		||||
					     PAGE_CACHE_SIZE, EXTENT_DELALLOC);
 | 
			
		||||
	set_extent_delalloc(&BTRFS_I(inode)->extent_tree, page_start,
 | 
			
		||||
	set_extent_delalloc(&BTRFS_I(inode)->io_tree, page_start,
 | 
			
		||||
			    page_end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	spin_lock(&root->fs_info->delalloc_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -903,7 +910,7 @@ static int btrfs_cow_one_page(struct inode *inode, struct page *page,
 | 
			
		|||
		kunmap(page);
 | 
			
		||||
	}
 | 
			
		||||
	set_page_dirty(page);
 | 
			
		||||
	unlock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
	unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -961,7 +968,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
			
		|||
	    attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
 | 
			
		||||
		struct btrfs_trans_handle *trans;
 | 
			
		||||
		struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
		struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
		struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
 | 
			
		||||
		u64 mask = root->sectorsize - 1;
 | 
			
		||||
		u64 pos = (inode->i_size + mask) & ~mask;
 | 
			
		||||
| 
						 | 
				
			
			@ -986,7 +993,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
			
		|||
 | 
			
		||||
		btrfs_truncate_page(inode->i_mapping, inode->i_size);
 | 
			
		||||
 | 
			
		||||
		lock_extent(em_tree, pos, block_end, GFP_NOFS);
 | 
			
		||||
		lock_extent(io_tree, pos, block_end, GFP_NOFS);
 | 
			
		||||
		hole_size = block_end - hole_start;
 | 
			
		||||
 | 
			
		||||
		mutex_lock(&root->fs_info->fs_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -1001,11 +1008,13 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
			
		|||
						       inode->i_ino,
 | 
			
		||||
						       hole_start, 0, 0,
 | 
			
		||||
						       hole_size);
 | 
			
		||||
			btrfs_drop_extent_cache(inode, hole_start,
 | 
			
		||||
						hole_size - 1);
 | 
			
		||||
			btrfs_check_file(root, inode);
 | 
			
		||||
		}
 | 
			
		||||
		btrfs_end_transaction(trans, root);
 | 
			
		||||
		mutex_unlock(&root->fs_info->fs_mutex);
 | 
			
		||||
		unlock_extent(em_tree, pos, block_end, GFP_NOFS);
 | 
			
		||||
		unlock_extent(io_tree, pos, block_end, GFP_NOFS);
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1189,7 +1198,8 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
 | 
			
		|||
	struct btrfs_iget_args *args = p;
 | 
			
		||||
	inode->i_ino = args->ino;
 | 
			
		||||
	BTRFS_I(inode)->root = args->root;
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
			     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1485,7 +1495,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	if (!inode)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
			     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	BTRFS_I(inode)->root = root;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1672,9 +1683,10 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
 | 
			
		|||
		inode->i_mapping->a_ops = &btrfs_aops;
 | 
			
		||||
		inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
		inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
 | 
			
		||||
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
	}
 | 
			
		||||
	dir->i_sb->s_dirt = 1;
 | 
			
		||||
	btrfs_update_inode_block_group(trans, inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -1816,7 +1828,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		||||
				    size_t page_offset, u64 start, u64 end,
 | 
			
		||||
				    size_t page_offset, u64 start, u64 len,
 | 
			
		||||
				    int create)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,7 +1838,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
	u64 extent_end = 0;
 | 
			
		||||
	u64 objectid = inode->i_ino;
 | 
			
		||||
	u32 found_type;
 | 
			
		||||
	int failed_insert = 0;
 | 
			
		||||
	struct btrfs_path *path;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	struct btrfs_file_extent_item *item;
 | 
			
		||||
| 
						 | 
				
			
			@ -1834,6 +1845,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
	struct btrfs_key found_key;
 | 
			
		||||
	struct extent_map *em = NULL;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	struct btrfs_trans_handle *trans = NULL;
 | 
			
		||||
 | 
			
		||||
	path = btrfs_alloc_path();
 | 
			
		||||
| 
						 | 
				
			
			@ -1841,24 +1853,26 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
	mutex_lock(&root->fs_info->fs_mutex);
 | 
			
		||||
 | 
			
		||||
again:
 | 
			
		||||
	em = lookup_extent_mapping(em_tree, start, end);
 | 
			
		||||
	spin_lock(&em_tree->lock);
 | 
			
		||||
	em = lookup_extent_mapping(em_tree, start, len);
 | 
			
		||||
	spin_unlock(&em_tree->lock);
 | 
			
		||||
 | 
			
		||||
	if (em) {
 | 
			
		||||
		if (em->start > start) {
 | 
			
		||||
			printk("get_extent start %Lu em start %Lu\n",
 | 
			
		||||
			       start, em->start);
 | 
			
		||||
			printk("get_extent lookup [%Lu %Lu] em [%Lu %Lu]\n",
 | 
			
		||||
			       start, len, em->start, em->len);
 | 
			
		||||
			WARN_ON(1);
 | 
			
		||||
		}
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	em = alloc_extent_map(GFP_NOFS);
 | 
			
		||||
	if (!em) {
 | 
			
		||||
		em = alloc_extent_map(GFP_NOFS);
 | 
			
		||||
		if (!em) {
 | 
			
		||||
			err = -ENOMEM;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		em->start = EXTENT_MAP_HOLE;
 | 
			
		||||
		em->end = EXTENT_MAP_HOLE;
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	em->start = EXTENT_MAP_HOLE;
 | 
			
		||||
	em->len = (u64)-1;
 | 
			
		||||
	em->bdev = inode->i_sb->s_bdev;
 | 
			
		||||
	ret = btrfs_lookup_file_extent(trans, root, path,
 | 
			
		||||
				       objectid, start, trans != NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -1893,28 +1907,25 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
		if (start < extent_start || start >= extent_end) {
 | 
			
		||||
			em->start = start;
 | 
			
		||||
			if (start < extent_start) {
 | 
			
		||||
				if (end < extent_start)
 | 
			
		||||
				if (start + len <= extent_start)
 | 
			
		||||
					goto not_found;
 | 
			
		||||
				em->end = extent_end - 1;
 | 
			
		||||
				em->len = extent_end - extent_start;
 | 
			
		||||
			} else {
 | 
			
		||||
				em->end = end;
 | 
			
		||||
				em->len = len;
 | 
			
		||||
			}
 | 
			
		||||
			goto not_found_em;
 | 
			
		||||
		}
 | 
			
		||||
		bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
 | 
			
		||||
		if (bytenr == 0) {
 | 
			
		||||
			em->start = extent_start;
 | 
			
		||||
			em->end = extent_end - 1;
 | 
			
		||||
			em->len = extent_end - extent_start;
 | 
			
		||||
			em->block_start = EXTENT_MAP_HOLE;
 | 
			
		||||
			em->block_end = EXTENT_MAP_HOLE;
 | 
			
		||||
			goto insert;
 | 
			
		||||
		}
 | 
			
		||||
		bytenr += btrfs_file_extent_offset(leaf, item);
 | 
			
		||||
		em->block_start = bytenr;
 | 
			
		||||
		em->block_end = em->block_start +
 | 
			
		||||
			btrfs_file_extent_num_bytes(leaf, item) - 1;
 | 
			
		||||
		em->start = extent_start;
 | 
			
		||||
		em->end = extent_end - 1;
 | 
			
		||||
		em->len = extent_end - extent_start;
 | 
			
		||||
		goto insert;
 | 
			
		||||
	} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
 | 
			
		||||
		unsigned long ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -1925,25 +1936,24 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
 | 
			
		||||
		size = btrfs_file_extent_inline_len(leaf, btrfs_item_nr(leaf,
 | 
			
		||||
						    path->slots[0]));
 | 
			
		||||
		extent_end = (extent_start + size - 1) |
 | 
			
		||||
			((u64)root->sectorsize - 1);
 | 
			
		||||
		extent_end = (extent_start + size + root->sectorsize - 1) &
 | 
			
		||||
			~((u64)root->sectorsize - 1);
 | 
			
		||||
		if (start < extent_start || start >= extent_end) {
 | 
			
		||||
			em->start = start;
 | 
			
		||||
			if (start < extent_start) {
 | 
			
		||||
				if (end < extent_start)
 | 
			
		||||
				if (start + len <= extent_start)
 | 
			
		||||
					goto not_found;
 | 
			
		||||
				em->end = extent_end;
 | 
			
		||||
				em->len = extent_end - extent_start;
 | 
			
		||||
			} else {
 | 
			
		||||
				em->end = end;
 | 
			
		||||
				em->len = len;
 | 
			
		||||
			}
 | 
			
		||||
			goto not_found_em;
 | 
			
		||||
		}
 | 
			
		||||
		em->block_start = EXTENT_MAP_INLINE;
 | 
			
		||||
		em->block_end = EXTENT_MAP_INLINE;
 | 
			
		||||
 | 
			
		||||
		if (!page) {
 | 
			
		||||
			em->start = extent_start;
 | 
			
		||||
			em->end = extent_start + size - 1;
 | 
			
		||||
			em->len = size;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1952,8 +1962,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
		copy_size = min_t(u64, PAGE_CACHE_SIZE - page_offset,
 | 
			
		||||
				size - extent_offset);
 | 
			
		||||
		em->start = extent_start + extent_offset;
 | 
			
		||||
		em->end = (em->start + copy_size -1) |
 | 
			
		||||
			((u64)root->sectorsize -1);
 | 
			
		||||
		em->len = copy_size;
 | 
			
		||||
		map = kmap(page);
 | 
			
		||||
		ptr = btrfs_file_extent_inline_start(item) + extent_offset;
 | 
			
		||||
		if (create == 0 && !PageUptodate(page)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1974,7 +1983,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
			btrfs_mark_buffer_dirty(leaf);
 | 
			
		||||
		}
 | 
			
		||||
		kunmap(page);
 | 
			
		||||
		set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS);
 | 
			
		||||
		set_extent_uptodate(io_tree, em->start,
 | 
			
		||||
				    extent_map_end(em) - 1, GFP_NOFS);
 | 
			
		||||
		goto insert;
 | 
			
		||||
	} else {
 | 
			
		||||
		printk("unkknown found_type %d\n", found_type);
 | 
			
		||||
| 
						 | 
				
			
			@ -1982,33 +1992,29 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
 | 
			
		|||
	}
 | 
			
		||||
not_found:
 | 
			
		||||
	em->start = start;
 | 
			
		||||
	em->end = end;
 | 
			
		||||
	em->len = len;
 | 
			
		||||
not_found_em:
 | 
			
		||||
	em->block_start = EXTENT_MAP_HOLE;
 | 
			
		||||
	em->block_end = EXTENT_MAP_HOLE;
 | 
			
		||||
insert:
 | 
			
		||||
	btrfs_release_path(root, path);
 | 
			
		||||
	if (em->start > start || em->end < start) {
 | 
			
		||||
		printk("bad extent! em: [%Lu %Lu] passed [%Lu %Lu]\n", em->start, em->end, start, end);
 | 
			
		||||
	if (em->start > start || extent_map_end(em) <= start) {
 | 
			
		||||
		printk("bad extent! em: [%Lu %Lu] passed [%Lu %Lu]\n", em->start, em->len, start, len);
 | 
			
		||||
		err = -EIO;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = 0;
 | 
			
		||||
	spin_lock(&em_tree->lock);
 | 
			
		||||
	ret = add_extent_mapping(em_tree, em);
 | 
			
		||||
	if (ret == -EEXIST) {
 | 
			
		||||
		free_extent_map(em);
 | 
			
		||||
		em = NULL;
 | 
			
		||||
		if (0 && failed_insert == 1) {
 | 
			
		||||
			btrfs_drop_extent_cache(inode, start, end);
 | 
			
		||||
		}
 | 
			
		||||
		failed_insert++;
 | 
			
		||||
		if (failed_insert > 5) {
 | 
			
		||||
			printk("failing to insert %Lu %Lu\n", start, end);
 | 
			
		||||
		em = lookup_extent_mapping(em_tree, start, len);
 | 
			
		||||
		if (!em) {
 | 
			
		||||
			err = -EIO;
 | 
			
		||||
			goto out;
 | 
			
		||||
			printk("failing to insert %Lu %Lu\n", start, len);
 | 
			
		||||
		}
 | 
			
		||||
		goto again;
 | 
			
		||||
	}
 | 
			
		||||
	err = 0;
 | 
			
		||||
	spin_unlock(&em_tree->lock);
 | 
			
		||||
out:
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
	if (trans) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2032,14 +2038,14 @@ static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock)
 | 
			
		|||
 | 
			
		||||
int btrfs_readpage(struct file *file, struct page *page)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	return extent_read_full_page(tree, page, btrfs_get_extent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (current->flags & PF_MEMALLOC) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2047,15 +2053,15 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
 | 
			
		|||
		unlock_page(page);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	return extent_write_full_page(tree, page, btrfs_get_extent, wbc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_writepages(struct address_space *mapping,
 | 
			
		||||
			    struct writeback_control *wbc)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->io_tree;
 | 
			
		||||
	return extent_writepages(tree, mapping, btrfs_get_extent, wbc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2063,19 +2069,21 @@ static int
 | 
			
		|||
btrfs_readpages(struct file *file, struct address_space *mapping,
 | 
			
		||||
		struct list_head *pages, unsigned nr_pages)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	tree = &BTRFS_I(mapping->host)->io_tree;
 | 
			
		||||
	return extent_readpages(tree, mapping, pages, nr_pages,
 | 
			
		||||
				btrfs_get_extent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
	struct extent_map_tree *map;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	ret = try_release_extent_mapping(tree, page);
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	map = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	ret = try_release_extent_mapping(map, tree, page);
 | 
			
		||||
	if (ret == 1) {
 | 
			
		||||
		ClearPagePrivate(page);
 | 
			
		||||
		set_page_private(page, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -2086,9 +2094,9 @@ static int btrfs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 | 
			
		|||
 | 
			
		||||
static void btrfs_invalidatepage(struct page *page, unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_map_tree *tree;
 | 
			
		||||
	struct extent_io_tree *tree;
 | 
			
		||||
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->extent_tree;
 | 
			
		||||
	tree = &BTRFS_I(page->mapping->host)->io_tree;
 | 
			
		||||
	extent_invalidatepage(tree, page, offset);
 | 
			
		||||
	btrfs_releasepage(page, GFP_NOFS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2374,7 +2382,7 @@ unsigned long btrfs_force_ra(struct address_space *mapping,
 | 
			
		|||
int btrfs_defrag_file(struct file *file) {
 | 
			
		||||
	struct inode *inode = fdentry(file)->d_inode;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
 | 
			
		||||
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 | 
			
		||||
	struct page *page;
 | 
			
		||||
	unsigned long last_index;
 | 
			
		||||
	unsigned long ra_index = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2414,13 +2422,13 @@ int btrfs_defrag_file(struct file *file) {
 | 
			
		|||
		page_start = (u64)page->index << PAGE_CACHE_SHIFT;
 | 
			
		||||
		page_end = page_start + PAGE_CACHE_SIZE - 1;
 | 
			
		||||
 | 
			
		||||
		lock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		lock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		delalloc_start = page_start;
 | 
			
		||||
		existing_delalloc =
 | 
			
		||||
			count_range_bits(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
			count_range_bits(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
					 &delalloc_start, page_end,
 | 
			
		||||
					 PAGE_CACHE_SIZE, EXTENT_DELALLOC);
 | 
			
		||||
		set_extent_delalloc(em_tree, page_start,
 | 
			
		||||
		set_extent_delalloc(io_tree, page_start,
 | 
			
		||||
				    page_end, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
		spin_lock(&root->fs_info->delalloc_lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -2428,7 +2436,7 @@ int btrfs_defrag_file(struct file *file) {
 | 
			
		|||
						 existing_delalloc;
 | 
			
		||||
		spin_unlock(&root->fs_info->delalloc_lock);
 | 
			
		||||
 | 
			
		||||
		unlock_extent(em_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
 | 
			
		||||
		set_page_dirty(page);
 | 
			
		||||
		unlock_page(page);
 | 
			
		||||
		page_cache_release(page);
 | 
			
		||||
| 
						 | 
				
			
			@ -2842,9 +2850,10 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 | 
			
		|||
		inode->i_mapping->a_ops = &btrfs_aops;
 | 
			
		||||
		inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
		inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree,
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		BTRFS_I(inode)->extent_tree.ops = &btrfs_extent_map_ops;
 | 
			
		||||
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
	}
 | 
			
		||||
	dir->i_sb->s_dirt = 1;
 | 
			
		||||
	btrfs_update_inode_block_group(trans, inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -2934,7 +2943,7 @@ static struct file_operations btrfs_dir_file_operations = {
 | 
			
		|||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct extent_map_ops btrfs_extent_map_ops = {
 | 
			
		||||
static struct extent_io_ops btrfs_extent_io_ops = {
 | 
			
		||||
	.fill_delalloc = run_delalloc_range,
 | 
			
		||||
	.writepage_io_hook = btrfs_writepage_io_hook,
 | 
			
		||||
	.readpage_io_hook = btrfs_readpage_io_hook,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -468,10 +468,15 @@ static int __init init_btrfs_fs(void)
 | 
			
		|||
	err = btrfs_init_cachep();
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto free_transaction_sys;
 | 
			
		||||
	err = extent_map_init();
 | 
			
		||||
 | 
			
		||||
	err = extent_io_init();
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto free_cachep;
 | 
			
		||||
 | 
			
		||||
	err = extent_map_init();
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto free_extent_io;
 | 
			
		||||
 | 
			
		||||
	err = register_filesystem(&btrfs_fs_type);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto free_extent_map;
 | 
			
		||||
| 
						 | 
				
			
			@ -479,6 +484,8 @@ static int __init init_btrfs_fs(void)
 | 
			
		|||
 | 
			
		||||
free_extent_map:
 | 
			
		||||
	extent_map_exit();
 | 
			
		||||
free_extent_io:
 | 
			
		||||
	extent_io_exit();
 | 
			
		||||
free_cachep:
 | 
			
		||||
	btrfs_destroy_cachep();
 | 
			
		||||
free_transaction_sys:
 | 
			
		||||
| 
						 | 
				
			
			@ -492,6 +499,7 @@ static void __exit exit_btrfs_fs(void)
 | 
			
		|||
	btrfs_exit_transaction_sys();
 | 
			
		||||
	btrfs_destroy_cachep();
 | 
			
		||||
	extent_map_exit();
 | 
			
		||||
	extent_io_exit();
 | 
			
		||||
	unregister_filesystem(&btrfs_fs_type);
 | 
			
		||||
	btrfs_exit_sysfs();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ static int join_transaction(struct btrfs_root *root)
 | 
			
		|||
		INIT_LIST_HEAD(&cur_trans->pending_snapshots);
 | 
			
		||||
		list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
 | 
			
		||||
		btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree);
 | 
			
		||||
		extent_map_tree_init(&cur_trans->dirty_pages,
 | 
			
		||||
		extent_io_tree_init(&cur_trans->dirty_pages,
 | 
			
		||||
				     root->fs_info->btree_inode->i_mapping,
 | 
			
		||||
				     GFP_NOFS);
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int ret;
 | 
			
		||||
	int err;
 | 
			
		||||
	int werr = 0;
 | 
			
		||||
	struct extent_map_tree *dirty_pages;
 | 
			
		||||
	struct extent_io_tree *dirty_pages;
 | 
			
		||||
	struct page *page;
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	u64 start;
 | 
			
		||||
| 
						 | 
				
			
			@ -610,7 +610,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_transaction *cur_trans;
 | 
			
		||||
	struct btrfs_transaction *prev_trans = NULL;
 | 
			
		||||
	struct list_head dirty_fs_roots;
 | 
			
		||||
	struct extent_map_tree *pinned_copy;
 | 
			
		||||
	struct extent_io_tree *pinned_copy;
 | 
			
		||||
	DEFINE_WAIT(wait);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -639,7 +639,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
	if (!pinned_copy)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	extent_map_tree_init(pinned_copy,
 | 
			
		||||
	extent_io_tree_init(pinned_copy,
 | 
			
		||||
			     root->fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	trans->transaction->in_commit = 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ struct btrfs_transaction {
 | 
			
		|||
	int use_count;
 | 
			
		||||
	int commit_done;
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	struct extent_map_tree dirty_pages;
 | 
			
		||||
	struct extent_io_tree dirty_pages;
 | 
			
		||||
	unsigned long start_time;
 | 
			
		||||
	struct btrfs_ordered_inode_tree ordered_inode_tree;
 | 
			
		||||
	wait_queue_head_t writer_wait;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue