diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2014-02-20 18:08:52 +0800 |
---|---|---|
committer | Josef Bacik <jbacik@fb.com> | 2014-03-10 15:16:40 -0400 |
commit | 48cab2e0714913a63155f800a55609a4ff6a36b9 (patch) | |
tree | 1767dcb212dc53386e30e4bafa13b1bc8f475785 /fs/btrfs/tree-log.c | |
parent | 5c902ba6223f6a6575054226931fafc51314a25f (diff) | |
download | lwn-48cab2e0714913a63155f800a55609a4ff6a36b9.tar.gz lwn-48cab2e0714913a63155f800a55609a4ff6a36b9.zip |
Btrfs: fix the skipped transaction commit during the file sync
We may abort the wait earlier if ->last_trans_log_full_commit was set to
the current transaction id, at this case, we need commit the current
transaction instead of the log sub-transaction. But the current code
didn't tell the caller to do it (return 0, not -EAGAIN). Fix it.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5a4e10b9ac3e..8a03b39648be 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2364,6 +2364,7 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, { DEFINE_WAIT(wait); int index = transid % 2; + int ret = 0; /* * we only allow two pending log transactions at a time, @@ -2371,21 +2372,26 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, * current transaction, we're done */ do { + if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == + trans->transid) { + ret = -EAGAIN; + break; + } + prepare_to_wait(&root->log_commit_wait[index], &wait, TASK_UNINTERRUPTIBLE); mutex_unlock(&root->log_mutex); - if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && root->log_transid < transid + 2 && + if (root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])) schedule(); finish_wait(&root->log_commit_wait[index], &wait); mutex_lock(&root->log_mutex); - } while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != - trans->transid && root->log_transid < transid + 2 && + } while (root->log_transid < transid + 2 && atomic_read(&root->log_commit[index])); - return 0; + + return ret; } static void wait_for_writer(struct btrfs_trans_handle *trans, @@ -2433,15 +2439,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, log_transid = root->log_transid; index1 = root->log_transid % 2; if (atomic_read(&root->log_commit[index1])) { - wait_log_commit(trans, root, root->log_transid); + ret = wait_log_commit(trans, root, root->log_transid); mutex_unlock(&root->log_mutex); - return 0; + return ret; } atomic_set(&root->log_commit[index1], 1); /* wait for previous tree log sync to complete */ if (atomic_read(&root->log_commit[(index1 + 1) % 2])) wait_log_commit(trans, root, root->log_transid - 1); + while (1) { int batch = atomic_read(&root->log_batch); /* when we're on an ssd, just kick the log commit out */ @@ -2529,11 +2536,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (atomic_read(&log_root_tree->log_commit[index2])) { blk_finish_plug(&plug); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - wait_log_commit(trans, log_root_tree, - log_root_tree->log_transid); + ret = wait_log_commit(trans, log_root_tree, + log_root_tree->log_transid); btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); - ret = 0; goto out; } atomic_set(&log_root_tree->log_commit[index2], 1); |