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: Josef Bacik <josef@toxicpanda.com> [ add note ] Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Родитель
0af4769da6
Коммит
fdfbf02066
|
@ -595,6 +595,9 @@ enum {
|
|||
/* Indicate whether there are any tree modification 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
|
||||
/* Indicate if we have error/warn message printed on 32bit systems */
|
||||
BTRFS_FS_32BIT_ERROR,
|
||||
|
|
|
@ -1934,7 +1934,8 @@ static int transaction_kthread(void *arg)
|
|||
}
|
||||
|
||||
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) {
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
delay -= msecs_to_jiffies((delta - 1) * 1000);
|
||||
|
|
|
@ -3622,7 +3622,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
|
|||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
u64 transid;
|
||||
int ret;
|
||||
|
||||
trans = btrfs_attach_transaction_barrier(root);
|
||||
if (IS_ERR(trans)) {
|
||||
|
@ -3634,11 +3633,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
|
|||
goto out;
|
||||
}
|
||||
transid = trans->transid;
|
||||
ret = btrfs_commit_transaction_async(trans);
|
||||
if (ret) {
|
||||
btrfs_end_transaction(trans);
|
||||
return ret;
|
||||
}
|
||||
btrfs_commit_transaction_async(trans);
|
||||
out:
|
||||
if (argp)
|
||||
if (copy_to_user(argp, &transid, sizeof(transid)))
|
||||
|
|
|
@ -1880,50 +1880,14 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
void btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_async_commit *ac;
|
||||
struct btrfs_transaction *cur_trans;
|
||||
|
||||
ac = kmalloc(sizeof(*ac), GFP_NOFS);
|
||||
if (!ac)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
}
|
||||
/* Kick the transaction kthread. */
|
||||
set_bit(BTRFS_FS_COMMIT_TRANS, &fs_info->flags);
|
||||
wake_up_process(fs_info->transaction_kthread);
|
||||
|
||||
/* take transaction reference */
|
||||
cur_trans = trans->transaction;
|
||||
|
@ -1931,14 +1895,6 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *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
|
||||
* subsequent transaction joins
|
||||
|
@ -1946,14 +1902,9 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
|
|||
wait_event(fs_info->transaction_blocked_wait,
|
||||
cur_trans->state >= TRANS_STATE_COMMIT_START ||
|
||||
TRANS_ABORTED(cur_trans));
|
||||
if (current->journal_info == trans)
|
||||
current->journal_info = NULL;
|
||||
|
||||
btrfs_put_transaction(cur_trans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
|
@ -2219,6 +2170,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
|
|||
wait_event(cur_trans->writer_wait,
|
||||
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)) {
|
||||
ret = cur_trans->aborted;
|
||||
goto scrub_continue;
|
||||
|
|
|
@ -217,7 +217,7 @@ void btrfs_add_dead_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_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);
|
||||
bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans);
|
||||
void btrfs_throttle(struct btrfs_fs_info *fs_info);
|
||||
|
|
Загрузка…
Ссылка в новой задаче