Commit d1310b2e authored by Chris Mason's avatar Chris Mason

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: default avatarChris Mason <chris.mason@oracle.com>
parent 5f56406a
...@@ -5,7 +5,8 @@ obj-m := btrfs.o ...@@ -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 \ 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 \ 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 \ 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) ifeq ($(CONFIG_FS_POSIX_ACL),y)
btrfs-y += acl.o btrfs-y += acl.o
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define __BTRFS_I__ #define __BTRFS_I__
#include "extent_map.h" #include "extent_map.h"
#include "extent_io.h"
/* in memory btrfs inode */ /* in memory btrfs inode */
struct btrfs_inode { struct btrfs_inode {
...@@ -27,6 +28,7 @@ struct btrfs_inode { ...@@ -27,6 +28,7 @@ struct btrfs_inode {
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
struct btrfs_key location; struct btrfs_key location;
struct extent_map_tree extent_tree; struct extent_map_tree extent_tree;
struct extent_io_tree io_tree;
struct inode vfs_inode; struct inode vfs_inode;
u64 ordered_trans; u64 ordered_trans;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <asm/kmap_types.h> #include <asm/kmap_types.h>
#include "bit-radix.h" #include "bit-radix.h"
#include "extent_io.h"
#include "extent_map.h" #include "extent_map.h"
struct btrfs_trans_handle; struct btrfs_trans_handle;
...@@ -314,11 +315,11 @@ struct btrfs_fs_info { ...@@ -314,11 +315,11 @@ struct btrfs_fs_info {
struct btrfs_root *tree_root; struct btrfs_root *tree_root;
struct radix_tree_root fs_roots_radix; struct radix_tree_root fs_roots_radix;
struct extent_map_tree free_space_cache; struct extent_io_tree free_space_cache;
struct extent_map_tree block_group_cache; struct extent_io_tree block_group_cache;
struct extent_map_tree pinned_extents; struct extent_io_tree pinned_extents;
struct extent_map_tree pending_del; struct extent_io_tree pending_del;
struct extent_map_tree extent_ins; struct extent_io_tree extent_ins;
u64 generation; u64 generation;
u64 last_trans_committed; u64 last_trans_committed;
...@@ -956,7 +957,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, ...@@ -956,7 +957,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
u64 first_extent); u64 first_extent);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans, int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root); 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 struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
btrfs_fs_info *info, btrfs_fs_info *info,
u64 bytenr); u64 bytenr);
...@@ -1001,7 +1002,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1001,7 +1002,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
u64 owner_objectid, u64 owner_offset, int pin); u64 owner_objectid, u64 owner_offset, int pin);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_map_tree *unpin); struct extent_io_tree *unpin);
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 bytenr, u64 num_bytes,
......
This diff is collapsed.
...@@ -63,7 +63,7 @@ static int cache_block_group(struct btrfs_root *root, ...@@ -63,7 +63,7 @@ static int cache_block_group(struct btrfs_root *root,
int ret; int ret;
struct btrfs_key key; struct btrfs_key key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct extent_map_tree *free_space_cache; struct extent_io_tree *free_space_cache;
int slot; int slot;
u64 last = 0; u64 last = 0;
u64 hole_size; u64 hole_size;
...@@ -158,7 +158,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct ...@@ -158,7 +158,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
btrfs_fs_info *info, btrfs_fs_info *info,
u64 bytenr) u64 bytenr)
{ {
struct extent_map_tree *block_group_cache; struct extent_io_tree *block_group_cache;
struct btrfs_block_group_cache *block_group = NULL; struct btrfs_block_group_cache *block_group = NULL;
u64 ptr; u64 ptr;
u64 start; u64 start;
...@@ -281,7 +281,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -281,7 +281,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
int data, int owner) int data, int owner)
{ {
struct btrfs_block_group_cache *cache; 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_block_group_cache *found_group = NULL;
struct btrfs_fs_info *info = root->fs_info; struct btrfs_fs_info *info = root->fs_info;
u64 used; u64 used;
...@@ -951,7 +951,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, ...@@ -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, int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root) struct btrfs_root *root)
{ {
struct extent_map_tree *block_group_cache; struct extent_io_tree *block_group_cache;
struct btrfs_block_group_cache *cache; struct btrfs_block_group_cache *cache;
int ret; int ret;
int err = 0; int err = 0;
...@@ -1107,12 +1107,12 @@ static int update_pinned_extents(struct btrfs_root *root, ...@@ -1107,12 +1107,12 @@ static int update_pinned_extents(struct btrfs_root *root,
return 0; 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 last = 0;
u64 start; u64 start;
u64 end; 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; int ret;
while(1) { while(1) {
...@@ -1128,12 +1128,12 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_map_tree *copy) ...@@ -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, int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_map_tree *unpin) struct extent_io_tree *unpin)
{ {
u64 start; u64 start;
u64 end; u64 end;
int ret; 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; free_space_cache = &root->fs_info->free_space_cache;
while(1) { while(1) {
...@@ -1329,8 +1329,8 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct ...@@ -1329,8 +1329,8 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
int err = 0; int err = 0;
u64 start; u64 start;
u64 end; u64 end;
struct extent_map_tree *pending_del; struct extent_io_tree *pending_del;
struct extent_map_tree *pinned_extents; struct extent_io_tree *pinned_extents;
pending_del = &extent_root->fs_info->pending_del; pending_del = &extent_root->fs_info->pending_del;
pinned_extents = &extent_root->fs_info->pinned_extents; pinned_extents = &extent_root->fs_info->pinned_extents;
...@@ -1802,7 +1802,7 @@ struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -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, set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS); 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, buf->start, buf->start + buf->len - 1,
EXTENT_CSUM, GFP_NOFS); EXTENT_CSUM, GFP_NOFS);
buf->flags |= EXTENT_CSUM; buf->flags |= EXTENT_CSUM;
...@@ -2166,7 +2166,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start, ...@@ -2166,7 +2166,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
unsigned long i; unsigned long i;
struct page *page; struct page *page;
struct btrfs_root *root = BTRFS_I(inode)->root; 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; struct file_ra_state *ra;
ra = kzalloc(sizeof(*ra), GFP_NOFS); ra = kzalloc(sizeof(*ra), GFP_NOFS);
...@@ -2195,15 +2195,14 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start, ...@@ -2195,15 +2195,14 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
page_start = (u64)page->index << PAGE_CACHE_SHIFT; page_start = (u64)page->index << PAGE_CACHE_SHIFT;
page_end = page_start + PAGE_CACHE_SIZE - 1; 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; delalloc_start = page_start;
existing_delalloc = existing_delalloc = count_range_bits(io_tree,
count_range_bits(&BTRFS_I(inode)->extent_tree,
&delalloc_start, page_end, &delalloc_start, page_end,
PAGE_CACHE_SIZE, EXTENT_DELALLOC); PAGE_CACHE_SIZE, EXTENT_DELALLOC);
set_extent_delalloc(em_tree, page_start, set_extent_delalloc(io_tree, page_start,
page_end, GFP_NOFS); page_end, GFP_NOFS);
spin_lock(&root->fs_info->delalloc_lock); spin_lock(&root->fs_info->delalloc_lock);
...@@ -2211,7 +2210,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start, ...@@ -2211,7 +2210,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
existing_delalloc; existing_delalloc;
spin_unlock(&root->fs_info->delalloc_lock); 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); set_page_dirty(page);
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
...@@ -2379,7 +2378,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size) ...@@ -2379,7 +2378,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size)
u64 cur_byte; u64 cur_byte;
u64 total_found; u64 total_found;
struct btrfs_fs_info *info = root->fs_info; 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 key;
struct btrfs_key found_key; struct btrfs_key found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -2561,7 +2560,7 @@ int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans, ...@@ -2561,7 +2560,7 @@ int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *cache; struct btrfs_block_group_cache *cache;
struct btrfs_block_group_item *item; struct btrfs_block_group_item *item;
struct btrfs_fs_info *info = root->fs_info; 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 key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int ret; int ret;
...@@ -2645,7 +2644,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) ...@@ -2645,7 +2644,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
int bit; int bit;
struct btrfs_block_group_cache *cache; struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *info = root->fs_info; 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 key;
struct btrfs_key found_key; struct btrfs_key found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
......
This diff is collapsed.
#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
This diff is collapsed.
...@@ -3,215 +3,53 @@ ...@@ -3,215 +3,53 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#define EXTENT_MAP_LAST_BYTE (u64)-4
#define EXTENT_MAP_HOLE (u64)-3 #define EXTENT_MAP_HOLE (u64)-3
#define EXTENT_MAP_INLINE (u64)-2 #define EXTENT_MAP_INLINE (u64)-2
#define EXTENT_MAP_DELALLOC (u64)-1 #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)
/*
* 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);
};
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;
};
/* note, this must start with the same fields as fs/extent_map.c:tree_entry */
struct extent_map { struct extent_map {
u64 start;
u64 end; /* inclusive */
int in_tree;
struct rb_node rb_node; struct rb_node rb_node;
/* block_start and block_end are in bytes */
/* all of these are in bytes */
u64 start;
u64 len;
u64 block_start; u64 block_start;
u64 block_end; /* inclusive */ unsigned long flags;
struct block_device *bdev; struct block_device *bdev;
atomic_t refs; atomic_t refs;
};
/* 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; 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 { struct extent_map_tree {
u64 start; struct rb_root map;
unsigned long len; struct extent_map *last;
char *map_token; spinlock_t lock;
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, static inline u64 extent_map_end(struct extent_map *em)
struct page *page, {
size_t page_offset, if (em->start + em->len < em->start)
u64 start, u64 end, return (u64)-1;
int create); return em->start + em->len;
}
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;
}
void extent_map_tree_init(struct extent_map_tree *tree, void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask);
struct address_space *mapping, gfp_t mask);
void extent_map_tree_empty_lru(struct extent_map_tree *tree);
struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, 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, int add_extent_mapping(struct extent_map_tree *tree,
struct extent_map *em); struct extent_map *em);
int remove_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); struct extent_map *alloc_extent_map(gfp_t mask);
void free_extent_map(struct extent_map *em); 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); int __init extent_map_init(void);
void extent_map_exit(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 #endif
...@@ -233,8 +233,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -233,8 +233,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
int err = 0; int err = 0;
int i; int i;
struct inode *inode = fdentry(file)->d_inode; struct inode *inode = fdentry(file)->d_inode;
struct extent_map *em; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
u64 hint_byte; u64 hint_byte;
u64 num_bytes; u64 num_bytes;
u64 start_pos; u64 start_pos;
...@@ -242,11 +241,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -242,11 +241,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
u64 end_pos = pos + write_bytes; u64 end_pos = pos + write_bytes;
u64 inline_size; u64 inline_size;
loff_t isize = i_size_read(inode); 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); start_pos = pos & ~((u64)root->sectorsize - 1);
num_bytes = (write_bytes + pos - start_pos + num_bytes = (write_bytes + pos - start_pos +
...@@ -254,7 +248,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -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; 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); mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
if (!trans) { if (!trans) {
...@@ -268,7 +262,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -268,7 +262,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
if ((end_of_last_block & 4095) == 0) { if ((end_of_last_block & 4095) == 0) {
printk("strange end of last %Lu %zu %Lu\n", start_pos, write_bytes, end_of_last_block); 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 */ /* FIXME...EIEIO, ENOSPC and more */
...@@ -293,6 +287,8 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -293,6 +287,8 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
inode->i_ino, inode->i_ino,
last_pos_in_file, last_pos_in_file,
0, 0, hole_size); 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); btrfs_check_file(root, inode);
} }
if (err) if (err)
...@@ -320,12 +316,12 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -320,12 +316,12 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
last_end += PAGE_CACHE_SIZE - 1; last_end += PAGE_CACHE_SIZE - 1;
if (start_pos < isize) { if (start_pos < isize) {
u64 delalloc_start = start_pos; u64 delalloc_start = start_pos;
existing_delalloc = count_range_bits(em_tree, existing_delalloc = count_range_bits(io_tree,
&delalloc_start, &delalloc_start,
end_of_last_block, (u64)-1, end_of_last_block, (u64)-1,
EXTENT_DELALLOC); 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); GFP_NOFS);
spin_lock(&root->fs_info->delalloc_lock); spin_lock(&root->fs_info->delalloc_lock);
root->fs_info->delalloc_bytes += (end_of_last_block + 1 - 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, ...@@ -346,6 +342,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
inline_size -= start_pos; inline_size -= start_pos;
err = insert_inline_extent(trans, root, inode, start_pos, err = insert_inline_extent(trans, root, inode, start_pos,
inline_size, pages, 0, num_pages); inline_size, pages, 0, num_pages);
btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1);
BUG_ON(err); BUG_ON(err);
} }
if (end_pos > isize) { if (end_pos > isize) {
...@@ -356,8 +353,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -356,8 +353,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
err = btrfs_end_transaction(trans, root); err = btrfs_end_transaction(trans, root);
out_unlock: out_unlock:
mutex_unlock(&root->fs_info->fs_mutex); mutex_unlock(&root->fs_info->fs_mutex);
unlock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS); unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
free_extent_map(em);
return err; return err;
} }
...@@ -367,10 +363,15 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) ...@@ -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; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
while(1) { while(1) {
spin_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, end); em = lookup_extent_mapping(em_tree, start, end);
if (!em) if (!em) {
spin_unlock(&em_tree->lock);
break; break;
}
remove_extent_mapping(em_tree, em); remove_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
/* once for us */ /* once for us */
free_extent_map(em); free_extent_map(em);
/* once for the tree*/ /* once for the tree*/
......
This diff is collapsed.
...@@ -468,10 +468,15 @@ static int __init init_btrfs_fs(void) ...@@ -468,10 +468,15 @@ static int __init init_btrfs_fs(void)
err = btrfs_init_cachep(); err = btrfs_init_cachep();
if (err) if (err)
goto free_transaction_sys; goto free_transaction_sys;
err = extent_map_init();
err = extent_io_init();
if (err) if (err)
goto free_cachep; goto free_cachep;
err = extent_map_init();
if (err)
goto free_extent_io;
err = register_filesystem(&btrfs_fs_type); err = register_filesystem(&btrfs_fs_type);
if (err) if (err)
goto free_extent_map; goto free_extent_map;
...@@ -479,6 +484,8 @@ static int __init init_btrfs_fs(void) ...@@ -479,6 +484,8 @@ static int __init init_btrfs_fs(void)
free_extent_map: free_extent_map:
extent_map_exit(); extent_map_exit();
free_extent_io:
extent_io_exit();
free_cachep: free_cachep:
btrfs_destroy_cachep(); btrfs_destroy_cachep();
free_transaction_sys: free_transaction_sys:
...@@ -492,6 +499,7 @@ static void __exit exit_btrfs_fs(void) ...@@ -492,6 +499,7 @@ static void __exit exit_btrfs_fs(void)
btrfs_exit_transaction_sys(); btrfs_exit_transaction_sys();
btrfs_destroy_cachep(); btrfs_destroy_cachep();
extent_map_exit(); extent_map_exit();
extent_io_exit();
unregister_filesystem(&btrfs_fs_type); unregister_filesystem(&btrfs_fs_type);
btrfs_exit_sysfs(); btrfs_exit_sysfs();
} }
......
...@@ -70,7 +70,7 @@ static int join_transaction(struct btrfs_root *root) ...@@ -70,7 +70,7 @@ static int join_transaction(struct btrfs_root *root)
INIT_LIST_HEAD(&cur_trans->pending_snapshots); INIT_LIST_HEAD(&cur_trans->pending_snapshots);
list_add_tail(&cur_trans->list, &root->fs_info->trans_list); list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree); 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, root->fs_info->btree_inode->i_mapping,
GFP_NOFS); GFP_NOFS);
} else { } else {
...@@ -153,7 +153,7 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, ...@@ -153,7 +153,7 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
int ret; int ret;
int err; int err;
int werr = 0; int werr = 0;
struct extent_map_tree *dirty_pages; struct extent_io_tree *dirty_pages;
struct page *page; struct page *page;
struct inode *btree_inode = root->fs_info->btree_inode; struct inode *btree_inode = root->fs_info->btree_inode;
u64 start; u64 start;
...@@ -610,7 +610,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -610,7 +610,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
struct btrfs_transaction *cur_trans; struct btrfs_transaction *cur_trans;
struct btrfs_transaction *prev_trans = NULL; struct btrfs_transaction *prev_trans = NULL;
struct list_head dirty_fs_roots; struct list_head dirty_fs_roots;
struct extent_map_tree *pinned_copy; struct extent_io_tree *pinned_copy;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
int ret; int ret;
...@@ -639,7 +639,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -639,7 +639,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
if (!pinned_copy) if (!pinned_copy)
return -ENOMEM; return -ENOMEM;
extent_map_tree_init(pinned_copy, extent_io_tree_init(pinned_copy,
root->fs_info->btree_inode->i_mapping, GFP_NOFS); root->fs_info->btree_inode->i_mapping, GFP_NOFS);
trans->transaction->in_commit = 1; trans->transaction->in_commit = 1;
......
...@@ -29,7 +29,7 @@ struct btrfs_transaction { ...@@ -29,7 +29,7 @@ struct btrfs_transaction {
int use_count; int use_count;
int commit_done; int commit_done;
struct list_head list; struct list_head list;
struct extent_map_tree dirty_pages; struct extent_io_tree dirty_pages;
unsigned long start_time; unsigned long start_time;
struct btrfs_ordered_inode_tree ordered_inode_tree; struct btrfs_ordered_inode_tree ordered_inode_tree;
wait_queue_head_t writer_wait; wait_queue_head_t writer_wait;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment