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>
This commit is contained in:
@@ -1980,6 +1980,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
struct btrfs_root *log = root->log_root;
|
||||
struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
|
||||
u64 log_transid = 0;
|
||||
|
||||
mutex_lock(&root->log_mutex);
|
||||
index1 = root->log_transid % 2;
|
||||
@@ -2018,6 +2019,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_root_node(&log->root_item, log->node);
|
||||
|
||||
root->log_batch = 0;
|
||||
log_transid = root->log_transid;
|
||||
root->log_transid++;
|
||||
log->log_transid = root->log_transid;
|
||||
root->log_start_pid = 0;
|
||||
@@ -2095,6 +2097,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||
write_ctree_super(trans, root->fs_info->tree_root, 1);
|
||||
ret = 0;
|
||||
|
||||
mutex_lock(&root->log_mutex);
|
||||
if (root->last_log_commit < log_transid)
|
||||
root->last_log_commit = log_transid;
|
||||
mutex_unlock(&root->log_mutex);
|
||||
|
||||
out_wake_log_root:
|
||||
atomic_set(&log_root_tree->log_commit[index2], 0);
|
||||
smp_mb();
|
||||
@@ -2862,6 +2869,21 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int inode_in_log(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&root->log_mutex);
|
||||
if (BTRFS_I(inode)->logged_trans == trans->transid &&
|
||||
BTRFS_I(inode)->last_sub_trans <= root->last_log_commit)
|
||||
ret = 1;
|
||||
mutex_unlock(&root->log_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* helper function around btrfs_log_inode to make sure newly created
|
||||
* 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,
|
||||
if (ret)
|
||||
goto end_no_trans;
|
||||
|
||||
if (inode_in_log(trans, inode)) {
|
||||
ret = BTRFS_NO_LOG_SYNC;
|
||||
goto end_no_trans;
|
||||
}
|
||||
|
||||
start_log_trans(trans, root);
|
||||
|
||||
ret = btrfs_log_inode(trans, root, inode, inode_only);
|
||||
|
Reference in New Issue
Block a user