Skip to content

Commit

Permalink
Btrfs: don't mix the ordered extents of all files together during log…
Browse files Browse the repository at this point in the history
…ging the inodes

There was a problem in the old code:
If we failed to log the csum, we would free all the ordered extents in the log list
including those ordered extents that were logged successfully, it would make the
log committer not to wait for the completion of the ordered extents.

This patch doesn't insert the ordered extents that is about to be logged into
a global list, instead, we insert them into a local list. If we log the ordered
extents successfully, we splice them with the global list, or we will throw them
away, then do full sync. It can also reduce the lock contention and the traverse
time of list.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
  • Loading branch information
Miao Xie authored and Josef Bacik committed Mar 10, 2014
1 parent 93de4ba commit 827463c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 35 deletions.
37 changes: 29 additions & 8 deletions fs/btrfs/ordered-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,27 +424,48 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
}

/* Needs to either be called under a log transaction or the log_mutex */
void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode)
void btrfs_get_logged_extents(struct inode *inode,
struct list_head *logged_list)
{
struct btrfs_ordered_inode_tree *tree;
struct btrfs_ordered_extent *ordered;
struct rb_node *n;
int index = log->log_transid % 2;

tree = &BTRFS_I(inode)->ordered_tree;
spin_lock_irq(&tree->lock);
for (n = rb_first(&tree->tree); n; n = rb_next(n)) {
ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node);
spin_lock(&log->log_extents_lock[index]);
if (list_empty(&ordered->log_list)) {
list_add_tail(&ordered->log_list, &log->logged_list[index]);
atomic_inc(&ordered->refs);
}
spin_unlock(&log->log_extents_lock[index]);
if (!list_empty(&ordered->log_list))
continue;
list_add_tail(&ordered->log_list, logged_list);
atomic_inc(&ordered->refs);
}
spin_unlock_irq(&tree->lock);
}

void btrfs_put_logged_extents(struct list_head *logged_list)
{
struct btrfs_ordered_extent *ordered;

while (!list_empty(logged_list)) {
ordered = list_first_entry(logged_list,
struct btrfs_ordered_extent,
log_list);
list_del_init(&ordered->log_list);
btrfs_put_ordered_extent(ordered);
}
}

void btrfs_submit_logged_extents(struct list_head *logged_list,
struct btrfs_root *log)
{
int index = log->log_transid % 2;

spin_lock_irq(&log->log_extents_lock[index]);
list_splice_tail(logged_list, &log->logged_list[index]);
spin_unlock_irq(&log->log_extents_lock[index]);
}

void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid)
{
struct btrfs_ordered_extent *ordered;
Expand Down
6 changes: 5 additions & 1 deletion fs/btrfs/ordered-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
struct inode *inode);
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr);
void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr);
void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode);
void btrfs_get_logged_extents(struct inode *inode,
struct list_head *logged_list);
void btrfs_put_logged_extents(struct list_head *logged_list);
void btrfs_submit_logged_extents(struct list_head *logged_list,
struct btrfs_root *log);
void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid);
void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
int __init ordered_data_init(void);
Expand Down
41 changes: 15 additions & 26 deletions fs/btrfs/tree-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -3479,7 +3479,8 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b)

static int log_one_extent(struct btrfs_trans_handle *trans,
struct inode *inode, struct btrfs_root *root,
struct extent_map *em, struct btrfs_path *path)
struct extent_map *em, struct btrfs_path *path,
struct list_head *logged_list)
{
struct btrfs_root *log = root->log_root;
struct btrfs_file_extent_item *fi;
Expand All @@ -3495,7 +3496,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
u64 extent_offset = em->start - em->orig_start;
u64 block_len;
int ret;
int index = log->log_transid % 2;
bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
int extent_inserted = 0;

Expand Down Expand Up @@ -3579,17 +3579,12 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
* First check and see if our csums are on our outstanding ordered
* extents.
*/
again:
spin_lock_irq(&log->log_extents_lock[index]);
list_for_each_entry(ordered, &log->logged_list[index], log_list) {
list_for_each_entry(ordered, logged_list, log_list) {
struct btrfs_ordered_sum *sum;

if (!mod_len)
break;

if (ordered->inode != inode)
continue;

if (ordered->file_offset + ordered->len <= mod_start ||
mod_start + mod_len <= ordered->file_offset)
continue;
Expand Down Expand Up @@ -3632,12 +3627,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM,
&ordered->flags))
continue;
atomic_inc(&ordered->refs);
spin_unlock_irq(&log->log_extents_lock[index]);
/*
* we've dropped the lock, we must either break or
* start over after this.
*/

if (ordered->csum_bytes_left) {
btrfs_start_ordered_extent(inode, ordered, 0);
Expand All @@ -3647,16 +3636,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans,

list_for_each_entry(sum, &ordered->list, list) {
ret = btrfs_csum_file_blocks(trans, log, sum);
if (ret) {
btrfs_put_ordered_extent(ordered);
if (ret)
goto unlocked;
}
}
btrfs_put_ordered_extent(ordered);
goto again;

}
spin_unlock_irq(&log->log_extents_lock[index]);
unlocked:

if (!mod_len || ret)
Expand Down Expand Up @@ -3694,7 +3678,8 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode,
struct btrfs_path *path)
struct btrfs_path *path,
struct list_head *logged_list)
{
struct extent_map *em, *n;
struct list_head extents;
Expand Down Expand Up @@ -3752,7 +3737,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,

write_unlock(&tree->lock);

ret = log_one_extent(trans, inode, root, em, path);
ret = log_one_extent(trans, inode, root, em, path, logged_list);
write_lock(&tree->lock);
clear_em_logging(tree, em);
free_extent_map(em);
Expand Down Expand Up @@ -3788,6 +3773,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_key max_key;
struct btrfs_root *log = root->log_root;
struct extent_buffer *src = NULL;
LIST_HEAD(logged_list);
u64 last_extent = 0;
int err = 0;
int ret;
Expand Down Expand Up @@ -3836,7 +3822,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,

mutex_lock(&BTRFS_I(inode)->log_mutex);

btrfs_get_logged_extents(log, inode);
btrfs_get_logged_extents(inode, &logged_list);

/*
* a brute force approach to making sure we get the most uptodate
Expand Down Expand Up @@ -3962,7 +3948,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
btrfs_release_path(path);
btrfs_release_path(dst_path);
if (fast_search) {
ret = btrfs_log_changed_extents(trans, root, inode, dst_path);
ret = btrfs_log_changed_extents(trans, root, inode, dst_path,
&logged_list);
if (ret) {
err = ret;
goto out_unlock;
Expand All @@ -3987,8 +3974,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
BTRFS_I(inode)->logged_trans = trans->transid;
BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans;
out_unlock:
if (err)
btrfs_free_logged_extents(log, log->log_transid);
if (unlikely(err))
btrfs_put_logged_extents(&logged_list);
else
btrfs_submit_logged_extents(&logged_list, log);
mutex_unlock(&BTRFS_I(inode)->log_mutex);

btrfs_free_path(path);
Expand Down

0 comments on commit 827463c

Please sign in to comment.