aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2009-11-12 04:33:26 -0500
committerChris Mason <chris.mason@oracle.com>2009-12-15 21:24:25 -0500
commit8cef4e160d74920ad1725f58c89fd75ec4c4ac38 (patch)
treec1592369c7085e75d67a1709438a4f56351b2348
parent22763c5cf3690a681551162c15d34d935308c8d7 (diff)
Btrfs: Avoid superfluous tree-log writeout
We allow two log transactions at a time, but use same flag to mark dirty tree-log btree blocks. So we may flush dirty blocks belonging to newer log transaction when committing a log transaction. This patch fixes the issue by using two flags to mark dirty tree-log btree blocks. Signed-off-by: Yan Zheng <zheng.yan@oracle.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/disk-io.c6
-rw-r--r--fs/btrfs/extent-tree.c12
-rw-r--r--fs/btrfs/transaction.c21
-rw-r--r--fs/btrfs/transaction.h6
-rw-r--r--fs/btrfs/tree-log.c33
5 files changed, 47 insertions, 31 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 02b6afbd7450..101940fab9b3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -980,12 +980,12 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
980 980
981 while (1) { 981 while (1) {
982 ret = find_first_extent_bit(&log_root_tree->dirty_log_pages, 982 ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
983 0, &start, &end, EXTENT_DIRTY); 983 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
984 if (ret) 984 if (ret)
985 break; 985 break;
986 986
987 clear_extent_dirty(&log_root_tree->dirty_log_pages, 987 clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
988 start, end, GFP_NOFS); 988 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
989 } 989 }
990 eb = fs_info->log_root_tree->node; 990 eb = fs_info->log_root_tree->node;
991 991
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 94627c4cc193..4a86508ce473 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4919,8 +4919,16 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
4919 btrfs_set_buffer_uptodate(buf); 4919 btrfs_set_buffer_uptodate(buf);
4920 4920
4921 if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { 4921 if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
4922 set_extent_dirty(&root->dirty_log_pages, buf->start, 4922 /*
4923 buf->start + buf->len - 1, GFP_NOFS); 4923 * we allow two log transactions at a time, use different
4924 * EXENT bit to differentiate dirty pages.
4925 */
4926 if (root->log_transid % 2 == 0)
4927 set_extent_dirty(&root->dirty_log_pages, buf->start,
4928 buf->start + buf->len - 1, GFP_NOFS);
4929 else
4930 set_extent_new(&root->dirty_log_pages, buf->start,
4931 buf->start + buf->len - 1, GFP_NOFS);
4924 } else { 4932 } else {
4925 set_extent_dirty(&trans->transaction->dirty_pages, buf->start, 4933 set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
4926 buf->start + buf->len - 1, GFP_NOFS); 4934 buf->start + buf->len - 1, GFP_NOFS);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index c207e8c32c9b..b7b22c344b66 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -354,7 +354,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
354 * those extents are sent to disk but does not wait on them 354 * those extents are sent to disk but does not wait on them
355 */ 355 */
356int btrfs_write_marked_extents(struct btrfs_root *root, 356int btrfs_write_marked_extents(struct btrfs_root *root,
357 struct extent_io_tree *dirty_pages) 357 struct extent_io_tree *dirty_pages, int mark)
358{ 358{
359 int ret; 359 int ret;
360 int err = 0; 360 int err = 0;
@@ -367,7 +367,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
367 367
368 while (1) { 368 while (1) {
369 ret = find_first_extent_bit(dirty_pages, start, &start, &end, 369 ret = find_first_extent_bit(dirty_pages, start, &start, &end,
370 EXTENT_DIRTY); 370 mark);
371 if (ret) 371 if (ret)
372 break; 372 break;
373 while (start <= end) { 373 while (start <= end) {
@@ -413,7 +413,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
413 * on all the pages and clear them from the dirty pages state tree 413 * on all the pages and clear them from the dirty pages state tree
414 */ 414 */
415int btrfs_wait_marked_extents(struct btrfs_root *root, 415int btrfs_wait_marked_extents(struct btrfs_root *root,
416 struct extent_io_tree *dirty_pages) 416 struct extent_io_tree *dirty_pages, int mark)
417{ 417{
418 int ret; 418 int ret;
419 int err = 0; 419 int err = 0;
@@ -425,12 +425,12 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
425 unsigned long index; 425 unsigned long index;
426 426
427 while (1) { 427 while (1) {
428 ret = find_first_extent_bit(dirty_pages, 0, &start, &end, 428 ret = find_first_extent_bit(dirty_pages, start, &start, &end,
429 EXTENT_DIRTY); 429 mark);
430 if (ret) 430 if (ret)
431 break; 431 break;
432 432
433 clear_extent_dirty(dirty_pages, start, end, GFP_NOFS); 433 clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
434 while (start <= end) { 434 while (start <= end) {
435 index = start >> PAGE_CACHE_SHIFT; 435 index = start >> PAGE_CACHE_SHIFT;
436 start = (u64)(index + 1) << PAGE_CACHE_SHIFT; 436 start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
@@ -460,13 +460,13 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
460 * those extents are on disk for transaction or log commit 460 * those extents are on disk for transaction or log commit
461 */ 461 */
462int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, 462int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
463 struct extent_io_tree *dirty_pages) 463 struct extent_io_tree *dirty_pages, int mark)
464{ 464{
465 int ret; 465 int ret;
466 int ret2; 466 int ret2;
467 467
468 ret = btrfs_write_marked_extents(root, dirty_pages); 468 ret = btrfs_write_marked_extents(root, dirty_pages, mark);
469 ret2 = btrfs_wait_marked_extents(root, dirty_pages); 469 ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark);
470 return ret || ret2; 470 return ret || ret2;
471} 471}
472 472
@@ -479,7 +479,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
479 return filemap_write_and_wait(btree_inode->i_mapping); 479 return filemap_write_and_wait(btree_inode->i_mapping);
480 } 480 }
481 return btrfs_write_and_wait_marked_extents(root, 481 return btrfs_write_and_wait_marked_extents(root,
482 &trans->transaction->dirty_pages); 482 &trans->transaction->dirty_pages,
483 EXTENT_DIRTY);
483} 484}
484 485
485/* 486/*
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index d4e3e7a6938c..93c7ccb33118 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -107,10 +107,10 @@ void btrfs_throttle(struct btrfs_root *root);
107int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, 107int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
108 struct btrfs_root *root); 108 struct btrfs_root *root);
109int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, 109int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
110 struct extent_io_tree *dirty_pages); 110 struct extent_io_tree *dirty_pages, int mark);
111int btrfs_write_marked_extents(struct btrfs_root *root, 111int btrfs_write_marked_extents(struct btrfs_root *root,
112 struct extent_io_tree *dirty_pages); 112 struct extent_io_tree *dirty_pages, int mark);
113int btrfs_wait_marked_extents(struct btrfs_root *root, 113int btrfs_wait_marked_extents(struct btrfs_root *root,
114 struct extent_io_tree *dirty_pages); 114 struct extent_io_tree *dirty_pages, int mark);
115int btrfs_transaction_in_commit(struct btrfs_fs_info *info); 115int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
116#endif 116#endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 741666a7676a..31da0002e78b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1977,10 +1977,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
1977{ 1977{
1978 int index1; 1978 int index1;
1979 int index2; 1979 int index2;
1980 int mark;
1980 int ret; 1981 int ret;
1981 struct btrfs_root *log = root->log_root; 1982 struct btrfs_root *log = root->log_root;
1982 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; 1983 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
1983 u64 log_transid = 0; 1984 unsigned long log_transid = 0;
1984 1985
1985 mutex_lock(&root->log_mutex); 1986 mutex_lock(&root->log_mutex);
1986 index1 = root->log_transid % 2; 1987 index1 = root->log_transid % 2;
@@ -2014,24 +2015,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2014 goto out; 2015 goto out;
2015 } 2016 }
2016 2017
2018 log_transid = root->log_transid;
2019 if (log_transid % 2 == 0)
2020 mark = EXTENT_DIRTY;
2021 else
2022 mark = EXTENT_NEW;
2023
2017 /* we start IO on all the marked extents here, but we don't actually 2024 /* we start IO on all the marked extents here, but we don't actually
2018 * wait for them until later. 2025 * wait for them until later.
2019 */ 2026 */
2020 ret = btrfs_write_marked_extents(log, &log->dirty_log_pages); 2027 ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
2021 BUG_ON(ret); 2028 BUG_ON(ret);
2022 2029
2023 btrfs_set_root_node(&log->root_item, log->node); 2030 btrfs_set_root_node(&log->root_item, log->node);
2024 2031
2025 root->log_batch = 0; 2032 root->log_batch = 0;
2026 log_transid = root->log_transid;
2027 root->log_transid++; 2033 root->log_transid++;
2028 log->log_transid = root->log_transid; 2034 log->log_transid = root->log_transid;
2029 root->log_start_pid = 0; 2035 root->log_start_pid = 0;
2030 smp_mb(); 2036 smp_mb();
2031 /* 2037 /*
2032 * log tree has been flushed to disk, new modifications of 2038 * IO has been started, blocks of the log tree have WRITTEN flag set
2033 * the log will be written to new positions. so it's safe to 2039 * in their headers. new modifications of the log will be written to
2034 * allow log writers to go in. 2040 * new positions. so it's safe to allow log writers to go in.
2035 */ 2041 */
2036 mutex_unlock(&root->log_mutex); 2042 mutex_unlock(&root->log_mutex);
2037 2043
@@ -2052,7 +2058,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2052 2058
2053 index2 = log_root_tree->log_transid % 2; 2059 index2 = log_root_tree->log_transid % 2;
2054 if (atomic_read(&log_root_tree->log_commit[index2])) { 2060 if (atomic_read(&log_root_tree->log_commit[index2])) {
2055 btrfs_wait_marked_extents(log, &log->dirty_log_pages); 2061 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2056 wait_log_commit(trans, log_root_tree, 2062 wait_log_commit(trans, log_root_tree,
2057 log_root_tree->log_transid); 2063 log_root_tree->log_transid);
2058 mutex_unlock(&log_root_tree->log_mutex); 2064 mutex_unlock(&log_root_tree->log_mutex);
@@ -2072,16 +2078,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2072 * check the full commit flag again 2078 * check the full commit flag again
2073 */ 2079 */
2074 if (root->fs_info->last_trans_log_full_commit == trans->transid) { 2080 if (root->fs_info->last_trans_log_full_commit == trans->transid) {
2075 btrfs_wait_marked_extents(log, &log->dirty_log_pages); 2081 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2076 mutex_unlock(&log_root_tree->log_mutex); 2082 mutex_unlock(&log_root_tree->log_mutex);
2077 ret = -EAGAIN; 2083 ret = -EAGAIN;
2078 goto out_wake_log_root; 2084 goto out_wake_log_root;
2079 } 2085 }
2080 2086
2081 ret = btrfs_write_and_wait_marked_extents(log_root_tree, 2087 ret = btrfs_write_and_wait_marked_extents(log_root_tree,
2082 &log_root_tree->dirty_log_pages); 2088 &log_root_tree->dirty_log_pages,
2089 EXTENT_DIRTY | EXTENT_NEW);
2083 BUG_ON(ret); 2090 BUG_ON(ret);
2084 btrfs_wait_marked_extents(log, &log->dirty_log_pages); 2091 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2085 2092
2086 btrfs_set_super_log_root(&root->fs_info->super_for_commit, 2093 btrfs_set_super_log_root(&root->fs_info->super_for_commit,
2087 log_root_tree->node->start); 2094 log_root_tree->node->start);
@@ -2147,12 +2154,12 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
2147 2154
2148 while (1) { 2155 while (1) {
2149 ret = find_first_extent_bit(&log->dirty_log_pages, 2156 ret = find_first_extent_bit(&log->dirty_log_pages,
2150 0, &start, &end, EXTENT_DIRTY); 2157 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
2151 if (ret) 2158 if (ret)
2152 break; 2159 break;
2153 2160
2154 clear_extent_dirty(&log->dirty_log_pages, 2161 clear_extent_bits(&log->dirty_log_pages, start, end,
2155 start, end, GFP_NOFS); 2162 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
2156 } 2163 }
2157 2164
2158 if (log->log_transid > 0) { 2165 if (log->log_transid > 0) {