Skip to content

Commit

Permalink
Btrfs: Dir fsync optimizations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Mason committed Sep 25, 2008
1 parent 98509cf commit 49eb7e4
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 6 deletions.
3 changes: 3 additions & 0 deletions fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ struct btrfs_inode {
* transid that last logged this inode
*/
u64 logged_trans;

/* trans that last made a change that should be fully fsync'd */
u64 log_dirty_trans;
u64 delalloc_bytes;
u64 disk_i_size;
u32 flags;
Expand Down
19 changes: 18 additions & 1 deletion fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,9 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
}
mutex_unlock(&root->fs_info->trans_mutex);

root->fs_info->tree_log_batch++;
filemap_fdatawait(inode->i_mapping);
root->fs_info->tree_log_batch++;

/*
* ok we haven't committed the transaction yet, lets do a commit
Expand All @@ -1076,14 +1078,29 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
}

ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
if (ret < 0)
if (ret < 0) {
goto out;
}

/* we've logged all the items and now have a consistent
* version of the file in the log. It is possible that
* someone will come in and modify the file, but that's
* fine because the log is consistent on disk, and we
* have references to all of the file's extents
*
* It is possible that someone will come in and log the
* file again, but that will end up using the synchronization
* inside btrfs_sync_log to keep things safe.
*/
mutex_unlock(&file->f_dentry->d_inode->i_mutex);

if (ret > 0) {
ret = btrfs_commit_transaction(trans, root);
} else {
btrfs_sync_log(trans, root);
ret = btrfs_end_transaction(trans, root);
}
mutex_lock(&file->f_dentry->d_inode->i_mutex);
out:
return ret > 0 ? EIO : ret;
}
Expand Down
5 changes: 4 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,9 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,

ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
inode, dir->i_ino);
BUG_ON(ret);
BUG_ON(ret != 0 && ret != -ENOENT);
if (ret != -ENOENT)
BTRFS_I(dir)->log_dirty_trans = trans->transid;

ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
dir, index);
Expand Down Expand Up @@ -1790,6 +1792,7 @@ static noinline void init_btrfs_i(struct inode *inode)
bi->disk_i_size = 0;
bi->flags = 0;
bi->index_cnt = (u64)-1;
bi->log_dirty_trans = 0;
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
inode->i_mapping, GFP_NOFS);
Expand Down
8 changes: 4 additions & 4 deletions fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1973,10 +1973,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
atomic_set(&log->fs_info->tree_log_commit, 1);

while(1) {
batch = log->fs_info->tree_log_batch;
mutex_unlock(&log->fs_info->tree_log_mutex);
schedule_timeout_uninterruptible(1);
mutex_lock(&log->fs_info->tree_log_mutex);
batch = log->fs_info->tree_log_batch;

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

if (ret == 0 || ret == -ENOENT)
return 0;
return ret;
}

Expand Down Expand Up @@ -2620,9 +2618,11 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans,
else
break;
}
if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode) &&
BTRFS_I(inode)->log_dirty_trans >= trans->transid) {
btrfs_release_path(root, path);
btrfs_release_path(log, dst_path);
BTRFS_I(inode)->log_dirty_trans = 0;
ret = log_directory_changes(trans, root, inode, path, dst_path);
BUG_ON(ret);
}
Expand Down

0 comments on commit 49eb7e4

Please sign in to comment.