diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 234 |
1 files changed, 210 insertions, 24 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 66e4c66cc63b..1fffbc017bdf 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -163,6 +163,7 @@ enum btrfs_trans_type { | |||
163 | TRANS_START, | 163 | TRANS_START, |
164 | TRANS_JOIN, | 164 | TRANS_JOIN, |
165 | TRANS_USERSPACE, | 165 | TRANS_USERSPACE, |
166 | TRANS_JOIN_NOLOCK, | ||
166 | }; | 167 | }; |
167 | 168 | ||
168 | static int may_wait_transaction(struct btrfs_root *root, int type) | 169 | static int may_wait_transaction(struct btrfs_root *root, int type) |
@@ -179,14 +180,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
179 | { | 180 | { |
180 | struct btrfs_trans_handle *h; | 181 | struct btrfs_trans_handle *h; |
181 | struct btrfs_transaction *cur_trans; | 182 | struct btrfs_transaction *cur_trans; |
182 | int retries = 0; | ||
183 | int ret; | 183 | int ret; |
184 | again: | 184 | again: |
185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
186 | if (!h) | 186 | if (!h) |
187 | return ERR_PTR(-ENOMEM); | 187 | return ERR_PTR(-ENOMEM); |
188 | 188 | ||
189 | mutex_lock(&root->fs_info->trans_mutex); | 189 | if (type != TRANS_JOIN_NOLOCK) |
190 | mutex_lock(&root->fs_info->trans_mutex); | ||
190 | if (may_wait_transaction(root, type)) | 191 | if (may_wait_transaction(root, type)) |
191 | wait_current_trans(root); | 192 | wait_current_trans(root); |
192 | 193 | ||
@@ -195,7 +196,8 @@ again: | |||
195 | 196 | ||
196 | cur_trans = root->fs_info->running_transaction; | 197 | cur_trans = root->fs_info->running_transaction; |
197 | cur_trans->use_count++; | 198 | cur_trans->use_count++; |
198 | mutex_unlock(&root->fs_info->trans_mutex); | 199 | if (type != TRANS_JOIN_NOLOCK) |
200 | mutex_unlock(&root->fs_info->trans_mutex); | ||
199 | 201 | ||
200 | h->transid = cur_trans->transid; | 202 | h->transid = cur_trans->transid; |
201 | h->transaction = cur_trans; | 203 | h->transaction = cur_trans; |
@@ -212,8 +214,7 @@ again: | |||
212 | } | 214 | } |
213 | 215 | ||
214 | if (num_items > 0) { | 216 | if (num_items > 0) { |
215 | ret = btrfs_trans_reserve_metadata(h, root, num_items, | 217 | ret = btrfs_trans_reserve_metadata(h, root, num_items); |
216 | &retries); | ||
217 | if (ret == -EAGAIN) { | 218 | if (ret == -EAGAIN) { |
218 | btrfs_commit_transaction(h, root); | 219 | btrfs_commit_transaction(h, root); |
219 | goto again; | 220 | goto again; |
@@ -224,9 +225,11 @@ again: | |||
224 | } | 225 | } |
225 | } | 226 | } |
226 | 227 | ||
227 | mutex_lock(&root->fs_info->trans_mutex); | 228 | if (type != TRANS_JOIN_NOLOCK) |
229 | mutex_lock(&root->fs_info->trans_mutex); | ||
228 | record_root_in_trans(h, root); | 230 | record_root_in_trans(h, root); |
229 | mutex_unlock(&root->fs_info->trans_mutex); | 231 | if (type != TRANS_JOIN_NOLOCK) |
232 | mutex_unlock(&root->fs_info->trans_mutex); | ||
230 | 233 | ||
231 | if (!current->journal_info && type != TRANS_USERSPACE) | 234 | if (!current->journal_info && type != TRANS_USERSPACE) |
232 | current->journal_info = h; | 235 | current->journal_info = h; |
@@ -244,6 +247,12 @@ struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, | |||
244 | return start_transaction(root, 0, TRANS_JOIN); | 247 | return start_transaction(root, 0, TRANS_JOIN); |
245 | } | 248 | } |
246 | 249 | ||
250 | struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root, | ||
251 | int num_blocks) | ||
252 | { | ||
253 | return start_transaction(root, 0, TRANS_JOIN_NOLOCK); | ||
254 | } | ||
255 | |||
247 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, | 256 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, |
248 | int num_blocks) | 257 | int num_blocks) |
249 | { | 258 | { |
@@ -270,6 +279,58 @@ static noinline int wait_for_commit(struct btrfs_root *root, | |||
270 | return 0; | 279 | return 0; |
271 | } | 280 | } |
272 | 281 | ||
282 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | ||
283 | { | ||
284 | struct btrfs_transaction *cur_trans = NULL, *t; | ||
285 | int ret; | ||
286 | |||
287 | mutex_lock(&root->fs_info->trans_mutex); | ||
288 | |||
289 | ret = 0; | ||
290 | if (transid) { | ||
291 | if (transid <= root->fs_info->last_trans_committed) | ||
292 | goto out_unlock; | ||
293 | |||
294 | /* find specified transaction */ | ||
295 | list_for_each_entry(t, &root->fs_info->trans_list, list) { | ||
296 | if (t->transid == transid) { | ||
297 | cur_trans = t; | ||
298 | break; | ||
299 | } | ||
300 | if (t->transid > transid) | ||
301 | break; | ||
302 | } | ||
303 | ret = -EINVAL; | ||
304 | if (!cur_trans) | ||
305 | goto out_unlock; /* bad transid */ | ||
306 | } else { | ||
307 | /* find newest transaction that is committing | committed */ | ||
308 | list_for_each_entry_reverse(t, &root->fs_info->trans_list, | ||
309 | list) { | ||
310 | if (t->in_commit) { | ||
311 | if (t->commit_done) | ||
312 | goto out_unlock; | ||
313 | cur_trans = t; | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | if (!cur_trans) | ||
318 | goto out_unlock; /* nothing committing|committed */ | ||
319 | } | ||
320 | |||
321 | cur_trans->use_count++; | ||
322 | mutex_unlock(&root->fs_info->trans_mutex); | ||
323 | |||
324 | wait_for_commit(root, cur_trans); | ||
325 | |||
326 | mutex_lock(&root->fs_info->trans_mutex); | ||
327 | put_transaction(cur_trans); | ||
328 | ret = 0; | ||
329 | out_unlock: | ||
330 | mutex_unlock(&root->fs_info->trans_mutex); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
273 | #if 0 | 334 | #if 0 |
274 | /* | 335 | /* |
275 | * rate limit against the drop_snapshot code. This helps to slow down new | 336 | * rate limit against the drop_snapshot code. This helps to slow down new |
@@ -348,7 +409,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
348 | } | 409 | } |
349 | 410 | ||
350 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | 411 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, |
351 | struct btrfs_root *root, int throttle) | 412 | struct btrfs_root *root, int throttle, int lock) |
352 | { | 413 | { |
353 | struct btrfs_transaction *cur_trans = trans->transaction; | 414 | struct btrfs_transaction *cur_trans = trans->transaction; |
354 | struct btrfs_fs_info *info = root->fs_info; | 415 | struct btrfs_fs_info *info = root->fs_info; |
@@ -376,26 +437,29 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
376 | 437 | ||
377 | btrfs_trans_release_metadata(trans, root); | 438 | btrfs_trans_release_metadata(trans, root); |
378 | 439 | ||
379 | if (!root->fs_info->open_ioctl_trans && | 440 | if (lock && !root->fs_info->open_ioctl_trans && |
380 | should_end_transaction(trans, root)) | 441 | should_end_transaction(trans, root)) |
381 | trans->transaction->blocked = 1; | 442 | trans->transaction->blocked = 1; |
382 | 443 | ||
383 | if (cur_trans->blocked && !cur_trans->in_commit) { | 444 | if (lock && cur_trans->blocked && !cur_trans->in_commit) { |
384 | if (throttle) | 445 | if (throttle) |
385 | return btrfs_commit_transaction(trans, root); | 446 | return btrfs_commit_transaction(trans, root); |
386 | else | 447 | else |
387 | wake_up_process(info->transaction_kthread); | 448 | wake_up_process(info->transaction_kthread); |
388 | } | 449 | } |
389 | 450 | ||
390 | mutex_lock(&info->trans_mutex); | 451 | if (lock) |
452 | mutex_lock(&info->trans_mutex); | ||
391 | WARN_ON(cur_trans != info->running_transaction); | 453 | WARN_ON(cur_trans != info->running_transaction); |
392 | WARN_ON(cur_trans->num_writers < 1); | 454 | WARN_ON(cur_trans->num_writers < 1); |
393 | cur_trans->num_writers--; | 455 | cur_trans->num_writers--; |
394 | 456 | ||
457 | smp_mb(); | ||
395 | if (waitqueue_active(&cur_trans->writer_wait)) | 458 | if (waitqueue_active(&cur_trans->writer_wait)) |
396 | wake_up(&cur_trans->writer_wait); | 459 | wake_up(&cur_trans->writer_wait); |
397 | put_transaction(cur_trans); | 460 | put_transaction(cur_trans); |
398 | mutex_unlock(&info->trans_mutex); | 461 | if (lock) |
462 | mutex_unlock(&info->trans_mutex); | ||
399 | 463 | ||
400 | if (current->journal_info == trans) | 464 | if (current->journal_info == trans) |
401 | current->journal_info = NULL; | 465 | current->journal_info = NULL; |
@@ -411,13 +475,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
411 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 475 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, |
412 | struct btrfs_root *root) | 476 | struct btrfs_root *root) |
413 | { | 477 | { |
414 | return __btrfs_end_transaction(trans, root, 0); | 478 | return __btrfs_end_transaction(trans, root, 0, 1); |
415 | } | 479 | } |
416 | 480 | ||
417 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | 481 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, |
418 | struct btrfs_root *root) | 482 | struct btrfs_root *root) |
419 | { | 483 | { |
420 | return __btrfs_end_transaction(trans, root, 1); | 484 | return __btrfs_end_transaction(trans, root, 1, 1); |
485 | } | ||
486 | |||
487 | int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans, | ||
488 | struct btrfs_root *root) | ||
489 | { | ||
490 | return __btrfs_end_transaction(trans, root, 0, 0); | ||
421 | } | 491 | } |
422 | 492 | ||
423 | /* | 493 | /* |
@@ -836,7 +906,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
836 | struct extent_buffer *tmp; | 906 | struct extent_buffer *tmp; |
837 | struct extent_buffer *old; | 907 | struct extent_buffer *old; |
838 | int ret; | 908 | int ret; |
839 | int retries = 0; | ||
840 | u64 to_reserve = 0; | 909 | u64 to_reserve = 0; |
841 | u64 index = 0; | 910 | u64 index = 0; |
842 | u64 objectid; | 911 | u64 objectid; |
@@ -858,7 +927,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
858 | 927 | ||
859 | if (to_reserve > 0) { | 928 | if (to_reserve > 0) { |
860 | ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, | 929 | ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, |
861 | to_reserve, &retries); | 930 | to_reserve); |
862 | if (ret) { | 931 | if (ret) { |
863 | pending->error = ret; | 932 | pending->error = ret; |
864 | goto fail; | 933 | goto fail; |
@@ -966,6 +1035,8 @@ static void update_super_roots(struct btrfs_root *root) | |||
966 | super->root = root_item->bytenr; | 1035 | super->root = root_item->bytenr; |
967 | super->generation = root_item->generation; | 1036 | super->generation = root_item->generation; |
968 | super->root_level = root_item->level; | 1037 | super->root_level = root_item->level; |
1038 | if (super->cache_generation != 0 || btrfs_test_opt(root, SPACE_CACHE)) | ||
1039 | super->cache_generation = root_item->generation; | ||
969 | } | 1040 | } |
970 | 1041 | ||
971 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | 1042 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) |
@@ -988,11 +1059,127 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) | |||
988 | return ret; | 1059 | return ret; |
989 | } | 1060 | } |
990 | 1061 | ||
1062 | /* | ||
1063 | * wait for the current transaction commit to start and block subsequent | ||
1064 | * transaction joins | ||
1065 | */ | ||
1066 | static void wait_current_trans_commit_start(struct btrfs_root *root, | ||
1067 | struct btrfs_transaction *trans) | ||
1068 | { | ||
1069 | DEFINE_WAIT(wait); | ||
1070 | |||
1071 | if (trans->in_commit) | ||
1072 | return; | ||
1073 | |||
1074 | while (1) { | ||
1075 | prepare_to_wait(&root->fs_info->transaction_blocked_wait, &wait, | ||
1076 | TASK_UNINTERRUPTIBLE); | ||
1077 | if (trans->in_commit) { | ||
1078 | finish_wait(&root->fs_info->transaction_blocked_wait, | ||
1079 | &wait); | ||
1080 | break; | ||
1081 | } | ||
1082 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1083 | schedule(); | ||
1084 | mutex_lock(&root->fs_info->trans_mutex); | ||
1085 | finish_wait(&root->fs_info->transaction_blocked_wait, &wait); | ||
1086 | } | ||
1087 | } | ||
1088 | |||
1089 | /* | ||
1090 | * wait for the current transaction to start and then become unblocked. | ||
1091 | * caller holds ref. | ||
1092 | */ | ||
1093 | static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, | ||
1094 | struct btrfs_transaction *trans) | ||
1095 | { | ||
1096 | DEFINE_WAIT(wait); | ||
1097 | |||
1098 | if (trans->commit_done || (trans->in_commit && !trans->blocked)) | ||
1099 | return; | ||
1100 | |||
1101 | while (1) { | ||
1102 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | ||
1103 | TASK_UNINTERRUPTIBLE); | ||
1104 | if (trans->commit_done || | ||
1105 | (trans->in_commit && !trans->blocked)) { | ||
1106 | finish_wait(&root->fs_info->transaction_wait, | ||
1107 | &wait); | ||
1108 | break; | ||
1109 | } | ||
1110 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1111 | schedule(); | ||
1112 | mutex_lock(&root->fs_info->trans_mutex); | ||
1113 | finish_wait(&root->fs_info->transaction_wait, | ||
1114 | &wait); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | * commit transactions asynchronously. once btrfs_commit_transaction_async | ||
1120 | * returns, any subsequent transaction will not be allowed to join. | ||
1121 | */ | ||
1122 | struct btrfs_async_commit { | ||
1123 | struct btrfs_trans_handle *newtrans; | ||
1124 | struct btrfs_root *root; | ||
1125 | struct delayed_work work; | ||
1126 | }; | ||
1127 | |||
1128 | static void do_async_commit(struct work_struct *work) | ||
1129 | { | ||
1130 | struct btrfs_async_commit *ac = | ||
1131 | container_of(work, struct btrfs_async_commit, work.work); | ||
1132 | |||
1133 | btrfs_commit_transaction(ac->newtrans, ac->root); | ||
1134 | kfree(ac); | ||
1135 | } | ||
1136 | |||
1137 | int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | ||
1138 | struct btrfs_root *root, | ||
1139 | int wait_for_unblock) | ||
1140 | { | ||
1141 | struct btrfs_async_commit *ac; | ||
1142 | struct btrfs_transaction *cur_trans; | ||
1143 | |||
1144 | ac = kmalloc(sizeof(*ac), GFP_NOFS); | ||
1145 | BUG_ON(!ac); | ||
1146 | |||
1147 | INIT_DELAYED_WORK(&ac->work, do_async_commit); | ||
1148 | ac->root = root; | ||
1149 | ac->newtrans = btrfs_join_transaction(root, 0); | ||
1150 | |||
1151 | /* take transaction reference */ | ||
1152 | mutex_lock(&root->fs_info->trans_mutex); | ||
1153 | cur_trans = trans->transaction; | ||
1154 | cur_trans->use_count++; | ||
1155 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1156 | |||
1157 | btrfs_end_transaction(trans, root); | ||
1158 | schedule_delayed_work(&ac->work, 0); | ||
1159 | |||
1160 | /* wait for transaction to start and unblock */ | ||
1161 | mutex_lock(&root->fs_info->trans_mutex); | ||
1162 | if (wait_for_unblock) | ||
1163 | wait_current_trans_commit_start_and_unblock(root, cur_trans); | ||
1164 | else | ||
1165 | wait_current_trans_commit_start(root, cur_trans); | ||
1166 | put_transaction(cur_trans); | ||
1167 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | /* | ||
1173 | * btrfs_transaction state sequence: | ||
1174 | * in_commit = 0, blocked = 0 (initial) | ||
1175 | * in_commit = 1, blocked = 1 | ||
1176 | * blocked = 0 | ||
1177 | * commit_done = 1 | ||
1178 | */ | ||
991 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 1179 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
992 | struct btrfs_root *root) | 1180 | struct btrfs_root *root) |
993 | { | 1181 | { |
994 | unsigned long joined = 0; | 1182 | unsigned long joined = 0; |
995 | unsigned long timeout = 1; | ||
996 | struct btrfs_transaction *cur_trans; | 1183 | struct btrfs_transaction *cur_trans; |
997 | struct btrfs_transaction *prev_trans = NULL; | 1184 | struct btrfs_transaction *prev_trans = NULL; |
998 | DEFINE_WAIT(wait); | 1185 | DEFINE_WAIT(wait); |
@@ -1039,6 +1226,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1039 | 1226 | ||
1040 | trans->transaction->in_commit = 1; | 1227 | trans->transaction->in_commit = 1; |
1041 | trans->transaction->blocked = 1; | 1228 | trans->transaction->blocked = 1; |
1229 | wake_up(&root->fs_info->transaction_blocked_wait); | ||
1230 | |||
1042 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | 1231 | if (cur_trans->list.prev != &root->fs_info->trans_list) { |
1043 | prev_trans = list_entry(cur_trans->list.prev, | 1232 | prev_trans = list_entry(cur_trans->list.prev, |
1044 | struct btrfs_transaction, list); | 1233 | struct btrfs_transaction, list); |
@@ -1063,11 +1252,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1063 | snap_pending = 1; | 1252 | snap_pending = 1; |
1064 | 1253 | ||
1065 | WARN_ON(cur_trans != trans->transaction); | 1254 | WARN_ON(cur_trans != trans->transaction); |
1066 | if (cur_trans->num_writers > 1) | ||
1067 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
1068 | else if (should_grow) | ||
1069 | timeout = 1; | ||
1070 | |||
1071 | mutex_unlock(&root->fs_info->trans_mutex); | 1255 | mutex_unlock(&root->fs_info->trans_mutex); |
1072 | 1256 | ||
1073 | if (flush_on_commit || snap_pending) { | 1257 | if (flush_on_commit || snap_pending) { |
@@ -1089,8 +1273,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1089 | TASK_UNINTERRUPTIBLE); | 1273 | TASK_UNINTERRUPTIBLE); |
1090 | 1274 | ||
1091 | smp_mb(); | 1275 | smp_mb(); |
1092 | if (cur_trans->num_writers > 1 || should_grow) | 1276 | if (cur_trans->num_writers > 1) |
1093 | schedule_timeout(timeout); | 1277 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); |
1278 | else if (should_grow) | ||
1279 | schedule_timeout(1); | ||
1094 | 1280 | ||
1095 | mutex_lock(&root->fs_info->trans_mutex); | 1281 | mutex_lock(&root->fs_info->trans_mutex); |
1096 | finish_wait(&cur_trans->writer_wait, &wait); | 1282 | finish_wait(&cur_trans->writer_wait, &wait); |