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/tree-log.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/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 27 | 
1 files changed, 27 insertions, 0 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 6d9ec285644d..0a1bde268963 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -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); | 
