aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-09-11 16:17:57 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:07 -0400
commitd0c803c4049c5ca322d4795d8b74f28768603e0e (patch)
treeb4c4f11b2f5938ad183a1771cd0b9e122709e2ff
parent31ff1cd25d376e8f499d450de177dffadc9e1c56 (diff)
Btrfs: Record dirty pages tree-log pages in an extent_io tree
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>
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/disk-io.c17
-rw-r--r--fs/btrfs/extent-tree.c7
-rw-r--r--fs/btrfs/transaction.c21
-rw-r--r--fs/btrfs/transaction.h2
-rw-r--r--fs/btrfs/tree-log.c29
6 files changed, 54 insertions, 24 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 2ed6918f32e5..eb65fd808883 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -668,6 +668,8 @@ struct btrfs_root {
668 struct btrfs_key root_key; 668 struct btrfs_key root_key;
669 struct btrfs_fs_info *fs_info; 669 struct btrfs_fs_info *fs_info;
670 struct inode *inode; 670 struct inode *inode;
671 struct extent_io_tree dirty_log_pages;
672
671 struct kobject root_kobj; 673 struct kobject root_kobj;
672 struct completion kobj_unregister; 674 struct completion kobj_unregister;
673 struct mutex objectid_mutex; 675 struct mutex objectid_mutex;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 5edb7f885799..57fbf107e59f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -777,6 +777,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
777 spin_lock_init(&root->list_lock); 777 spin_lock_init(&root->list_lock);
778 mutex_init(&root->objectid_mutex); 778 mutex_init(&root->objectid_mutex);
779 mutex_init(&root->log_mutex); 779 mutex_init(&root->log_mutex);
780 extent_io_tree_init(&root->dirty_log_pages,
781 fs_info->btree_inode->i_mapping, GFP_NOFS);
780 782
781 btrfs_leaf_ref_tree_init(&root->ref_tree_struct); 783 btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
782 root->ref_tree = &root->ref_tree_struct; 784 root->ref_tree = &root->ref_tree_struct;
@@ -819,11 +821,23 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
819 struct btrfs_fs_info *fs_info) 821 struct btrfs_fs_info *fs_info)
820{ 822{
821 struct extent_buffer *eb; 823 struct extent_buffer *eb;
824 struct btrfs_root *log_root_tree = fs_info->log_root_tree;
825 u64 start = 0;
826 u64 end = 0;
822 int ret; 827 int ret;
823 828
824 if (!fs_info->log_root_tree) 829 if (!log_root_tree)
825 return 0; 830 return 0;
826 831
832 while(1) {
833 ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
834 0, &start, &end, EXTENT_DIRTY);
835 if (ret)
836 break;
837
838 clear_extent_dirty(&log_root_tree->dirty_log_pages,
839 start, end, GFP_NOFS);
840 }
827 eb = fs_info->log_root_tree->node; 841 eb = fs_info->log_root_tree->node;
828 842
829 WARN_ON(btrfs_header_level(eb) != 0); 843 WARN_ON(btrfs_header_level(eb) != 0);
@@ -1412,7 +1426,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1412 memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 1426 memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
1413 sizeof(struct btrfs_key)); 1427 sizeof(struct btrfs_key));
1414 insert_inode_hash(fs_info->btree_inode); 1428 insert_inode_hash(fs_info->btree_inode);
1415 mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
1416 1429
1417 mutex_init(&fs_info->trans_mutex); 1430 mutex_init(&fs_info->trans_mutex);
1418 mutex_init(&fs_info->tree_log_mutex); 1431 mutex_init(&fs_info->tree_log_mutex);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c479d71e2869..c0bb6b9ac4c6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2392,8 +2392,13 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
2392 btrfs_tree_lock(buf); 2392 btrfs_tree_lock(buf);
2393 clean_tree_block(trans, root, buf); 2393 clean_tree_block(trans, root, buf);
2394 btrfs_set_buffer_uptodate(buf); 2394 btrfs_set_buffer_uptodate(buf);
2395 set_extent_dirty(&trans->transaction->dirty_pages, buf->start, 2395 if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
2396 set_extent_dirty(&root->dirty_log_pages, buf->start,
2397 buf->start + buf->len - 1, GFP_NOFS);
2398 } else {
2399 set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
2396 buf->start + buf->len - 1, GFP_NOFS); 2400 buf->start + buf->len - 1, GFP_NOFS);
2401 }
2397 trans->blocks_used++; 2402 trans->blocks_used++;
2398 return buf; 2403 return buf;
2399} 2404}
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 61a377bcb2fb..151b00d52593 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -302,23 +302,18 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
302} 302}
303 303
304 304
305int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, 305int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
306 struct btrfs_root *root) 306 struct extent_io_tree *dirty_pages)
307{ 307{
308 int ret; 308 int ret;
309 int err = 0; 309 int err = 0;
310 int werr = 0; 310 int werr = 0;
311 struct extent_io_tree *dirty_pages;
312 struct page *page; 311 struct page *page;
313 struct inode *btree_inode = root->fs_info->btree_inode; 312 struct inode *btree_inode = root->fs_info->btree_inode;
314 u64 start = 0; 313 u64 start = 0;
315 u64 end; 314 u64 end;
316 unsigned long index; 315 unsigned long index;
317 316
318 if (!trans || !trans->transaction) {
319 return filemap_write_and_wait(btree_inode->i_mapping);
320 }
321 dirty_pages = &trans->transaction->dirty_pages;
322 while(1) { 317 while(1) {
323 ret = find_first_extent_bit(dirty_pages, start, &start, &end, 318 ret = find_first_extent_bit(dirty_pages, start, &start, &end,
324 EXTENT_DIRTY); 319 EXTENT_DIRTY);
@@ -385,6 +380,18 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
385 return werr; 380 return werr;
386} 381}
387 382
383int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
384 struct btrfs_root *root)
385{
386 if (!trans || !trans->transaction) {
387 struct inode *btree_inode;
388 btree_inode = root->fs_info->btree_inode;
389 return filemap_write_and_wait(btree_inode->i_mapping);
390 }
391 return btrfs_write_and_wait_marked_extents(root,
392 &trans->transaction->dirty_pages);
393}
394
388static int update_cowonly_root(struct btrfs_trans_handle *trans, 395static int update_cowonly_root(struct btrfs_trans_handle *trans,
389 struct btrfs_root *root) 396 struct btrfs_root *root)
390{ 397{
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index cc63650d60d6..eef2cb7d7e78 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -99,4 +99,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
99 struct btrfs_root *root); 99 struct btrfs_root *root);
100void btrfs_throttle(struct btrfs_root *root); 100void btrfs_throttle(struct btrfs_root *root);
101int btrfs_record_root_in_trans(struct btrfs_root *root); 101int btrfs_record_root_in_trans(struct btrfs_root *root);
102int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
103 struct extent_io_tree *dirty_pages);
102#endif 104#endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index ae96451bc223..bfa710800963 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1954,10 +1954,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
1954 int ret; 1954 int ret;
1955 unsigned long batch; 1955 unsigned long batch;
1956 struct btrfs_root *log = root->log_root; 1956 struct btrfs_root *log = root->log_root;
1957 struct walk_control wc = {
1958 .write = 1,
1959 .process_func = process_one_buffer
1960 };
1961 1957
1962 mutex_lock(&log->fs_info->tree_log_mutex); 1958 mutex_lock(&log->fs_info->tree_log_mutex);
1963 if (atomic_read(&log->fs_info->tree_log_commit)) { 1959 if (atomic_read(&log->fs_info->tree_log_commit)) {
@@ -1985,18 +1981,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
1985 if (batch == log->fs_info->tree_log_batch) 1981 if (batch == log->fs_info->tree_log_batch)
1986 break; 1982 break;
1987 } 1983 }
1988 ret = walk_log_tree(trans, log, &wc);
1989 BUG_ON(ret);
1990
1991 ret = walk_log_tree(trans, log->fs_info->log_root_tree, &wc);
1992 BUG_ON(ret);
1993
1994 wc.wait = 1;
1995 1984
1996 ret = walk_log_tree(trans, log, &wc); 1985 ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
1997 BUG_ON(ret); 1986 BUG_ON(ret);
1998 1987 ret = btrfs_write_and_wait_marked_extents(root->fs_info->log_root_tree,
1999 ret = walk_log_tree(trans, log->fs_info->log_root_tree, &wc); 1988 &root->fs_info->log_root_tree->dirty_log_pages);
2000 BUG_ON(ret); 1989 BUG_ON(ret);
2001 1990
2002 btrfs_set_super_log_root(&root->fs_info->super_for_commit, 1991 btrfs_set_super_log_root(&root->fs_info->super_for_commit,
@@ -2025,6 +2014,8 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
2025 int ret; 2014 int ret;
2026 struct btrfs_root *log; 2015 struct btrfs_root *log;
2027 struct key; 2016 struct key;
2017 u64 start;
2018 u64 end;
2028 struct walk_control wc = { 2019 struct walk_control wc = {
2029 .free = 1, 2020 .free = 1,
2030 .process_func = process_one_buffer 2021 .process_func = process_one_buffer
@@ -2037,6 +2028,16 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
2037 ret = walk_log_tree(trans, log, &wc); 2028 ret = walk_log_tree(trans, log, &wc);
2038 BUG_ON(ret); 2029 BUG_ON(ret);
2039 2030
2031 while(1) {
2032 ret = find_first_extent_bit(&log->dirty_log_pages,
2033 0, &start, &end, EXTENT_DIRTY);
2034 if (ret)
2035 break;
2036
2037 clear_extent_dirty(&log->dirty_log_pages,
2038 start, end, GFP_NOFS);
2039 }
2040
2040 log = root->log_root; 2041 log = root->log_root;
2041 ret = btrfs_del_root(trans, root->fs_info->log_root_tree, 2042 ret = btrfs_del_root(trans, root->fs_info->log_root_tree,
2042 &log->root_key); 2043 &log->root_key);