Skip to content

Commit

Permalink
Btrfs: cache the extent state everywhere we possibly can V2
Browse files Browse the repository at this point in the history
This patch just goes through and fixes everybody that does

lock_extent()
blah
unlock_extent()

to use

lock_extent_bits()
blah
unlock_extent_cached()

and pass around a extent_state so we only have to do the searches once per
function.  This gives me about a 3 mb/s boots on my random write test.  I have
not converted some things, like the relocation and ioctl's, since they aren't
heavily used and the relocation stuff is in the middle of being re-written.  I
also changed the clear_extent_bit() to only unset the cached state if we are
clearing EXTENT_LOCKED and related stuff, so we can do things like this

lock_extent_bits()
clear delalloc bits
unlock_extent_cached()

without losing our cached state.  I tested this thoroughly and turned on
LEAK_DEBUG to make sure we weren't leaking extent states, everything worked out
fine.

Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Josef Bacik authored and Chris Mason committed Mar 15, 2010
1 parent 5a1a3df commit 2ac55d4
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 90 deletions.
3 changes: 2 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2311,7 +2311,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
u32 min_type);

int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
struct extent_state **cached_state);
int btrfs_writepages(struct address_space *mapping,
struct writeback_control *wbc);
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
Expand Down
15 changes: 9 additions & 6 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,15 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
static int verify_parent_transid(struct extent_io_tree *io_tree,
struct extent_buffer *eb, u64 parent_transid)
{
struct extent_state *cached_state = NULL;
int ret;

if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
return 0;

lock_extent(io_tree, eb->start, eb->start + eb->len - 1, GFP_NOFS);
if (extent_buffer_uptodate(io_tree, eb) &&
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
0, &cached_state, GFP_NOFS);
if (extent_buffer_uptodate(io_tree, eb, cached_state) &&
btrfs_header_generation(eb) == parent_transid) {
ret = 0;
goto out;
Expand All @@ -282,10 +284,10 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
(unsigned long long)btrfs_header_generation(eb));
}
ret = 1;
clear_extent_buffer_uptodate(io_tree, eb);
clear_extent_buffer_uptodate(io_tree, eb, &cached_state);
out:
unlock_extent(io_tree, eb->start, eb->start + eb->len - 1,
GFP_NOFS);
unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
&cached_state, GFP_NOFS);
return ret;
}

Expand Down Expand Up @@ -2497,7 +2499,8 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
int ret;
struct inode *btree_inode = buf->first_page->mapping->host;

ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf);
ret = extent_buffer_uptodate(&BTRFS_I(btree_inode)->io_tree, buf,
NULL);
if (!ret)
return ret;

Expand Down
11 changes: 7 additions & 4 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -6561,6 +6561,7 @@ static noinline int invalidate_extent_cache(struct btrfs_root *root,
struct btrfs_key key;
struct inode *inode = NULL;
struct btrfs_file_extent_item *fi;
struct extent_state *cached_state = NULL;
u64 num_bytes;
u64 skip_objectid = 0;
u32 nritems;
Expand Down Expand Up @@ -6589,12 +6590,14 @@ static noinline int invalidate_extent_cache(struct btrfs_root *root,
}
num_bytes = btrfs_file_extent_num_bytes(leaf, fi);

lock_extent(&BTRFS_I(inode)->io_tree, key.offset,
key.offset + num_bytes - 1, GFP_NOFS);
lock_extent_bits(&BTRFS_I(inode)->io_tree, key.offset,
key.offset + num_bytes - 1, 0, &cached_state,
GFP_NOFS);
btrfs_drop_extent_cache(inode, key.offset,
key.offset + num_bytes - 1, 1);
unlock_extent(&BTRFS_I(inode)->io_tree, key.offset,
key.offset + num_bytes - 1, GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, key.offset,
key.offset + num_bytes - 1, &cached_state,
GFP_NOFS);
cond_resched();
}
iput(inode);
Expand Down
61 changes: 38 additions & 23 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
u64 last_end;
int err;
int set = 0;
int clear = 0;

if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY))
clear = 1;
again:
if (!prealloc && (mask & __GFP_WAIT)) {
prealloc = alloc_extent_state(mask);
Expand All @@ -524,14 +527,20 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
spin_lock(&tree->lock);
if (cached_state) {
cached = *cached_state;
*cached_state = NULL;
cached_state = NULL;

if (clear) {
*cached_state = NULL;
cached_state = NULL;
}

if (cached && cached->tree && cached->start == start) {
atomic_dec(&cached->refs);
if (clear)
atomic_dec(&cached->refs);
state = cached;
goto hit_next;
}
free_extent_state(cached);
if (clear)
free_extent_state(cached);
}
/*
* this search will find the extents that end after
Expand Down Expand Up @@ -946,11 +955,11 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
}

int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask)
struct extent_state **cached_state, gfp_t mask)
{
return set_extent_bit(tree, start, end,
EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE,
0, NULL, NULL, mask);
0, NULL, cached_state, mask);
}

int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
Expand Down Expand Up @@ -984,10 +993,11 @@ int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
}

static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
u64 end, gfp_t mask)
u64 end, struct extent_state **cached_state,
gfp_t mask)
{
return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
NULL, mask);
cached_state, mask);
}

int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
Expand Down Expand Up @@ -1727,7 +1737,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
}

if (!uptodate) {
clear_extent_uptodate(tree, start, end, GFP_NOFS);
clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
ClearPageUptodate(page);
SetPageError(page);
}
Expand Down Expand Up @@ -2710,6 +2720,7 @@ int extent_readpages(struct extent_io_tree *tree,
int extent_invalidatepage(struct extent_io_tree *tree,
struct page *page, unsigned long offset)
{
struct extent_state *cached_state = NULL;
u64 start = ((u64)page->index << PAGE_CACHE_SHIFT);
u64 end = start + PAGE_CACHE_SIZE - 1;
size_t blocksize = page->mapping->host->i_sb->s_blocksize;
Expand All @@ -2718,12 +2729,12 @@ int extent_invalidatepage(struct extent_io_tree *tree,
if (start > end)
return 0;

lock_extent(tree, start, end, GFP_NOFS);
lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS);
wait_on_page_writeback(page);
clear_extent_bit(tree, start, end,
EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING,
1, 1, NULL, GFP_NOFS);
1, 1, &cached_state, GFP_NOFS);
return 0;
}

Expand Down Expand Up @@ -2926,16 +2937,17 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
get_extent_t *get_extent)
{
struct inode *inode = mapping->host;
struct extent_state *cached_state = NULL;
u64 start = iblock << inode->i_blkbits;
sector_t sector = 0;
size_t blksize = (1 << inode->i_blkbits);
struct extent_map *em;

lock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
GFP_NOFS);
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
0, &cached_state, GFP_NOFS);
em = get_extent(inode, NULL, 0, start, blksize, 0);
unlock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1,
GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start,
start + blksize - 1, &cached_state, GFP_NOFS);
if (!em || IS_ERR(em))
return 0;

Expand All @@ -2957,6 +2969,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u32 flags = 0;
u64 disko = 0;
struct extent_map *em = NULL;
struct extent_state *cached_state = NULL;
int end = 0;
u64 em_start = 0, em_len = 0;
unsigned long emflags;
Expand All @@ -2965,8 +2978,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
if (len == 0)
return -EINVAL;

lock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
GFP_NOFS);
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
&cached_state, GFP_NOFS);
em = get_extent(inode, NULL, 0, off, max - off, 0);
if (!em)
goto out;
Expand Down Expand Up @@ -3029,8 +3042,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
out_free:
free_extent_map(em);
out:
unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len,
&cached_state, GFP_NOFS);
return ret;
}

Expand Down Expand Up @@ -3270,7 +3283,8 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
}

int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
struct extent_buffer *eb)
struct extent_buffer *eb,
struct extent_state **cached_state)
{
unsigned long i;
struct page *page;
Expand All @@ -3280,7 +3294,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);

clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
GFP_NOFS);
cached_state, GFP_NOFS);
for (i = 0; i < num_pages; i++) {
page = extent_buffer_page(eb, i);
if (page)
Expand Down Expand Up @@ -3340,7 +3354,8 @@ int extent_range_uptodate(struct extent_io_tree *tree,
}

int extent_buffer_uptodate(struct extent_io_tree *tree,
struct extent_buffer *eb)
struct extent_buffer *eb,
struct extent_state *cached_state)
{
int ret = 0;
unsigned long num_pages;
Expand All @@ -3352,7 +3367,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
return 1;

ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
EXTENT_UPTODATE, 1, NULL);
EXTENT_UPTODATE, 1, cached_state);
if (ret)
return ret;

Expand Down
10 changes: 7 additions & 3 deletions fs/btrfs/extent_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
int bits, struct extent_state **cached, gfp_t mask);
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state **cached, gfp_t mask);
int try_lock_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,
Expand Down Expand Up @@ -196,7 +198,7 @@ int clear_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
int clear_extent_ordered_metadata(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);
struct extent_state **cached_state, gfp_t mask);
int set_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask);
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
Expand Down Expand Up @@ -281,9 +283,11 @@ int test_extent_buffer_dirty(struct extent_io_tree *tree,
int set_extent_buffer_uptodate(struct extent_io_tree *tree,
struct extent_buffer *eb);
int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
struct extent_buffer *eb);
struct extent_buffer *eb,
struct extent_state **cached_state);
int extent_buffer_uptodate(struct extent_io_tree *tree,
struct extent_buffer *eb);
struct extent_buffer *eb,
struct extent_state *cached_state);
int map_extent_buffer(struct extent_buffer *eb, unsigned long offset,
unsigned long min_len, char **token, char **map,
unsigned long *map_start,
Expand Down
23 changes: 14 additions & 9 deletions fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
root->sectorsize - 1) & ~((u64)root->sectorsize - 1);

end_of_last_block = start_pos + num_bytes - 1;
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
NULL);
if (err)
return err;

Expand Down Expand Up @@ -753,6 +754,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
loff_t pos, unsigned long first_index,
unsigned long last_index, size_t write_bytes)
{
struct extent_state *cached_state = NULL;
int i;
unsigned long index = pos >> PAGE_CACHE_SHIFT;
struct inode *inode = fdentry(file)->d_inode;
Expand Down Expand Up @@ -781,16 +783,18 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
}
if (start_pos < inode->i_size) {
struct btrfs_ordered_extent *ordered;
lock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS);
lock_extent_bits(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, 0, &cached_state,
GFP_NOFS);
ordered = btrfs_lookup_first_ordered_extent(inode,
last_pos - 1);
if (ordered &&
ordered->file_offset + ordered->len > start_pos &&
ordered->file_offset < last_pos) {
btrfs_put_ordered_extent(ordered);
unlock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1,
&cached_state, GFP_NOFS);
for (i = 0; i < num_pages; i++) {
unlock_page(pages[i]);
page_cache_release(pages[i]);
Expand All @@ -802,12 +806,13 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
if (ordered)
btrfs_put_ordered_extent(ordered);

clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos,
clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos,
last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING,
EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
GFP_NOFS);
unlock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS);
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, &cached_state,
GFP_NOFS);
}
for (i = 0; i < num_pages; i++) {
clear_page_dirty_for_io(pages[i]);
Expand Down
Loading

0 comments on commit 2ac55d4

Please sign in to comment.