diff options
author | Sage Weil <sage@newdream.net> | 2008-08-04 10:41:27 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:06 -0400 |
commit | 9ca9ee09c176a814189063c8b88f75c8f8e4ad19 (patch) | |
tree | 3092ed3f5dd472e66a61da9306dfa6839604c42c /fs/btrfs/ioctl.c | |
parent | 3117a77370b6cb902191568e4e647cdcba083d0a (diff) |
Btrfs: fix ioctl-initiated transactions vs wait_current_trans()
Commit 597:466b27332893 (btrfs_start_transaction: wait for commits in
progress) breaks the transaction start/stop ioctls by making
btrfs_start_transaction conditionally wait for the next transaction to
start. If an application artificially is holding a transaction open,
things deadlock.
This workaround maintains a count of open ioctl-initiated transactions in
fs_info, and avoids wait_current_trans() if any are currently open (in
start_transaction() and btrfs_throttle()). The start transaction ioctl
uses a new btrfs_start_ioctl_transaction() that _does_ call
wait_current_trans(), effectively pushing the join/wait decision to the
outer ioctl-initiated transaction.
This more or less neuters btrfs_throttle() when ioctl-initiated
transactions are in use, but that seems like a pretty fundamental
consequence of wrapping lots of write()'s in a transaction. Btrfs has no
way to tell if the application considers a given operation as part of it's
transaction.
Obviously, if the transaction start/stop ioctls aren't being used, there
is no effect on current behavior.
Signed-off-by: Sage Weil <sage@newdream.net>
---
ctree.h | 1 +
ioctl.c | 12 +++++++++++-
transaction.c | 18 +++++++++++++-----
transaction.h | 2 ++
4 files changed, 27 insertions(+), 6 deletions(-)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 224da287b3ed..0b63c3c77cfd 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -715,7 +715,12 @@ long btrfs_ioctl_trans_start(struct file *file) | |||
715 | ret = -EINPROGRESS; | 715 | ret = -EINPROGRESS; |
716 | goto out; | 716 | goto out; |
717 | } | 717 | } |
718 | trans = btrfs_start_transaction(root, 0); | 718 | |
719 | mutex_lock(&root->fs_info->trans_mutex); | ||
720 | root->fs_info->open_ioctl_trans++; | ||
721 | mutex_unlock(&root->fs_info->trans_mutex); | ||
722 | |||
723 | trans = btrfs_start_ioctl_transaction(root, 0); | ||
719 | if (trans) | 724 | if (trans) |
720 | file->private_data = trans; | 725 | file->private_data = trans; |
721 | else | 726 | else |
@@ -745,6 +750,11 @@ long btrfs_ioctl_trans_end(struct file *file) | |||
745 | } | 750 | } |
746 | btrfs_end_transaction(trans, root); | 751 | btrfs_end_transaction(trans, root); |
747 | file->private_data = 0; | 752 | file->private_data = 0; |
753 | |||
754 | mutex_lock(&root->fs_info->trans_mutex); | ||
755 | root->fs_info->open_ioctl_trans--; | ||
756 | mutex_unlock(&root->fs_info->trans_mutex); | ||
757 | |||
748 | out: | 758 | out: |
749 | return ret; | 759 | return ret; |
750 | } | 760 | } |