Commit fdfbf020 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

btrfs: rework async transaction committing

Currently we do this awful thing where we get another ref on a trans
handle, async off that handle and commit the transaction from that work.
Because we do this we have to mess with current->journal_info and the
freeze counting stuff.

We already have an async thing to kick for the transaction commit, the
transaction kthread.  Replace this work struct with a flag on the
fs_info to tell the kthread to go ahead and commit even if it's before
our timeout.  Then we can drastically simplify the async transaction
commit path.

Note: this can be simplified and functionality based on the pending
operation COMMIT.
Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
[ add note ]
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 0af4769d
...@@ -595,6 +595,9 @@ enum { ...@@ -595,6 +595,9 @@ enum {
/* Indicate whether there are any tree modification log users */ /* Indicate whether there are any tree modification log users */
BTRFS_FS_TREE_MOD_LOG_USERS, BTRFS_FS_TREE_MOD_LOG_USERS,
/* Indicate that we want the transaction kthread to commit right now. */
BTRFS_FS_COMMIT_TRANS,
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
/* Indicate if we have error/warn message printed on 32bit systems */ /* Indicate if we have error/warn message printed on 32bit systems */
BTRFS_FS_32BIT_ERROR, BTRFS_FS_32BIT_ERROR,
......
...@@ -1934,7 +1934,8 @@ static int transaction_kthread(void *arg) ...@@ -1934,7 +1934,8 @@ static int transaction_kthread(void *arg)
} }
delta = ktime_get_seconds() - cur->start_time; delta = ktime_get_seconds() - cur->start_time;
if (cur->state < TRANS_STATE_COMMIT_START && if (!test_and_clear_bit(BTRFS_FS_COMMIT_TRANS, &fs_info->flags) &&
cur->state < TRANS_STATE_COMMIT_START &&
delta < fs_info->commit_interval) { delta < fs_info->commit_interval) {
spin_unlock(&fs_info->trans_lock); spin_unlock(&fs_info->trans_lock);
delay -= msecs_to_jiffies((delta - 1) * 1000); delay -= msecs_to_jiffies((delta - 1) * 1000);
......
...@@ -3622,7 +3622,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, ...@@ -3622,7 +3622,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
u64 transid; u64 transid;
int ret;
trans = btrfs_attach_transaction_barrier(root); trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
...@@ -3634,11 +3633,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, ...@@ -3634,11 +3633,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
goto out; goto out;
} }
transid = trans->transid; transid = trans->transid;
ret = btrfs_commit_transaction_async(trans); btrfs_commit_transaction_async(trans);
if (ret) {
btrfs_end_transaction(trans);
return ret;
}
out: out:
if (argp) if (argp)
if (copy_to_user(argp, &transid, sizeof(transid))) if (copy_to_user(argp, &transid, sizeof(transid)))
......
...@@ -1880,50 +1880,14 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) ...@@ -1880,50 +1880,14 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info)
return ret; return ret;
} }
/* void btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
* commit transactions asynchronously. once btrfs_commit_transaction_async
* returns, any subsequent transaction will not be allowed to join.
*/
struct btrfs_async_commit {
struct btrfs_trans_handle *newtrans;
struct work_struct work;
};
static void do_async_commit(struct work_struct *work)
{
struct btrfs_async_commit *ac =
container_of(work, struct btrfs_async_commit, work);
/*
* We've got freeze protection passed with the transaction.
* Tell lockdep about it.
*/
if (ac->newtrans->type & __TRANS_FREEZABLE)
__sb_writers_acquired(ac->newtrans->fs_info->sb, SB_FREEZE_FS);
current->journal_info = ac->newtrans;
btrfs_commit_transaction(ac->newtrans);
kfree(ac);
}
int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_async_commit *ac;
struct btrfs_transaction *cur_trans; struct btrfs_transaction *cur_trans;
ac = kmalloc(sizeof(*ac), GFP_NOFS); /* Kick the transaction kthread. */
if (!ac) set_bit(BTRFS_FS_COMMIT_TRANS, &fs_info->flags);
return -ENOMEM; wake_up_process(fs_info->transaction_kthread);
INIT_WORK(&ac->work, do_async_commit);
ac->newtrans = btrfs_join_transaction(trans->root);
if (IS_ERR(ac->newtrans)) {
int err = PTR_ERR(ac->newtrans);
kfree(ac);
return err;
}
/* take transaction reference */ /* take transaction reference */
cur_trans = trans->transaction; cur_trans = trans->transaction;
...@@ -1931,14 +1895,6 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans) ...@@ -1931,14 +1895,6 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
/*
* Tell lockdep we've released the freeze rwsem, since the
* async commit thread will be the one to unlock it.
*/
if (ac->newtrans->type & __TRANS_FREEZABLE)
__sb_writers_release(fs_info->sb, SB_FREEZE_FS);
schedule_work(&ac->work);
/* /*
* Wait for the current transaction commit to start and block * Wait for the current transaction commit to start and block
* subsequent transaction joins * subsequent transaction joins
...@@ -1946,14 +1902,9 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans) ...@@ -1946,14 +1902,9 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
wait_event(fs_info->transaction_blocked_wait, wait_event(fs_info->transaction_blocked_wait,
cur_trans->state >= TRANS_STATE_COMMIT_START || cur_trans->state >= TRANS_STATE_COMMIT_START ||
TRANS_ABORTED(cur_trans)); TRANS_ABORTED(cur_trans));
if (current->journal_info == trans)
current->journal_info = NULL;
btrfs_put_transaction(cur_trans); btrfs_put_transaction(cur_trans);
return 0;
} }
static void cleanup_transaction(struct btrfs_trans_handle *trans, int err) static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
...@@ -2219,6 +2170,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) ...@@ -2219,6 +2170,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
wait_event(cur_trans->writer_wait, wait_event(cur_trans->writer_wait,
atomic_read(&cur_trans->num_writers) == 1); atomic_read(&cur_trans->num_writers) == 1);
/*
* We've started the commit, clear the flag in case we were triggered to
* do an async commit but somebody else started before the transaction
* kthread could do the work.
*/
clear_bit(BTRFS_FS_COMMIT_TRANS, &fs_info->flags);
if (TRANS_ABORTED(cur_trans)) { if (TRANS_ABORTED(cur_trans)) {
ret = cur_trans->aborted; ret = cur_trans->aborted;
goto scrub_continue; goto scrub_continue;
......
...@@ -217,7 +217,7 @@ void btrfs_add_dead_root(struct btrfs_root *root); ...@@ -217,7 +217,7 @@ void btrfs_add_dead_root(struct btrfs_root *root);
int btrfs_defrag_root(struct btrfs_root *root); int btrfs_defrag_root(struct btrfs_root *root);
int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root); int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root);
int btrfs_commit_transaction(struct btrfs_trans_handle *trans); int btrfs_commit_transaction(struct btrfs_trans_handle *trans);
int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans); void btrfs_commit_transaction_async(struct btrfs_trans_handle *trans);
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans); int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans);
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans); bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans);
void btrfs_throttle(struct btrfs_fs_info *fs_info); void btrfs_throttle(struct btrfs_fs_info *fs_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment