aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
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 /fs/btrfs/file.c
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>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c41
1 files changed, 26 insertions, 15 deletions
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: