Skip to content

Commit 49eb7e4

Browse files
committed
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 <[email protected]>
1 parent 98509cf commit 49eb7e4

File tree

4 files changed

+29
-6
lines changed

4 files changed

+29
-6
lines changed

fs/btrfs/btrfs_inode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ struct btrfs_inode {
5656
* transid that last logged this inode
5757
*/
5858
u64 logged_trans;
59+
60+
/* trans that last made a change that should be fully fsync'd */
61+
u64 log_dirty_trans;
5962
u64 delalloc_bytes;
6063
u64 disk_i_size;
6164
u32 flags;

fs/btrfs/file.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,9 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
10611061
}
10621062
mutex_unlock(&root->fs_info->trans_mutex);
10631063

1064+
root->fs_info->tree_log_batch++;
10641065
filemap_fdatawait(inode->i_mapping);
1066+
root->fs_info->tree_log_batch++;
10651067

10661068
/*
10671069
* 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)
10761078
}
10771079

10781080
ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
1079-
if (ret < 0)
1081+
if (ret < 0) {
10801082
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+
10811097
if (ret > 0) {
10821098
ret = btrfs_commit_transaction(trans, root);
10831099
} else {
10841100
btrfs_sync_log(trans, root);
10851101
ret = btrfs_end_transaction(trans, root);
10861102
}
1103+
mutex_lock(&file->f_dentry->d_inode->i_mutex);
10871104
out:
10881105
return ret > 0 ? EIO : ret;
10891106
}

fs/btrfs/inode.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,9 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
11871187

11881188
ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
11891189
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;
11911193

11921194
ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
11931195
dir, index);
@@ -1790,6 +1792,7 @@ static noinline void init_btrfs_i(struct inode *inode)
17901792
bi->disk_i_size = 0;
17911793
bi->flags = 0;
17921794
bi->index_cnt = (u64)-1;
1795+
bi->log_dirty_trans = 0;
17931796
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
17941797
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
17951798
inode->i_mapping, GFP_NOFS);

fs/btrfs/tree-log.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,10 +1973,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
19731973
atomic_set(&log->fs_info->tree_log_commit, 1);
19741974

19751975
while(1) {
1976+
batch = log->fs_info->tree_log_batch;
19761977
mutex_unlock(&log->fs_info->tree_log_mutex);
19771978
schedule_timeout_uninterruptible(1);
19781979
mutex_lock(&log->fs_info->tree_log_mutex);
1979-
batch = log->fs_info->tree_log_batch;
19801980

19811981
while(atomic_read(&log->fs_info->tree_log_writers)) {
19821982
DEFINE_WAIT(wait);
@@ -2189,8 +2189,6 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
21892189
mutex_unlock(&BTRFS_I(inode)->log_mutex);
21902190
end_log_trans(root);
21912191

2192-
if (ret == 0 || ret == -ENOENT)
2193-
return 0;
21942192
return ret;
21952193
}
21962194

@@ -2620,9 +2618,11 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
26202618
else
26212619
break;
26222620
}
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) {
26242623
btrfs_release_path(root, path);
26252624
btrfs_release_path(log, dst_path);
2625+
BTRFS_I(inode)->log_dirty_trans = 0;
26262626
ret = log_directory_changes(trans, root, inode, path, dst_path);
26272627
BUG_ON(ret);
26282628
}

0 commit comments

Comments
 (0)