aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-10-13 13:21:08 -0400
committerChris Mason <chris.mason@oracle.com>2009-10-13 13:35:12 -0400
commit257c62e1bce03e5b9f3f069fd52ad73a56de71fd (patch)
treead047fe5796156aa88e3f3600111bf2b8d12759f
parent4722607db6a78bd7748c51fa4c8d7371da797254 (diff)
Btrfs: avoid tree log commit when there are no changes
rpm has a habit of running fdatasync when the file hasn't changed. We already detect if a file hasn't been changed in the current transaction but it might have been sent to the tree-log in this transaction and not changed since the last call to fsync. In this case, we want to avoid a tree log sync, which includes a number of synchronous writes and barriers. This commit extends the existing tracking of the last transaction to change a file to also track the last sub-transaction. The end result is that rpm -ivh and -Uvh are roughly twice as fast, and on par with ext3. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/btrfs_inode.h6
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/btrfs/file.c41
-rw-r--r--fs/btrfs/inode.c6
-rw-r--r--fs/btrfs/transaction.h1
-rw-r--r--fs/btrfs/tree-log.c27
-rw-r--r--fs/btrfs/tree-log.h3
8 files changed, 71 insertions, 16 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index c71abec0ab90..f6783a42f010 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -86,6 +86,12 @@ struct btrfs_inode {
86 * transid of the trans_handle that last modified this inode 86 * transid of the trans_handle that last modified this inode
87 */ 87 */
88 u64 last_trans; 88 u64 last_trans;
89
90 /*
91 * log transid when this inode was last modified
92 */
93 u64 last_sub_trans;
94
89 /* 95 /*
90 * transid that last logged this inode 96 * transid that last logged this inode
91 */ 97 */
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 36a19cd43e03..d0cede5ff25e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1009,6 +1009,7 @@ struct btrfs_root {
1009 atomic_t log_writers; 1009 atomic_t log_writers;
1010 atomic_t log_commit[2]; 1010 atomic_t log_commit[2];
1011 unsigned long log_transid; 1011 unsigned long log_transid;
1012 unsigned long last_log_commit;
1012 unsigned long log_batch; 1013 unsigned long log_batch;
1013 pid_t log_start_pid; 1014 pid_t log_start_pid;
1014 bool log_multiple_pids; 1015 bool log_multiple_pids;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index ac8927bdc33d..d4132aad9ea1 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -919,6 +919,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
919 atomic_set(&root->log_writers, 0); 919 atomic_set(&root->log_writers, 0);
920 root->log_batch = 0; 920 root->log_batch = 0;
921 root->log_transid = 0; 921 root->log_transid = 0;
922 root->last_log_commit = 0;
922 extent_io_tree_init(&root->dirty_log_pages, 923 extent_io_tree_init(&root->dirty_log_pages,
923 fs_info->btree_inode->i_mapping, GFP_NOFS); 924 fs_info->btree_inode->i_mapping, GFP_NOFS);
924 925
@@ -1089,6 +1090,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
1089 WARN_ON(root->log_root); 1090 WARN_ON(root->log_root);
1090 root->log_root = log_root; 1091 root->log_root = log_root;
1091 root->log_transid = 0; 1092 root->log_transid = 0;
1093 root->last_log_commit = 0;
1092 return 0; 1094 return 0;
1093} 1095}
1094 1096
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 53fb1c997f0e..4599113ed72e 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1087,8 +1087,10 @@ out_nolock:
1087 btrfs_end_transaction(trans, root); 1087 btrfs_end_transaction(trans, root);
1088 else 1088 else
1089 btrfs_commit_transaction(trans, root); 1089 btrfs_commit_transaction(trans, root);
1090 } else { 1090 } else if (ret != BTRFS_NO_LOG_SYNC) {
1091 btrfs_commit_transaction(trans, root); 1091 btrfs_commit_transaction(trans, root);
1092 } else {
1093 btrfs_end_transaction(trans, root);
1092 } 1094 }
1093 } 1095 }
1094 if (file->f_flags & O_DIRECT) { 1096 if (file->f_flags & O_DIRECT) {
@@ -1138,6 +1140,13 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1138 int ret = 0; 1140 int ret = 0;
1139 struct btrfs_trans_handle *trans; 1141 struct btrfs_trans_handle *trans;
1140 1142
1143
1144 /* we wait first, since the writeback may change the inode */
1145 root->log_batch++;
1146 /* the VFS called filemap_fdatawrite for us */
1147 btrfs_wait_ordered_range(inode, 0, (u64)-1);
1148 root->log_batch++;
1149
1141 /* 1150 /*
1142 * check the transaction that last modified this inode 1151 * check the transaction that last modified this inode
1143 * and see if its already been committed 1152 * and see if its already been committed
@@ -1145,6 +1154,11 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1145 if (!BTRFS_I(inode)->last_trans) 1154 if (!BTRFS_I(inode)->last_trans)
1146 goto out; 1155 goto out;
1147 1156
1157 /*
1158 * if the last transaction that changed this file was before
1159 * the current transaction, we can bail out now without any
1160 * syncing
1161 */
1148 mutex_lock(&root->fs_info->trans_mutex); 1162 mutex_lock(&root->fs_info->trans_mutex);
1149 if (BTRFS_I(inode)->last_trans <= 1163 if (BTRFS_I(inode)->last_trans <=
1150 root->fs_info->last_trans_committed) { 1164 root->fs_info->last_trans_committed) {
@@ -1154,13 +1168,6 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1154 } 1168 }
1155 mutex_unlock(&root->fs_info->trans_mutex); 1169 mutex_unlock(&root->fs_info->trans_mutex);
1156 1170
1157 root->log_batch++;
1158 filemap_fdatawrite(inode->i_mapping);
1159 btrfs_wait_ordered_range(inode, 0, (u64)-1);
1160 root->log_batch++;
1161
1162 if (datasync && !(inode->i_state & I_DIRTY_PAGES))
1163 goto out;
1164 /* 1171 /*
1165 * ok we haven't committed the transaction yet, lets do a commit 1172 * ok we haven't committed the transaction yet, lets do a commit
1166 */ 1173 */
@@ -1189,14 +1196,18 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1189 */ 1196 */
1190 mutex_unlock(&dentry->d_inode->i_mutex); 1197 mutex_unlock(&dentry->d_inode->i_mutex);
1191 1198
1192 if (ret > 0) { 1199 if (ret != BTRFS_NO_LOG_SYNC) {
1193 ret = btrfs_commit_transaction(trans, root); 1200 if (ret > 0) {
1194 } else {
1195 ret = btrfs_sync_log(trans, root);
1196 if (ret == 0)
1197 ret = btrfs_end_transaction(trans, root);
1198 else
1199 ret = btrfs_commit_transaction(trans, root); 1201 ret = btrfs_commit_transaction(trans, root);
1202 } else {
1203 ret = btrfs_sync_log(trans, root);
1204 if (ret == 0)
1205 ret = btrfs_end_transaction(trans, root);
1206 else
1207 ret = btrfs_commit_transaction(trans, root);
1208 }
1209 } else {
1210 ret = btrfs_end_transaction(trans, root);
1200 } 1211 }
1201 mutex_lock(&dentry->d_inode->i_mutex); 1212 mutex_lock(&dentry->d_inode->i_mutex);
1202out: 1213out:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ef399a7794ff..5b9567caba0a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3480,6 +3480,7 @@ static noinline void init_btrfs_i(struct inode *inode)
3480 bi->generation = 0; 3480 bi->generation = 0;
3481 bi->sequence = 0; 3481 bi->sequence = 0;
3482 bi->last_trans = 0; 3482 bi->last_trans = 0;
3483 bi->last_sub_trans = 0;
3483 bi->logged_trans = 0; 3484 bi->logged_trans = 0;
3484 bi->delalloc_bytes = 0; 3485 bi->delalloc_bytes = 0;
3485 bi->reserved_bytes = 0; 3486 bi->reserved_bytes = 0;
@@ -4980,7 +4981,9 @@ again:
4980 set_page_dirty(page); 4981 set_page_dirty(page);
4981 SetPageUptodate(page); 4982 SetPageUptodate(page);
4982 4983
4983 BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; 4984 BTRFS_I(inode)->last_trans = root->fs_info->generation;
4985 BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
4986
4984 unlock_extent(io_tree, page_start, page_end, GFP_NOFS); 4987 unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
4985 4988
4986out_unlock: 4989out_unlock:
@@ -5100,6 +5103,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
5100 if (!ei) 5103 if (!ei)
5101 return NULL; 5104 return NULL;
5102 ei->last_trans = 0; 5105 ei->last_trans = 0;
5106 ei->last_sub_trans = 0;
5103 ei->logged_trans = 0; 5107 ei->logged_trans = 0;
5104 ei->outstanding_extents = 0; 5108 ei->outstanding_extents = 0;
5105 ei->reserved_extents = 0; 5109 ei->reserved_extents = 0;
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 663c67404918..f68cbbe61e56 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -79,6 +79,7 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
79 struct inode *inode) 79 struct inode *inode)
80{ 80{
81 BTRFS_I(inode)->last_trans = trans->transaction->transid; 81 BTRFS_I(inode)->last_trans = trans->transaction->transid;
82 BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
82} 83}
83 84
84int btrfs_end_transaction(struct btrfs_trans_handle *trans, 85int btrfs_end_transaction(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 6d9ec285644d..0a1bde268963 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1980,6 +1980,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
1980 int ret; 1980 int ret;
1981 struct btrfs_root *log = root->log_root; 1981 struct btrfs_root *log = root->log_root;
1982 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; 1982 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
1983 u64 log_transid = 0;
1983 1984
1984 mutex_lock(&root->log_mutex); 1985 mutex_lock(&root->log_mutex);
1985 index1 = root->log_transid % 2; 1986 index1 = root->log_transid % 2;
@@ -2018,6 +2019,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2018 btrfs_set_root_node(&log->root_item, log->node); 2019 btrfs_set_root_node(&log->root_item, log->node);
2019 2020
2020 root->log_batch = 0; 2021 root->log_batch = 0;
2022 log_transid = root->log_transid;
2021 root->log_transid++; 2023 root->log_transid++;
2022 log->log_transid = root->log_transid; 2024 log->log_transid = root->log_transid;
2023 root->log_start_pid = 0; 2025 root->log_start_pid = 0;
@@ -2095,6 +2097,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2095 write_ctree_super(trans, root->fs_info->tree_root, 1); 2097 write_ctree_super(trans, root->fs_info->tree_root, 1);
2096 ret = 0; 2098 ret = 0;
2097 2099
2100 mutex_lock(&root->log_mutex);
2101 if (root->last_log_commit < log_transid)
2102 root->last_log_commit = log_transid;
2103 mutex_unlock(&root->log_mutex);
2104
2098out_wake_log_root: 2105out_wake_log_root:
2099 atomic_set(&log_root_tree->log_commit[index2], 0); 2106 atomic_set(&log_root_tree->log_commit[index2], 0);
2100 smp_mb(); 2107 smp_mb();
@@ -2862,6 +2869,21 @@ out:
2862 return ret; 2869 return ret;
2863} 2870}
2864 2871
2872static int inode_in_log(struct btrfs_trans_handle *trans,
2873 struct inode *inode)
2874{
2875 struct btrfs_root *root = BTRFS_I(inode)->root;
2876 int ret = 0;
2877
2878 mutex_lock(&root->log_mutex);
2879 if (BTRFS_I(inode)->logged_trans == trans->transid &&
2880 BTRFS_I(inode)->last_sub_trans <= root->last_log_commit)
2881 ret = 1;
2882 mutex_unlock(&root->log_mutex);
2883 return ret;
2884}
2885
2886
2865/* 2887/*
2866 * helper function around btrfs_log_inode to make sure newly created 2888 * helper function around btrfs_log_inode to make sure newly created
2867 * parent directories also end up in the log. A minimal inode and backref 2889 * parent directories also end up in the log. A minimal inode and backref
@@ -2901,6 +2923,11 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
2901 if (ret) 2923 if (ret)
2902 goto end_no_trans; 2924 goto end_no_trans;
2903 2925
2926 if (inode_in_log(trans, inode)) {
2927 ret = BTRFS_NO_LOG_SYNC;
2928 goto end_no_trans;
2929 }
2930
2904 start_log_trans(trans, root); 2931 start_log_trans(trans, root);
2905 2932
2906 ret = btrfs_log_inode(trans, root, inode, inode_only); 2933 ret = btrfs_log_inode(trans, root, inode, inode_only);
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index d09c7609e16b..0776eacb5083 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -19,6 +19,9 @@
19#ifndef __TREE_LOG_ 19#ifndef __TREE_LOG_
20#define __TREE_LOG_ 20#define __TREE_LOG_
21 21
22/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */
23#define BTRFS_NO_LOG_SYNC 256
24
22int btrfs_sync_log(struct btrfs_trans_handle *trans, 25int btrfs_sync_log(struct btrfs_trans_handle *trans,
23 struct btrfs_root *root); 26 struct btrfs_root *root);
24int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); 27int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);