diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 236 | 
1 files changed, 162 insertions, 74 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 39d83da03e03..e2f45fc02610 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -136,13 +136,20 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, | |||
| 136 | * syncing the tree wait for us to finish | 136 | * syncing the tree wait for us to finish | 
| 137 | */ | 137 | */ | 
| 138 | static int start_log_trans(struct btrfs_trans_handle *trans, | 138 | static int start_log_trans(struct btrfs_trans_handle *trans, | 
| 139 | struct btrfs_root *root) | 139 | struct btrfs_root *root, | 
| 140 | struct btrfs_log_ctx *ctx) | ||
| 140 | { | 141 | { | 
| 142 | int index; | ||
| 141 | int ret; | 143 | int ret; | 
| 142 | int err = 0; | ||
| 143 | 144 | ||
| 144 | mutex_lock(&root->log_mutex); | 145 | mutex_lock(&root->log_mutex); | 
| 145 | if (root->log_root) { | 146 | if (root->log_root) { | 
| 147 | if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == | ||
| 148 | trans->transid) { | ||
| 149 | ret = -EAGAIN; | ||
| 150 | goto out; | ||
| 151 | } | ||
| 152 | |||
| 146 | if (!root->log_start_pid) { | 153 | if (!root->log_start_pid) { | 
| 147 | root->log_start_pid = current->pid; | 154 | root->log_start_pid = current->pid; | 
| 148 | root->log_multiple_pids = false; | 155 | root->log_multiple_pids = false; | 
| @@ -152,27 +159,40 @@ static int start_log_trans(struct btrfs_trans_handle *trans, | |||
| 152 | 159 | ||
| 153 | atomic_inc(&root->log_batch); | 160 | atomic_inc(&root->log_batch); | 
| 154 | atomic_inc(&root->log_writers); | 161 | atomic_inc(&root->log_writers); | 
| 162 | if (ctx) { | ||
| 163 | index = root->log_transid % 2; | ||
| 164 | list_add_tail(&ctx->list, &root->log_ctxs[index]); | ||
| 165 | ctx->log_transid = root->log_transid; | ||
| 166 | } | ||
| 155 | mutex_unlock(&root->log_mutex); | 167 | mutex_unlock(&root->log_mutex); | 
| 156 | return 0; | 168 | return 0; | 
| 157 | } | 169 | } | 
| 158 | root->log_multiple_pids = false; | 170 | |
| 159 | root->log_start_pid = current->pid; | 171 | ret = 0; | 
| 160 | mutex_lock(&root->fs_info->tree_log_mutex); | 172 | mutex_lock(&root->fs_info->tree_log_mutex); | 
| 161 | if (!root->fs_info->log_root_tree) { | 173 | if (!root->fs_info->log_root_tree) | 
| 162 | ret = btrfs_init_log_root_tree(trans, root->fs_info); | 174 | ret = btrfs_init_log_root_tree(trans, root->fs_info); | 
| 163 | if (ret) | 175 | mutex_unlock(&root->fs_info->tree_log_mutex); | 
| 164 | err = ret; | 176 | if (ret) | 
| 165 | } | 177 | goto out; | 
| 166 | if (err == 0 && !root->log_root) { | 178 | |
| 179 | if (!root->log_root) { | ||
| 167 | ret = btrfs_add_log_tree(trans, root); | 180 | ret = btrfs_add_log_tree(trans, root); | 
| 168 | if (ret) | 181 | if (ret) | 
| 169 | err = ret; | 182 | goto out; | 
| 170 | } | 183 | } | 
| 171 | mutex_unlock(&root->fs_info->tree_log_mutex); | 184 | root->log_multiple_pids = false; | 
| 185 | root->log_start_pid = current->pid; | ||
| 172 | atomic_inc(&root->log_batch); | 186 | atomic_inc(&root->log_batch); | 
| 173 | atomic_inc(&root->log_writers); | 187 | atomic_inc(&root->log_writers); | 
| 188 | if (ctx) { | ||
| 189 | index = root->log_transid % 2; | ||
| 190 | list_add_tail(&ctx->list, &root->log_ctxs[index]); | ||
| 191 | ctx->log_transid = root->log_transid; | ||
| 192 | } | ||
| 193 | out: | ||
| 174 | mutex_unlock(&root->log_mutex); | 194 | mutex_unlock(&root->log_mutex); | 
| 175 | return err; | 195 | return ret; | 
| 176 | } | 196 | } | 
| 177 | 197 | ||
| 178 | /* | 198 | /* | 
| @@ -2359,8 +2379,8 @@ static int update_log_root(struct btrfs_trans_handle *trans, | |||
| 2359 | return ret; | 2379 | return ret; | 
| 2360 | } | 2380 | } | 
| 2361 | 2381 | ||
| 2362 | static int wait_log_commit(struct btrfs_trans_handle *trans, | 2382 | static void wait_log_commit(struct btrfs_trans_handle *trans, | 
| 2363 | struct btrfs_root *root, unsigned long transid) | 2383 | struct btrfs_root *root, int transid) | 
| 2364 | { | 2384 | { | 
| 2365 | DEFINE_WAIT(wait); | 2385 | DEFINE_WAIT(wait); | 
| 2366 | int index = transid % 2; | 2386 | int index = transid % 2; | 
| @@ -2375,36 +2395,63 @@ static int wait_log_commit(struct btrfs_trans_handle *trans, | |||
| 2375 | &wait, TASK_UNINTERRUPTIBLE); | 2395 | &wait, TASK_UNINTERRUPTIBLE); | 
| 2376 | mutex_unlock(&root->log_mutex); | 2396 | mutex_unlock(&root->log_mutex); | 
| 2377 | 2397 | ||
| 2378 | if (root->fs_info->last_trans_log_full_commit != | 2398 | if (root->log_transid_committed < transid && | 
| 2379 | trans->transid && root->log_transid < transid + 2 && | ||
| 2380 | atomic_read(&root->log_commit[index])) | 2399 | atomic_read(&root->log_commit[index])) | 
| 2381 | schedule(); | 2400 | schedule(); | 
| 2382 | 2401 | ||
| 2383 | finish_wait(&root->log_commit_wait[index], &wait); | 2402 | finish_wait(&root->log_commit_wait[index], &wait); | 
| 2384 | mutex_lock(&root->log_mutex); | 2403 | mutex_lock(&root->log_mutex); | 
| 2385 | } while (root->fs_info->last_trans_log_full_commit != | 2404 | } while (root->log_transid_committed < transid && | 
| 2386 | trans->transid && root->log_transid < transid + 2 && | ||
| 2387 | atomic_read(&root->log_commit[index])); | 2405 | atomic_read(&root->log_commit[index])); | 
| 2388 | return 0; | ||
| 2389 | } | 2406 | } | 
| 2390 | 2407 | ||
| 2391 | static void wait_for_writer(struct btrfs_trans_handle *trans, | 2408 | static void wait_for_writer(struct btrfs_trans_handle *trans, | 
| 2392 | struct btrfs_root *root) | 2409 | struct btrfs_root *root) | 
| 2393 | { | 2410 | { | 
| 2394 | DEFINE_WAIT(wait); | 2411 | DEFINE_WAIT(wait); | 
| 2395 | while (root->fs_info->last_trans_log_full_commit != | 2412 | |
| 2396 | trans->transid && atomic_read(&root->log_writers)) { | 2413 | while (atomic_read(&root->log_writers)) { | 
| 2397 | prepare_to_wait(&root->log_writer_wait, | 2414 | prepare_to_wait(&root->log_writer_wait, | 
| 2398 | &wait, TASK_UNINTERRUPTIBLE); | 2415 | &wait, TASK_UNINTERRUPTIBLE); | 
| 2399 | mutex_unlock(&root->log_mutex); | 2416 | mutex_unlock(&root->log_mutex); | 
| 2400 | if (root->fs_info->last_trans_log_full_commit != | 2417 | if (atomic_read(&root->log_writers)) | 
| 2401 | trans->transid && atomic_read(&root->log_writers)) | ||
| 2402 | schedule(); | 2418 | schedule(); | 
| 2403 | mutex_lock(&root->log_mutex); | 2419 | mutex_lock(&root->log_mutex); | 
| 2404 | finish_wait(&root->log_writer_wait, &wait); | 2420 | finish_wait(&root->log_writer_wait, &wait); | 
| 2405 | } | 2421 | } | 
| 2406 | } | 2422 | } | 
| 2407 | 2423 | ||
| 2424 | static inline void btrfs_remove_log_ctx(struct btrfs_root *root, | ||
| 2425 | struct btrfs_log_ctx *ctx) | ||
| 2426 | { | ||
| 2427 | if (!ctx) | ||
| 2428 | return; | ||
| 2429 | |||
| 2430 | mutex_lock(&root->log_mutex); | ||
| 2431 | list_del_init(&ctx->list); | ||
| 2432 | mutex_unlock(&root->log_mutex); | ||
| 2433 | } | ||
| 2434 | |||
| 2435 | /* | ||
| 2436 | * Invoked in log mutex context, or be sure there is no other task which | ||
| 2437 | * can access the list. | ||
| 2438 | */ | ||
| 2439 | static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, | ||
| 2440 | int index, int error) | ||
| 2441 | { | ||
| 2442 | struct btrfs_log_ctx *ctx; | ||
| 2443 | |||
| 2444 | if (!error) { | ||
| 2445 | INIT_LIST_HEAD(&root->log_ctxs[index]); | ||
| 2446 | return; | ||
| 2447 | } | ||
| 2448 | |||
| 2449 | list_for_each_entry(ctx, &root->log_ctxs[index], list) | ||
| 2450 | ctx->log_ret = error; | ||
| 2451 | |||
| 2452 | INIT_LIST_HEAD(&root->log_ctxs[index]); | ||
| 2453 | } | ||
| 2454 | |||
| 2408 | /* | 2455 | /* | 
| 2409 | * btrfs_sync_log does sends a given tree log down to the disk and | 2456 | * btrfs_sync_log does sends a given tree log down to the disk and | 
| 2410 | * updates the super blocks to record it. When this call is done, | 2457 | * updates the super blocks to record it. When this call is done, | 
| @@ -2418,7 +2465,7 @@ static void wait_for_writer(struct btrfs_trans_handle *trans, | |||
| 2418 | * that has happened. | 2465 | * that has happened. | 
| 2419 | */ | 2466 | */ | 
| 2420 | int btrfs_sync_log(struct btrfs_trans_handle *trans, | 2467 | int btrfs_sync_log(struct btrfs_trans_handle *trans, | 
| 2421 | struct btrfs_root *root) | 2468 | struct btrfs_root *root, struct btrfs_log_ctx *ctx) | 
| 2422 | { | 2469 | { | 
| 2423 | int index1; | 2470 | int index1; | 
| 2424 | int index2; | 2471 | int index2; | 
| @@ -2426,22 +2473,30 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2426 | int ret; | 2473 | int ret; | 
| 2427 | struct btrfs_root *log = root->log_root; | 2474 | struct btrfs_root *log = root->log_root; | 
| 2428 | struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; | 2475 | struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; | 
| 2429 | unsigned long log_transid = 0; | 2476 | int log_transid = 0; | 
| 2477 | struct btrfs_log_ctx root_log_ctx; | ||
| 2430 | struct blk_plug plug; | 2478 | struct blk_plug plug; | 
| 2431 | 2479 | ||
| 2432 | mutex_lock(&root->log_mutex); | 2480 | mutex_lock(&root->log_mutex); | 
| 2433 | log_transid = root->log_transid; | 2481 | log_transid = ctx->log_transid; | 
| 2434 | index1 = root->log_transid % 2; | 2482 | if (root->log_transid_committed >= log_transid) { | 
| 2483 | mutex_unlock(&root->log_mutex); | ||
| 2484 | return ctx->log_ret; | ||
| 2485 | } | ||
| 2486 | |||
| 2487 | index1 = log_transid % 2; | ||
| 2435 | if (atomic_read(&root->log_commit[index1])) { | 2488 | if (atomic_read(&root->log_commit[index1])) { | 
| 2436 | wait_log_commit(trans, root, root->log_transid); | 2489 | wait_log_commit(trans, root, log_transid); | 
| 2437 | mutex_unlock(&root->log_mutex); | 2490 | mutex_unlock(&root->log_mutex); | 
| 2438 | return 0; | 2491 | return ctx->log_ret; | 
| 2439 | } | 2492 | } | 
| 2493 | ASSERT(log_transid == root->log_transid); | ||
| 2440 | atomic_set(&root->log_commit[index1], 1); | 2494 | atomic_set(&root->log_commit[index1], 1); | 
| 2441 | 2495 | ||
| 2442 | /* wait for previous tree log sync to complete */ | 2496 | /* wait for previous tree log sync to complete */ | 
| 2443 | if (atomic_read(&root->log_commit[(index1 + 1) % 2])) | 2497 | if (atomic_read(&root->log_commit[(index1 + 1) % 2])) | 
| 2444 | wait_log_commit(trans, root, root->log_transid - 1); | 2498 | wait_log_commit(trans, root, log_transid - 1); | 
| 2499 | |||
| 2445 | while (1) { | 2500 | while (1) { | 
| 2446 | int batch = atomic_read(&root->log_batch); | 2501 | int batch = atomic_read(&root->log_batch); | 
| 2447 | /* when we're on an ssd, just kick the log commit out */ | 2502 | /* when we're on an ssd, just kick the log commit out */ | 
| @@ -2456,7 +2511,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2456 | } | 2511 | } | 
| 2457 | 2512 | ||
| 2458 | /* bail out if we need to do a full commit */ | 2513 | /* bail out if we need to do a full commit */ | 
| 2459 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2514 | if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == | 
| 2515 | trans->transid) { | ||
| 2460 | ret = -EAGAIN; | 2516 | ret = -EAGAIN; | 
| 2461 | btrfs_free_logged_extents(log, log_transid); | 2517 | btrfs_free_logged_extents(log, log_transid); | 
| 2462 | mutex_unlock(&root->log_mutex); | 2518 | mutex_unlock(&root->log_mutex); | 
| @@ -2477,6 +2533,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2477 | blk_finish_plug(&plug); | 2533 | blk_finish_plug(&plug); | 
| 2478 | btrfs_abort_transaction(trans, root, ret); | 2534 | btrfs_abort_transaction(trans, root, ret); | 
| 2479 | btrfs_free_logged_extents(log, log_transid); | 2535 | btrfs_free_logged_extents(log, log_transid); | 
| 2536 | ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = | ||
| 2537 | trans->transid; | ||
| 2480 | mutex_unlock(&root->log_mutex); | 2538 | mutex_unlock(&root->log_mutex); | 
| 2481 | goto out; | 2539 | goto out; | 
| 2482 | } | 2540 | } | 
| @@ -2486,7 +2544,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2486 | root->log_transid++; | 2544 | root->log_transid++; | 
| 2487 | log->log_transid = root->log_transid; | 2545 | log->log_transid = root->log_transid; | 
| 2488 | root->log_start_pid = 0; | 2546 | root->log_start_pid = 0; | 
| 2489 | smp_mb(); | ||
| 2490 | /* | 2547 | /* | 
| 2491 | * IO has been started, blocks of the log tree have WRITTEN flag set | 2548 | * IO has been started, blocks of the log tree have WRITTEN flag set | 
| 2492 | * in their headers. new modifications of the log will be written to | 2549 | * in their headers. new modifications of the log will be written to | 
| @@ -2494,9 +2551,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2494 | */ | 2551 | */ | 
| 2495 | mutex_unlock(&root->log_mutex); | 2552 | mutex_unlock(&root->log_mutex); | 
| 2496 | 2553 | ||
| 2554 | btrfs_init_log_ctx(&root_log_ctx); | ||
| 2555 | |||
| 2497 | mutex_lock(&log_root_tree->log_mutex); | 2556 | mutex_lock(&log_root_tree->log_mutex); | 
| 2498 | atomic_inc(&log_root_tree->log_batch); | 2557 | atomic_inc(&log_root_tree->log_batch); | 
| 2499 | atomic_inc(&log_root_tree->log_writers); | 2558 | atomic_inc(&log_root_tree->log_writers); | 
| 2559 | |||
| 2560 | index2 = log_root_tree->log_transid % 2; | ||
| 2561 | list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); | ||
| 2562 | root_log_ctx.log_transid = log_root_tree->log_transid; | ||
| 2563 | |||
| 2500 | mutex_unlock(&log_root_tree->log_mutex); | 2564 | mutex_unlock(&log_root_tree->log_mutex); | 
| 2501 | 2565 | ||
| 2502 | ret = update_log_root(trans, log); | 2566 | ret = update_log_root(trans, log); | 
| @@ -2509,13 +2573,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2509 | } | 2573 | } | 
| 2510 | 2574 | ||
| 2511 | if (ret) { | 2575 | if (ret) { | 
| 2576 | if (!list_empty(&root_log_ctx.list)) | ||
| 2577 | list_del_init(&root_log_ctx.list); | ||
| 2578 | |||
| 2512 | blk_finish_plug(&plug); | 2579 | blk_finish_plug(&plug); | 
| 2580 | ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = | ||
| 2581 | trans->transid; | ||
| 2513 | if (ret != -ENOSPC) { | 2582 | if (ret != -ENOSPC) { | 
| 2514 | btrfs_abort_transaction(trans, root, ret); | 2583 | btrfs_abort_transaction(trans, root, ret); | 
| 2515 | mutex_unlock(&log_root_tree->log_mutex); | 2584 | mutex_unlock(&log_root_tree->log_mutex); | 
| 2516 | goto out; | 2585 | goto out; | 
| 2517 | } | 2586 | } | 
| 2518 | root->fs_info->last_trans_log_full_commit = trans->transid; | ||
| 2519 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2587 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 
| 2520 | btrfs_free_logged_extents(log, log_transid); | 2588 | btrfs_free_logged_extents(log, log_transid); | 
| 2521 | mutex_unlock(&log_root_tree->log_mutex); | 2589 | mutex_unlock(&log_root_tree->log_mutex); | 
| @@ -2523,22 +2591,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2523 | goto out; | 2591 | goto out; | 
| 2524 | } | 2592 | } | 
| 2525 | 2593 | ||
| 2526 | index2 = log_root_tree->log_transid % 2; | 2594 | if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) { | 
| 2595 | mutex_unlock(&log_root_tree->log_mutex); | ||
| 2596 | ret = root_log_ctx.log_ret; | ||
| 2597 | goto out; | ||
| 2598 | } | ||
| 2599 | |||
| 2600 | index2 = root_log_ctx.log_transid % 2; | ||
| 2527 | if (atomic_read(&log_root_tree->log_commit[index2])) { | 2601 | if (atomic_read(&log_root_tree->log_commit[index2])) { | 
| 2528 | blk_finish_plug(&plug); | 2602 | blk_finish_plug(&plug); | 
| 2529 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2603 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 
| 2530 | wait_log_commit(trans, log_root_tree, | 2604 | wait_log_commit(trans, log_root_tree, | 
| 2531 | log_root_tree->log_transid); | 2605 | root_log_ctx.log_transid); | 
| 2532 | btrfs_free_logged_extents(log, log_transid); | 2606 | btrfs_free_logged_extents(log, log_transid); | 
| 2533 | mutex_unlock(&log_root_tree->log_mutex); | 2607 | mutex_unlock(&log_root_tree->log_mutex); | 
| 2534 | ret = 0; | 2608 | ret = root_log_ctx.log_ret; | 
| 2535 | goto out; | 2609 | goto out; | 
| 2536 | } | 2610 | } | 
| 2611 | ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); | ||
| 2537 | atomic_set(&log_root_tree->log_commit[index2], 1); | 2612 | atomic_set(&log_root_tree->log_commit[index2], 1); | 
| 2538 | 2613 | ||
| 2539 | if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { | 2614 | if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { | 
| 2540 | wait_log_commit(trans, log_root_tree, | 2615 | wait_log_commit(trans, log_root_tree, | 
| 2541 | log_root_tree->log_transid - 1); | 2616 | root_log_ctx.log_transid - 1); | 
| 2542 | } | 2617 | } | 
| 2543 | 2618 | ||
| 2544 | wait_for_writer(trans, log_root_tree); | 2619 | wait_for_writer(trans, log_root_tree); | 
| @@ -2547,7 +2622,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2547 | * now that we've moved on to the tree of log tree roots, | 2622 | * now that we've moved on to the tree of log tree roots, | 
| 2548 | * check the full commit flag again | 2623 | * check the full commit flag again | 
| 2549 | */ | 2624 | */ | 
| 2550 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2625 | if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) == | 
| 2626 | trans->transid) { | ||
| 2551 | blk_finish_plug(&plug); | 2627 | blk_finish_plug(&plug); | 
| 2552 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2628 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 
| 2553 | btrfs_free_logged_extents(log, log_transid); | 2629 | btrfs_free_logged_extents(log, log_transid); | 
| @@ -2561,6 +2637,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2561 | EXTENT_DIRTY | EXTENT_NEW); | 2637 | EXTENT_DIRTY | EXTENT_NEW); | 
| 2562 | blk_finish_plug(&plug); | 2638 | blk_finish_plug(&plug); | 
| 2563 | if (ret) { | 2639 | if (ret) { | 
| 2640 | ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = | ||
| 2641 | trans->transid; | ||
| 2564 | btrfs_abort_transaction(trans, root, ret); | 2642 | btrfs_abort_transaction(trans, root, ret); | 
| 2565 | btrfs_free_logged_extents(log, log_transid); | 2643 | btrfs_free_logged_extents(log, log_transid); | 
| 2566 | mutex_unlock(&log_root_tree->log_mutex); | 2644 | mutex_unlock(&log_root_tree->log_mutex); | 
| @@ -2578,8 +2656,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2578 | btrfs_header_level(log_root_tree->node)); | 2656 | btrfs_header_level(log_root_tree->node)); | 
| 2579 | 2657 | ||
| 2580 | log_root_tree->log_transid++; | 2658 | log_root_tree->log_transid++; | 
| 2581 | smp_mb(); | ||
| 2582 | |||
| 2583 | mutex_unlock(&log_root_tree->log_mutex); | 2659 | mutex_unlock(&log_root_tree->log_mutex); | 
| 2584 | 2660 | ||
| 2585 | /* | 2661 | /* | 
| @@ -2591,6 +2667,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2591 | */ | 2667 | */ | 
| 2592 | ret = write_ctree_super(trans, root->fs_info->tree_root, 1); | 2668 | ret = write_ctree_super(trans, root->fs_info->tree_root, 1); | 
| 2593 | if (ret) { | 2669 | if (ret) { | 
| 2670 | ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) = | ||
| 2671 | trans->transid; | ||
| 2594 | btrfs_abort_transaction(trans, root, ret); | 2672 | btrfs_abort_transaction(trans, root, ret); | 
| 2595 | goto out_wake_log_root; | 2673 | goto out_wake_log_root; | 
| 2596 | } | 2674 | } | 
| @@ -2601,13 +2679,28 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
| 2601 | mutex_unlock(&root->log_mutex); | 2679 | mutex_unlock(&root->log_mutex); | 
| 2602 | 2680 | ||
| 2603 | out_wake_log_root: | 2681 | out_wake_log_root: | 
| 2682 | /* | ||
| 2683 | * We needn't get log_mutex here because we are sure all | ||
| 2684 | * the other tasks are blocked. | ||
| 2685 | */ | ||
| 2686 | btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); | ||
| 2687 | |||
| 2688 | mutex_lock(&log_root_tree->log_mutex); | ||
| 2689 | log_root_tree->log_transid_committed++; | ||
| 2604 | atomic_set(&log_root_tree->log_commit[index2], 0); | 2690 | atomic_set(&log_root_tree->log_commit[index2], 0); | 
| 2605 | smp_mb(); | 2691 | mutex_unlock(&log_root_tree->log_mutex); | 
| 2692 | |||
| 2606 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) | 2693 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) | 
| 2607 | wake_up(&log_root_tree->log_commit_wait[index2]); | 2694 | wake_up(&log_root_tree->log_commit_wait[index2]); | 
| 2608 | out: | 2695 | out: | 
| 2696 | /* See above. */ | ||
| 2697 | btrfs_remove_all_log_ctxs(root, index1, ret); | ||
| 2698 | |||
| 2699 | mutex_lock(&root->log_mutex); | ||
| 2700 | root->log_transid_committed++; | ||
| 2609 | atomic_set(&root->log_commit[index1], 0); | 2701 | atomic_set(&root->log_commit[index1], 0); | 
| 2610 | smp_mb(); | 2702 | mutex_unlock(&root->log_mutex); | 
| 2703 | |||
| 2611 | if (waitqueue_active(&root->log_commit_wait[index1])) | 2704 | if (waitqueue_active(&root->log_commit_wait[index1])) | 
| 2612 | wake_up(&root->log_commit_wait[index1]); | 2705 | wake_up(&root->log_commit_wait[index1]); | 
| 2613 | return ret; | 2706 | return ret; | 
| @@ -3479,7 +3572,8 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
| 3479 | 3572 | ||
| 3480 | static int log_one_extent(struct btrfs_trans_handle *trans, | 3573 | static int log_one_extent(struct btrfs_trans_handle *trans, | 
| 3481 | struct inode *inode, struct btrfs_root *root, | 3574 | struct inode *inode, struct btrfs_root *root, | 
| 3482 | struct extent_map *em, struct btrfs_path *path) | 3575 | struct extent_map *em, struct btrfs_path *path, | 
| 3576 | struct list_head *logged_list) | ||
| 3483 | { | 3577 | { | 
| 3484 | struct btrfs_root *log = root->log_root; | 3578 | struct btrfs_root *log = root->log_root; | 
| 3485 | struct btrfs_file_extent_item *fi; | 3579 | struct btrfs_file_extent_item *fi; | 
| @@ -3495,7 +3589,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
| 3495 | u64 extent_offset = em->start - em->orig_start; | 3589 | u64 extent_offset = em->start - em->orig_start; | 
| 3496 | u64 block_len; | 3590 | u64 block_len; | 
| 3497 | int ret; | 3591 | int ret; | 
| 3498 | int index = log->log_transid % 2; | ||
| 3499 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3592 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 
| 3500 | int extent_inserted = 0; | 3593 | int extent_inserted = 0; | 
| 3501 | 3594 | ||
| @@ -3579,17 +3672,12 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
| 3579 | * First check and see if our csums are on our outstanding ordered | 3672 | * First check and see if our csums are on our outstanding ordered | 
| 3580 | * extents. | 3673 | * extents. | 
| 3581 | */ | 3674 | */ | 
| 3582 | again: | 3675 | list_for_each_entry(ordered, logged_list, log_list) { | 
| 3583 | spin_lock_irq(&log->log_extents_lock[index]); | ||
| 3584 | list_for_each_entry(ordered, &log->logged_list[index], log_list) { | ||
| 3585 | struct btrfs_ordered_sum *sum; | 3676 | struct btrfs_ordered_sum *sum; | 
| 3586 | 3677 | ||
| 3587 | if (!mod_len) | 3678 | if (!mod_len) | 
| 3588 | break; | 3679 | break; | 
| 3589 | 3680 | ||
| 3590 | if (ordered->inode != inode) | ||
| 3591 | continue; | ||
| 3592 | |||
| 3593 | if (ordered->file_offset + ordered->len <= mod_start || | 3681 | if (ordered->file_offset + ordered->len <= mod_start || | 
| 3594 | mod_start + mod_len <= ordered->file_offset) | 3682 | mod_start + mod_len <= ordered->file_offset) | 
| 3595 | continue; | 3683 | continue; | 
| @@ -3632,12 +3720,6 @@ again: | |||
| 3632 | if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, | 3720 | if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, | 
| 3633 | &ordered->flags)) | 3721 | &ordered->flags)) | 
| 3634 | continue; | 3722 | continue; | 
| 3635 | atomic_inc(&ordered->refs); | ||
| 3636 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
| 3637 | /* | ||
| 3638 | * we've dropped the lock, we must either break or | ||
| 3639 | * start over after this. | ||
| 3640 | */ | ||
| 3641 | 3723 | ||
| 3642 | if (ordered->csum_bytes_left) { | 3724 | if (ordered->csum_bytes_left) { | 
| 3643 | btrfs_start_ordered_extent(inode, ordered, 0); | 3725 | btrfs_start_ordered_extent(inode, ordered, 0); | 
| @@ -3647,16 +3729,11 @@ again: | |||
| 3647 | 3729 | ||
| 3648 | list_for_each_entry(sum, &ordered->list, list) { | 3730 | list_for_each_entry(sum, &ordered->list, list) { | 
| 3649 | ret = btrfs_csum_file_blocks(trans, log, sum); | 3731 | ret = btrfs_csum_file_blocks(trans, log, sum); | 
| 3650 | if (ret) { | 3732 | if (ret) | 
| 3651 | btrfs_put_ordered_extent(ordered); | ||
| 3652 | goto unlocked; | 3733 | goto unlocked; | 
| 3653 | } | ||
| 3654 | } | 3734 | } | 
| 3655 | btrfs_put_ordered_extent(ordered); | ||
| 3656 | goto again; | ||
| 3657 | 3735 | ||
| 3658 | } | 3736 | } | 
| 3659 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
| 3660 | unlocked: | 3737 | unlocked: | 
| 3661 | 3738 | ||
| 3662 | if (!mod_len || ret) | 3739 | if (!mod_len || ret) | 
| @@ -3694,7 +3771,8 @@ unlocked: | |||
| 3694 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 3771 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 
| 3695 | struct btrfs_root *root, | 3772 | struct btrfs_root *root, | 
| 3696 | struct inode *inode, | 3773 | struct inode *inode, | 
| 3697 | struct btrfs_path *path) | 3774 | struct btrfs_path *path, | 
| 3775 | struct list_head *logged_list) | ||
| 3698 | { | 3776 | { | 
| 3699 | struct extent_map *em, *n; | 3777 | struct extent_map *em, *n; | 
| 3700 | struct list_head extents; | 3778 | struct list_head extents; | 
| @@ -3752,7 +3830,7 @@ process: | |||
| 3752 | 3830 | ||
| 3753 | write_unlock(&tree->lock); | 3831 | write_unlock(&tree->lock); | 
| 3754 | 3832 | ||
| 3755 | ret = log_one_extent(trans, inode, root, em, path); | 3833 | ret = log_one_extent(trans, inode, root, em, path, logged_list); | 
| 3756 | write_lock(&tree->lock); | 3834 | write_lock(&tree->lock); | 
| 3757 | clear_em_logging(tree, em); | 3835 | clear_em_logging(tree, em); | 
| 3758 | free_extent_map(em); | 3836 | free_extent_map(em); | 
| @@ -3788,6 +3866,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
| 3788 | struct btrfs_key max_key; | 3866 | struct btrfs_key max_key; | 
| 3789 | struct btrfs_root *log = root->log_root; | 3867 | struct btrfs_root *log = root->log_root; | 
| 3790 | struct extent_buffer *src = NULL; | 3868 | struct extent_buffer *src = NULL; | 
| 3869 | LIST_HEAD(logged_list); | ||
| 3791 | u64 last_extent = 0; | 3870 | u64 last_extent = 0; | 
| 3792 | int err = 0; | 3871 | int err = 0; | 
| 3793 | int ret; | 3872 | int ret; | 
| @@ -3836,7 +3915,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
| 3836 | 3915 | ||
| 3837 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 3916 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 
| 3838 | 3917 | ||
| 3839 | btrfs_get_logged_extents(log, inode); | 3918 | btrfs_get_logged_extents(inode, &logged_list); | 
| 3840 | 3919 | ||
| 3841 | /* | 3920 | /* | 
| 3842 | * a brute force approach to making sure we get the most uptodate | 3921 | * a brute force approach to making sure we get the most uptodate | 
| @@ -3962,7 +4041,8 @@ log_extents: | |||
| 3962 | btrfs_release_path(path); | 4041 | btrfs_release_path(path); | 
| 3963 | btrfs_release_path(dst_path); | 4042 | btrfs_release_path(dst_path); | 
| 3964 | if (fast_search) { | 4043 | if (fast_search) { | 
| 3965 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path); | 4044 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path, | 
| 4045 | &logged_list); | ||
| 3966 | if (ret) { | 4046 | if (ret) { | 
| 3967 | err = ret; | 4047 | err = ret; | 
| 3968 | goto out_unlock; | 4048 | goto out_unlock; | 
| @@ -3987,8 +4067,10 @@ log_extents: | |||
| 3987 | BTRFS_I(inode)->logged_trans = trans->transid; | 4067 | BTRFS_I(inode)->logged_trans = trans->transid; | 
| 3988 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; | 4068 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; | 
| 3989 | out_unlock: | 4069 | out_unlock: | 
| 3990 | if (err) | 4070 | if (unlikely(err)) | 
| 3991 | btrfs_free_logged_extents(log, log->log_transid); | 4071 | btrfs_put_logged_extents(&logged_list); | 
| 4072 | else | ||
| 4073 | btrfs_submit_logged_extents(&logged_list, log); | ||
| 3992 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 4074 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 
| 3993 | 4075 | ||
| 3994 | btrfs_free_path(path); | 4076 | btrfs_free_path(path); | 
| @@ -4079,7 +4161,8 @@ out: | |||
| 4079 | */ | 4161 | */ | 
| 4080 | static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | 4162 | static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | 
| 4081 | struct btrfs_root *root, struct inode *inode, | 4163 | struct btrfs_root *root, struct inode *inode, | 
| 4082 | struct dentry *parent, int exists_only) | 4164 | struct dentry *parent, int exists_only, | 
| 4165 | struct btrfs_log_ctx *ctx) | ||
| 4083 | { | 4166 | { | 
| 4084 | int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; | 4167 | int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; | 
| 4085 | struct super_block *sb; | 4168 | struct super_block *sb; | 
| @@ -4116,9 +4199,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
| 4116 | goto end_no_trans; | 4199 | goto end_no_trans; | 
| 4117 | } | 4200 | } | 
| 4118 | 4201 | ||
| 4119 | ret = start_log_trans(trans, root); | 4202 | ret = start_log_trans(trans, root, ctx); | 
| 4120 | if (ret) | 4203 | if (ret) | 
| 4121 | goto end_trans; | 4204 | goto end_no_trans; | 
| 4122 | 4205 | ||
| 4123 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 4206 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 
| 4124 | if (ret) | 4207 | if (ret) | 
| @@ -4166,6 +4249,9 @@ end_trans: | |||
| 4166 | root->fs_info->last_trans_log_full_commit = trans->transid; | 4249 | root->fs_info->last_trans_log_full_commit = trans->transid; | 
| 4167 | ret = 1; | 4250 | ret = 1; | 
| 4168 | } | 4251 | } | 
| 4252 | |||
| 4253 | if (ret) | ||
| 4254 | btrfs_remove_log_ctx(root, ctx); | ||
| 4169 | btrfs_end_log_trans(root); | 4255 | btrfs_end_log_trans(root); | 
| 4170 | end_no_trans: | 4256 | end_no_trans: | 
| 4171 | return ret; | 4257 | return ret; | 
| @@ -4178,12 +4264,14 @@ end_no_trans: | |||
| 4178 | * data on disk. | 4264 | * data on disk. | 
| 4179 | */ | 4265 | */ | 
| 4180 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, | 4266 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, | 
| 4181 | struct btrfs_root *root, struct dentry *dentry) | 4267 | struct btrfs_root *root, struct dentry *dentry, | 
| 4268 | struct btrfs_log_ctx *ctx) | ||
| 4182 | { | 4269 | { | 
| 4183 | struct dentry *parent = dget_parent(dentry); | 4270 | struct dentry *parent = dget_parent(dentry); | 
| 4184 | int ret; | 4271 | int ret; | 
| 4185 | 4272 | ||
| 4186 | ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0); | 4273 | ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, | 
| 4274 | 0, ctx); | ||
| 4187 | dput(parent); | 4275 | dput(parent); | 
| 4188 | 4276 | ||
| 4189 | return ret; | 4277 | return ret; | 
| @@ -4420,6 +4508,6 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, | |||
| 4420 | root->fs_info->last_trans_committed)) | 4508 | root->fs_info->last_trans_committed)) | 
| 4421 | return 0; | 4509 | return 0; | 
| 4422 | 4510 | ||
| 4423 | return btrfs_log_inode_parent(trans, root, inode, parent, 1); | 4511 | return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL); | 
| 4424 | } | 4512 | } | 
| 4425 | 4513 | ||
