diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-06-25 16:01:31 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:03 -0400 |
commit | 89ce8a63d0c761fbb02089850605360f389477d8 (patch) | |
tree | a509b1daf6e41f7768eaf49235c573690f12ef9b /fs/btrfs/transaction.c | |
parent | 333db94cdde9e6dfdedab9290d04d812f83e0922 (diff) |
Add btrfs_end_transaction_throttle to force writers to wait for pending commits
The existing throttle mechanism was often not sufficient to prevent
new writers from coming in and making a given transaction run forever.
This adds an explicit wait at the end of most operations so they will
allow the current transaction to close.
There is no wait inside file_write, inode updates, or cow filling, all which
have different deadlock possibilities.
This is a temporary measure until better asynchronous commit support is
added. This code leads to stalls as it waits for data=ordered
writeback, and it really needs to be fixed.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 5a1ee0665ae8..69ed5f85a387 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -130,8 +130,27 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
130 | return h; | 130 | return h; |
131 | } | 131 | } |
132 | 132 | ||
133 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 133 | static noinline int wait_for_commit(struct btrfs_root *root, |
134 | struct btrfs_root *root) | 134 | struct btrfs_transaction *commit) |
135 | { | ||
136 | DEFINE_WAIT(wait); | ||
137 | mutex_lock(&root->fs_info->trans_mutex); | ||
138 | while(!commit->commit_done) { | ||
139 | prepare_to_wait(&commit->commit_wait, &wait, | ||
140 | TASK_UNINTERRUPTIBLE); | ||
141 | if (commit->commit_done) | ||
142 | break; | ||
143 | mutex_unlock(&root->fs_info->trans_mutex); | ||
144 | schedule(); | ||
145 | mutex_lock(&root->fs_info->trans_mutex); | ||
146 | } | ||
147 | mutex_unlock(&root->fs_info->trans_mutex); | ||
148 | finish_wait(&commit->commit_wait, &wait); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||
153 | struct btrfs_root *root, int throttle) | ||
135 | { | 154 | { |
136 | struct btrfs_transaction *cur_trans; | 155 | struct btrfs_transaction *cur_trans; |
137 | 156 | ||
@@ -140,8 +159,18 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
140 | WARN_ON(cur_trans != trans->transaction); | 159 | WARN_ON(cur_trans != trans->transaction); |
141 | WARN_ON(cur_trans->num_writers < 1); | 160 | WARN_ON(cur_trans->num_writers < 1); |
142 | cur_trans->num_writers--; | 161 | cur_trans->num_writers--; |
162 | |||
143 | if (waitqueue_active(&cur_trans->writer_wait)) | 163 | if (waitqueue_active(&cur_trans->writer_wait)) |
144 | wake_up(&cur_trans->writer_wait); | 164 | wake_up(&cur_trans->writer_wait); |
165 | |||
166 | if (cur_trans->in_commit && throttle) { | ||
167 | int ret; | ||
168 | mutex_unlock(&root->fs_info->trans_mutex); | ||
169 | ret = wait_for_commit(root, cur_trans); | ||
170 | BUG_ON(ret); | ||
171 | mutex_lock(&root->fs_info->trans_mutex); | ||
172 | } | ||
173 | |||
145 | put_transaction(cur_trans); | 174 | put_transaction(cur_trans); |
146 | mutex_unlock(&root->fs_info->trans_mutex); | 175 | mutex_unlock(&root->fs_info->trans_mutex); |
147 | memset(trans, 0, sizeof(*trans)); | 176 | memset(trans, 0, sizeof(*trans)); |
@@ -149,6 +178,18 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
149 | return 0; | 178 | return 0; |
150 | } | 179 | } |
151 | 180 | ||
181 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||
182 | struct btrfs_root *root) | ||
183 | { | ||
184 | return __btrfs_end_transaction(trans, root, 0); | ||
185 | } | ||
186 | |||
187 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | ||
188 | struct btrfs_root *root) | ||
189 | { | ||
190 | return __btrfs_end_transaction(trans, root, 1); | ||
191 | } | ||
192 | |||
152 | 193 | ||
153 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | 194 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, |
154 | struct btrfs_root *root) | 195 | struct btrfs_root *root) |
@@ -240,25 +281,6 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |||
240 | return 0; | 281 | return 0; |
241 | } | 282 | } |
242 | 283 | ||
243 | static noinline int wait_for_commit(struct btrfs_root *root, | ||
244 | struct btrfs_transaction *commit) | ||
245 | { | ||
246 | DEFINE_WAIT(wait); | ||
247 | mutex_lock(&root->fs_info->trans_mutex); | ||
248 | while(!commit->commit_done) { | ||
249 | prepare_to_wait(&commit->commit_wait, &wait, | ||
250 | TASK_UNINTERRUPTIBLE); | ||
251 | if (commit->commit_done) | ||
252 | break; | ||
253 | mutex_unlock(&root->fs_info->trans_mutex); | ||
254 | schedule(); | ||
255 | mutex_lock(&root->fs_info->trans_mutex); | ||
256 | } | ||
257 | mutex_unlock(&root->fs_info->trans_mutex); | ||
258 | finish_wait(&commit->commit_wait, &wait); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | struct dirty_root { | 284 | struct dirty_root { |
263 | struct list_head list; | 285 | struct list_head list; |
264 | struct btrfs_root *root; | 286 | struct btrfs_root *root; |
@@ -680,6 +702,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
680 | root->fs_info->btree_inode->i_mapping, GFP_NOFS); | 702 | root->fs_info->btree_inode->i_mapping, GFP_NOFS); |
681 | 703 | ||
682 | trans->transaction->in_commit = 1; | 704 | trans->transaction->in_commit = 1; |
705 | printk("trans %Lu in commit\n", trans->transid); | ||
683 | cur_trans = trans->transaction; | 706 | cur_trans = trans->transaction; |
684 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | 707 | if (cur_trans->list.prev != &root->fs_info->trans_list) { |
685 | prev_trans = list_entry(cur_trans->list.prev, | 708 | prev_trans = list_entry(cur_trans->list.prev, |
@@ -760,6 +783,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
760 | kfree(pinned_copy); | 783 | kfree(pinned_copy); |
761 | 784 | ||
762 | cur_trans->commit_done = 1; | 785 | cur_trans->commit_done = 1; |
786 | printk("trans %Lu done in commit\n", cur_trans->transid); | ||
763 | root->fs_info->last_trans_committed = cur_trans->transid; | 787 | root->fs_info->last_trans_committed = cur_trans->transid; |
764 | wake_up(&cur_trans->commit_wait); | 788 | wake_up(&cur_trans->commit_wait); |
765 | put_transaction(cur_trans); | 789 | put_transaction(cur_trans); |