diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 116 |
1 files changed, 39 insertions, 77 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 51dcec86757..e24b7964a15 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -216,17 +216,11 @@ static void wait_current_trans(struct btrfs_root *root) | |||
216 | spin_lock(&root->fs_info->trans_lock); | 216 | spin_lock(&root->fs_info->trans_lock); |
217 | cur_trans = root->fs_info->running_transaction; | 217 | cur_trans = root->fs_info->running_transaction; |
218 | if (cur_trans && cur_trans->blocked) { | 218 | if (cur_trans && cur_trans->blocked) { |
219 | DEFINE_WAIT(wait); | ||
220 | atomic_inc(&cur_trans->use_count); | 219 | atomic_inc(&cur_trans->use_count); |
221 | spin_unlock(&root->fs_info->trans_lock); | 220 | spin_unlock(&root->fs_info->trans_lock); |
222 | while (1) { | 221 | |
223 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 222 | wait_event(root->fs_info->transaction_wait, |
224 | TASK_UNINTERRUPTIBLE); | 223 | !cur_trans->blocked); |
225 | if (!cur_trans->blocked) | ||
226 | break; | ||
227 | schedule(); | ||
228 | } | ||
229 | finish_wait(&root->fs_info->transaction_wait, &wait); | ||
230 | put_transaction(cur_trans); | 224 | put_transaction(cur_trans); |
231 | } else { | 225 | } else { |
232 | spin_unlock(&root->fs_info->trans_lock); | 226 | spin_unlock(&root->fs_info->trans_lock); |
@@ -260,7 +254,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
260 | { | 254 | { |
261 | struct btrfs_trans_handle *h; | 255 | struct btrfs_trans_handle *h; |
262 | struct btrfs_transaction *cur_trans; | 256 | struct btrfs_transaction *cur_trans; |
263 | int retries = 0; | 257 | u64 num_bytes = 0; |
264 | int ret; | 258 | int ret; |
265 | 259 | ||
266 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) | 260 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) |
@@ -274,6 +268,19 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
274 | h->block_rsv = NULL; | 268 | h->block_rsv = NULL; |
275 | goto got_it; | 269 | goto got_it; |
276 | } | 270 | } |
271 | |||
272 | /* | ||
273 | * Do the reservation before we join the transaction so we can do all | ||
274 | * the appropriate flushing if need be. | ||
275 | */ | ||
276 | if (num_items > 0 && root != root->fs_info->chunk_root) { | ||
277 | num_bytes = btrfs_calc_trans_metadata_size(root, num_items); | ||
278 | ret = btrfs_block_rsv_add(NULL, root, | ||
279 | &root->fs_info->trans_block_rsv, | ||
280 | num_bytes); | ||
281 | if (ret) | ||
282 | return ERR_PTR(ret); | ||
283 | } | ||
277 | again: | 284 | again: |
278 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 285 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
279 | if (!h) | 286 | if (!h) |
@@ -310,24 +317,9 @@ again: | |||
310 | goto again; | 317 | goto again; |
311 | } | 318 | } |
312 | 319 | ||
313 | if (num_items > 0) { | 320 | if (num_bytes) { |
314 | ret = btrfs_trans_reserve_metadata(h, root, num_items); | 321 | h->block_rsv = &root->fs_info->trans_block_rsv; |
315 | if (ret == -EAGAIN && !retries) { | 322 | h->bytes_reserved = num_bytes; |
316 | retries++; | ||
317 | btrfs_commit_transaction(h, root); | ||
318 | goto again; | ||
319 | } else if (ret == -EAGAIN) { | ||
320 | /* | ||
321 | * We have already retried and got EAGAIN, so really we | ||
322 | * don't have space, so set ret to -ENOSPC. | ||
323 | */ | ||
324 | ret = -ENOSPC; | ||
325 | } | ||
326 | |||
327 | if (ret < 0) { | ||
328 | btrfs_end_transaction(h, root); | ||
329 | return ERR_PTR(ret); | ||
330 | } | ||
331 | } | 323 | } |
332 | 324 | ||
333 | got_it: | 325 | got_it: |
@@ -359,19 +351,10 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root | |||
359 | } | 351 | } |
360 | 352 | ||
361 | /* wait for a transaction commit to be fully complete */ | 353 | /* wait for a transaction commit to be fully complete */ |
362 | static noinline int wait_for_commit(struct btrfs_root *root, | 354 | static noinline void wait_for_commit(struct btrfs_root *root, |
363 | struct btrfs_transaction *commit) | 355 | struct btrfs_transaction *commit) |
364 | { | 356 | { |
365 | DEFINE_WAIT(wait); | 357 | wait_event(commit->commit_wait, commit->commit_done); |
366 | while (!commit->commit_done) { | ||
367 | prepare_to_wait(&commit->commit_wait, &wait, | ||
368 | TASK_UNINTERRUPTIBLE); | ||
369 | if (commit->commit_done) | ||
370 | break; | ||
371 | schedule(); | ||
372 | } | ||
373 | finish_wait(&commit->commit_wait, &wait); | ||
374 | return 0; | ||
375 | } | 358 | } |
376 | 359 | ||
377 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | 360 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) |
@@ -499,10 +482,17 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
499 | } | 482 | } |
500 | 483 | ||
501 | if (lock && cur_trans->blocked && !cur_trans->in_commit) { | 484 | if (lock && cur_trans->blocked && !cur_trans->in_commit) { |
502 | if (throttle) | 485 | if (throttle) { |
486 | /* | ||
487 | * We may race with somebody else here so end up having | ||
488 | * to call end_transaction on ourselves again, so inc | ||
489 | * our use_count. | ||
490 | */ | ||
491 | trans->use_count++; | ||
503 | return btrfs_commit_transaction(trans, root); | 492 | return btrfs_commit_transaction(trans, root); |
504 | else | 493 | } else { |
505 | wake_up_process(info->transaction_kthread); | 494 | wake_up_process(info->transaction_kthread); |
495 | } | ||
506 | } | 496 | } |
507 | 497 | ||
508 | WARN_ON(cur_trans != info->running_transaction); | 498 | WARN_ON(cur_trans != info->running_transaction); |
@@ -894,6 +884,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
894 | struct btrfs_root *tree_root = fs_info->tree_root; | 884 | struct btrfs_root *tree_root = fs_info->tree_root; |
895 | struct btrfs_root *root = pending->root; | 885 | struct btrfs_root *root = pending->root; |
896 | struct btrfs_root *parent_root; | 886 | struct btrfs_root *parent_root; |
887 | struct btrfs_block_rsv *rsv; | ||
897 | struct inode *parent_inode; | 888 | struct inode *parent_inode; |
898 | struct dentry *parent; | 889 | struct dentry *parent; |
899 | struct dentry *dentry; | 890 | struct dentry *dentry; |
@@ -905,6 +896,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
905 | u64 objectid; | 896 | u64 objectid; |
906 | u64 root_flags; | 897 | u64 root_flags; |
907 | 898 | ||
899 | rsv = trans->block_rsv; | ||
900 | |||
908 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 901 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
909 | if (!new_root_item) { | 902 | if (!new_root_item) { |
910 | pending->error = -ENOMEM; | 903 | pending->error = -ENOMEM; |
@@ -1012,6 +1005,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1012 | btrfs_orphan_post_snapshot(trans, pending); | 1005 | btrfs_orphan_post_snapshot(trans, pending); |
1013 | fail: | 1006 | fail: |
1014 | kfree(new_root_item); | 1007 | kfree(new_root_item); |
1008 | trans->block_rsv = rsv; | ||
1015 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); | 1009 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); |
1016 | return 0; | 1010 | return 0; |
1017 | } | 1011 | } |
@@ -1080,22 +1074,7 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) | |||
1080 | static void wait_current_trans_commit_start(struct btrfs_root *root, | 1074 | static void wait_current_trans_commit_start(struct btrfs_root *root, |
1081 | struct btrfs_transaction *trans) | 1075 | struct btrfs_transaction *trans) |
1082 | { | 1076 | { |
1083 | DEFINE_WAIT(wait); | 1077 | wait_event(root->fs_info->transaction_blocked_wait, trans->in_commit); |
1084 | |||
1085 | if (trans->in_commit) | ||
1086 | return; | ||
1087 | |||
1088 | while (1) { | ||
1089 | prepare_to_wait(&root->fs_info->transaction_blocked_wait, &wait, | ||
1090 | TASK_UNINTERRUPTIBLE); | ||
1091 | if (trans->in_commit) { | ||
1092 | finish_wait(&root->fs_info->transaction_blocked_wait, | ||
1093 | &wait); | ||
1094 | break; | ||
1095 | } | ||
1096 | schedule(); | ||
1097 | finish_wait(&root->fs_info->transaction_blocked_wait, &wait); | ||
1098 | } | ||
1099 | } | 1078 | } |
1100 | 1079 | ||
1101 | /* | 1080 | /* |
@@ -1105,24 +1084,8 @@ static void wait_current_trans_commit_start(struct btrfs_root *root, | |||
1105 | static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, | 1084 | static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, |
1106 | struct btrfs_transaction *trans) | 1085 | struct btrfs_transaction *trans) |
1107 | { | 1086 | { |
1108 | DEFINE_WAIT(wait); | 1087 | wait_event(root->fs_info->transaction_wait, |
1109 | 1088 | trans->commit_done || (trans->in_commit && !trans->blocked)); | |
1110 | if (trans->commit_done || (trans->in_commit && !trans->blocked)) | ||
1111 | return; | ||
1112 | |||
1113 | while (1) { | ||
1114 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | ||
1115 | TASK_UNINTERRUPTIBLE); | ||
1116 | if (trans->commit_done || | ||
1117 | (trans->in_commit && !trans->blocked)) { | ||
1118 | finish_wait(&root->fs_info->transaction_wait, | ||
1119 | &wait); | ||
1120 | break; | ||
1121 | } | ||
1122 | schedule(); | ||
1123 | finish_wait(&root->fs_info->transaction_wait, | ||
1124 | &wait); | ||
1125 | } | ||
1126 | } | 1089 | } |
1127 | 1090 | ||
1128 | /* | 1091 | /* |
@@ -1229,8 +1192,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1229 | atomic_inc(&cur_trans->use_count); | 1192 | atomic_inc(&cur_trans->use_count); |
1230 | btrfs_end_transaction(trans, root); | 1193 | btrfs_end_transaction(trans, root); |
1231 | 1194 | ||
1232 | ret = wait_for_commit(root, cur_trans); | 1195 | wait_for_commit(root, cur_trans); |
1233 | BUG_ON(ret); | ||
1234 | 1196 | ||
1235 | put_transaction(cur_trans); | 1197 | put_transaction(cur_trans); |
1236 | 1198 | ||