@@ -3629,9 +3629,9 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info,
static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
void __user *argp)
{
+ struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_trans_handle *trans;
u64 transid;
- int ret;
trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) {
@@ -3639,15 +3639,13 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
return PTR_ERR(trans);
/* No running transaction, don't bother */
- transid = root->fs_info->last_trans_committed;
+ transid = fs_info->last_trans_committed;
goto out;
}
transid = trans->transid;
- ret = btrfs_commit_transaction_async(trans);
- if (ret) {
- btrfs_end_transaction(trans);
- return ret;
- }
+ /* Trigger commit via the pending action */
+ btrfs_set_pending(fs_info, COMMIT);
+ wake_up_process(fs_info->transaction_kthread);
out:
if (argp)
if (copy_to_user(argp, &transid, sizeof(transid)))
@@ -1870,80 +1870,6 @@ 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)
-{
- 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;
- }
-
- /* take transaction reference */
- cur_trans = trans->transaction;
- refcount_inc(&cur_trans->use_count);
-
- 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
- */
- 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;
@@ -226,7 +226,6 @@ 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);
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);
Note: this is a semantic change of what the async transaction ioctl does. This used to be utilized by ceph, together with the now removed user transaction ioctls. Last external code that can be found using this ioctl is a test in ceph testsuite. As btrfs and ceph have taken independent routes, we don't need to keep the code around. The btrfs-progs use the start and wait transaction ioctls in a simpler way, that does not require to block new transaction on the start. The new semantics is to eventually get transaction id of the running transaction if there is anything pending for a commit. The wait for transaction ioctl will block until it's finished. If there's nothing to be done since start, wait will return immediately. This effectively implements "wait for current transaction, if any". Any action started before the start, like deleting a subvolume, may take long time to finish. In case it's fast enough to finish before the start, the following wait will also finish immediately. A long running operation will catch the transaction and block at wait call until it's done. Both cases are expected and shall be the new semantics. This is implemented by the pending action infrastructure, that allows to asynchronously and safely request a commit by just setting a bit and waking the transaction kthread. This is different, because originally start would block, but now it returns immediately. However, the new behaviour still corresponds with the documentation of libbtrfsutil so this should not cause any surprises. This also simplifies a few transaction commit things: - another quirky freezing protection removed - fs_info::transaction_blocked_wait is now never populated, so it's a no-op and can be simplified as well - one less current->journal_info usage, that's been problematic in some cases Signed-off-by: David Sterba <dsterba@suse.com> --- fs/btrfs/ioctl.c | 12 +++---- fs/btrfs/transaction.c | 74 ------------------------------------------ fs/btrfs/transaction.h | 1 - 3 files changed, 5 insertions(+), 82 deletions(-)