Skip to content

Commit

Permalink
Btrfs: Record dirty pages tree-log pages in an extent_io tree
Browse files Browse the repository at this point in the history
This is the same way the transaction code makes sure that all the
other tree blocks are safely on disk.  There's an extent_io tree
for each root, and any blocks allocated to the tree logs are
recorded in that tree.

At tree-log sync, the extent_io tree is walked to flush down the
dirty pages and wait for them.

The main benefit is less time spent walking the tree log and skipping
clean pages, and getting sequential IO down to the drive.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 25, 2008
1 parent 31ff1cd commit d0c803c
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 24 deletions.
2 changes: 2 additions & 0 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,8 @@ struct btrfs_root {
struct btrfs_key root_key;
struct btrfs_fs_info *fs_info;
struct inode *inode;
struct extent_io_tree dirty_log_pages;

struct kobject root_kobj;
struct completion kobj_unregister;
struct mutex objectid_mutex;
Expand Down
17 changes: 15 additions & 2 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
spin_lock_init(&root->list_lock);
mutex_init(&root->objectid_mutex);
mutex_init(&root->log_mutex);
extent_io_tree_init(&root->dirty_log_pages,
fs_info->btree_inode->i_mapping, GFP_NOFS);

btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
root->ref_tree = &root->ref_tree_struct;
Expand Down Expand Up @@ -819,11 +821,23 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{
struct extent_buffer *eb;
struct btrfs_root *log_root_tree = fs_info->log_root_tree;
u64 start = 0;
u64 end = 0;
int ret;

if (!fs_info->log_root_tree)
if (!log_root_tree)
return 0;

while(1) {
ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY);
if (ret)
break;

clear_extent_dirty(&log_root_tree->dirty_log_pages,
start, end, GFP_NOFS);
}
eb = fs_info->log_root_tree->node;

WARN_ON(btrfs_header_level(eb) != 0);
Expand Down Expand Up @@ -1412,7 +1426,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
sizeof(struct btrfs_key));
insert_inode_hash(fs_info->btree_inode);
mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);

mutex_init(&fs_info->trans_mutex);
mutex_init(&fs_info->tree_log_mutex);
Expand Down
7 changes: 6 additions & 1 deletion fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2392,8 +2392,13 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
btrfs_tree_lock(buf);
clean_tree_block(trans, root, buf);
btrfs_set_buffer_uptodate(buf);
set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
set_extent_dirty(&root->dirty_log_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS);
} else {
set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS);
}
trans->blocks_used++;
return buf;
}
Expand Down
21 changes: 14 additions & 7 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,23 +302,18 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
}


int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages)
{
int ret;
int err = 0;
int werr = 0;
struct extent_io_tree *dirty_pages;
struct page *page;
struct inode *btree_inode = root->fs_info->btree_inode;
u64 start = 0;
u64 end;
unsigned long index;

if (!trans || !trans->transaction) {
return filemap_write_and_wait(btree_inode->i_mapping);
}
dirty_pages = &trans->transaction->dirty_pages;
while(1) {
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
EXTENT_DIRTY);
Expand Down Expand Up @@ -385,6 +380,18 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
return werr;
}

int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
if (!trans || !trans->transaction) {
struct inode *btree_inode;
btree_inode = root->fs_info->btree_inode;
return filemap_write_and_wait(btree_inode->i_mapping);
}
return btrfs_write_and_wait_marked_extents(root,
&trans->transaction->dirty_pages);
}

static int update_cowonly_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
void btrfs_throttle(struct btrfs_root *root);
int btrfs_record_root_in_trans(struct btrfs_root *root);
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages);
#endif
29 changes: 15 additions & 14 deletions fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1954,10 +1954,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
int ret;
unsigned long batch;
struct btrfs_root *log = root->log_root;
struct walk_control wc = {
.write = 1,
.process_func = process_one_buffer
};

mutex_lock(&log->fs_info->tree_log_mutex);
if (atomic_read(&log->fs_info->tree_log_commit)) {
Expand Down Expand Up @@ -1985,18 +1981,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
if (batch == log->fs_info->tree_log_batch)
break;
}
ret = walk_log_tree(trans, log, &wc);
BUG_ON(ret);

ret = walk_log_tree(trans, log->fs_info->log_root_tree, &wc);
BUG_ON(ret);

wc.wait = 1;

ret = walk_log_tree(trans, log, &wc);
ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
BUG_ON(ret);

ret = walk_log_tree(trans, log->fs_info->log_root_tree, &wc);
ret = btrfs_write_and_wait_marked_extents(root->fs_info->log_root_tree,
&root->fs_info->log_root_tree->dirty_log_pages);
BUG_ON(ret);

btrfs_set_super_log_root(&root->fs_info->super_for_commit,
Expand Down Expand Up @@ -2025,6 +2014,8 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
int ret;
struct btrfs_root *log;
struct key;
u64 start;
u64 end;
struct walk_control wc = {
.free = 1,
.process_func = process_one_buffer
Expand All @@ -2037,6 +2028,16 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
ret = walk_log_tree(trans, log, &wc);
BUG_ON(ret);

while(1) {
ret = find_first_extent_bit(&log->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY);
if (ret)
break;

clear_extent_dirty(&log->dirty_log_pages,
start, end, GFP_NOFS);
}

log = root->log_root;
ret = btrfs_del_root(trans, root->fs_info->log_root_tree,
&log->root_key);
Expand Down

0 comments on commit d0c803c

Please sign in to comment.