aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-09-11 15:53:12 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:07 -0400
commit49eb7e46d47ea72a9bd2a5f8cedb04f5159cc277 (patch)
treec3d05588c3cf73453673206214fadedc07bd79d7
parent98509cfc5a6857bddcfe4b19a9539726655ec9bd (diff)
Btrfs: Dir fsync optimizations
Drop i_mutex during the commit Don't bother doing the fsync at all unless the dir is marked as dirtied and needing fsync in this transaction. For directories, this means that someone has unlinked a file from the dir without fsyncing the file. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/btrfs_inode.h3
-rw-r--r--fs/btrfs/file.c19
-rw-r--r--fs/btrfs/inode.c5
-rw-r--r--fs/btrfs/tree-log.c8
4 files changed, 29 insertions, 6 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index fcc8cf27e906..0577fda2168a 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -56,6 +56,9 @@ struct btrfs_inode {
56 * transid that last logged this inode 56 * transid that last logged this inode
57 */ 57 */
58 u64 logged_trans; 58 u64 logged_trans;
59
60 /* trans that last made a change that should be fully fsync'd */
61 u64 log_dirty_trans;
59 u64 delalloc_bytes; 62 u64 delalloc_bytes;
60 u64 disk_i_size; 63 u64 disk_i_size;
61 u32 flags; 64 u32 flags;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 84ecf3ab8511..58b329ddb426 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1061,7 +1061,9 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1061 } 1061 }
1062 mutex_unlock(&root->fs_info->trans_mutex); 1062 mutex_unlock(&root->fs_info->trans_mutex);
1063 1063
1064 root->fs_info->tree_log_batch++;
1064 filemap_fdatawait(inode->i_mapping); 1065 filemap_fdatawait(inode->i_mapping);
1066 root->fs_info->tree_log_batch++;
1065 1067
1066 /* 1068 /*
1067 * ok we haven't committed the transaction yet, lets do a commit 1069 * ok we haven't committed the transaction yet, lets do a commit
@@ -1076,14 +1078,29 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
1076 } 1078 }
1077 1079
1078 ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); 1080 ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
1079 if (ret < 0) 1081 if (ret < 0) {
1080 goto out; 1082 goto out;
1083 }
1084
1085 /* we've logged all the items and now have a consistent
1086 * version of the file in the log. It is possible that
1087 * someone will come in and modify the file, but that's
1088 * fine because the log is consistent on disk, and we
1089 * have references to all of the file's extents
1090 *
1091 * It is possible that someone will come in and log the
1092 * file again, but that will end up using the synchronization
1093 * inside btrfs_sync_log to keep things safe.
1094 */
1095 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
1096
1081 if (ret > 0) { 1097 if (ret > 0) {
1082 ret = btrfs_commit_transaction(trans, root); 1098 ret = btrfs_commit_transaction(trans, root);
1083 } else { 1099 } else {
1084 btrfs_sync_log(trans, root); 1100 btrfs_sync_log(trans, root);
1085 ret = btrfs_end_transaction(trans, root); 1101 ret = btrfs_end_transaction(trans, root);
1086 } 1102 }
1103 mutex_lock(&file->f_dentry->d_inode->i_mutex);
1087out: 1104out:
1088 return ret > 0 ? EIO : ret; 1105 return ret > 0 ? EIO : ret;
1089} 1106}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 24b7e97fccb9..12c1c0530f3d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1187,7 +1187,9 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
1187 1187
1188 ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len, 1188 ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
1189 inode, dir->i_ino); 1189 inode, dir->i_ino);
1190 BUG_ON(ret); 1190 BUG_ON(ret != 0 && ret != -ENOENT);
1191 if (ret != -ENOENT)
1192 BTRFS_I(dir)->log_dirty_trans = trans->transid;
1191 1193
1192 ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len, 1194 ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
1193 dir, index); 1195 dir, index);
@@ -1790,6 +1792,7 @@ static noinline void init_btrfs_i(struct inode *inode)
1790 bi->disk_i_size = 0; 1792 bi->disk_i_size = 0;
1791 bi->flags = 0; 1793 bi->flags = 0;
1792 bi->index_cnt = (u64)-1; 1794 bi->index_cnt = (u64)-1;
1795 bi->log_dirty_trans = 0;
1793 extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS); 1796 extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
1794 extent_io_tree_init(&BTRFS_I(inode)->io_tree, 1797 extent_io_tree_init(&BTRFS_I(inode)->io_tree,
1795 inode->i_mapping, GFP_NOFS); 1798 inode->i_mapping, GFP_NOFS);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 3f4b139b27ed..5d49a701bdcd 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1973,10 +1973,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
1973 atomic_set(&log->fs_info->tree_log_commit, 1); 1973 atomic_set(&log->fs_info->tree_log_commit, 1);
1974 1974
1975 while(1) { 1975 while(1) {
1976 batch = log->fs_info->tree_log_batch;
1976 mutex_unlock(&log->fs_info->tree_log_mutex); 1977 mutex_unlock(&log->fs_info->tree_log_mutex);
1977 schedule_timeout_uninterruptible(1); 1978 schedule_timeout_uninterruptible(1);
1978 mutex_lock(&log->fs_info->tree_log_mutex); 1979 mutex_lock(&log->fs_info->tree_log_mutex);
1979 batch = log->fs_info->tree_log_batch;
1980 1980
1981 while(atomic_read(&log->fs_info->tree_log_writers)) { 1981 while(atomic_read(&log->fs_info->tree_log_writers)) {
1982 DEFINE_WAIT(wait); 1982 DEFINE_WAIT(wait);
@@ -2189,8 +2189,6 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
2189 mutex_unlock(&BTRFS_I(inode)->log_mutex); 2189 mutex_unlock(&BTRFS_I(inode)->log_mutex);
2190 end_log_trans(root); 2190 end_log_trans(root);
2191 2191
2192 if (ret == 0 || ret == -ENOENT)
2193 return 0;
2194 return ret; 2192 return ret;
2195} 2193}
2196 2194
@@ -2620,9 +2618,11 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
2620 else 2618 else
2621 break; 2619 break;
2622 } 2620 }
2623 if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { 2621 if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode) &&
2622 BTRFS_I(inode)->log_dirty_trans >= trans->transid) {
2624 btrfs_release_path(root, path); 2623 btrfs_release_path(root, path);
2625 btrfs_release_path(log, dst_path); 2624 btrfs_release_path(log, dst_path);
2625 BTRFS_I(inode)->log_dirty_trans = 0;
2626 ret = log_directory_changes(trans, root, inode, path, dst_path); 2626 ret = log_directory_changes(trans, root, inode, path, dst_path);
2627 BUG_ON(ret); 2627 BUG_ON(ret);
2628 } 2628 }