diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-10-13 13:21:08 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-10-13 13:35:12 -0400 |
commit | 257c62e1bce03e5b9f3f069fd52ad73a56de71fd (patch) | |
tree | ad047fe5796156aa88e3f3600111bf2b8d12759f /fs/btrfs/file.c | |
parent | 4722607db6a78bd7748c51fa4c8d7371da797254 (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.c | 41 |
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); |
1202 | out: | 1213 | out: |