diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 183 |
1 files changed, 122 insertions, 61 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5f77bee0f846..ae96451bc223 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2452,6 +2452,94 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | |||
2452 | return 0; | 2452 | return 0; |
2453 | } | 2453 | } |
2454 | 2454 | ||
2455 | static noinline int copy_items(struct btrfs_trans_handle *trans, | ||
2456 | struct btrfs_root *log, | ||
2457 | struct btrfs_path *dst_path, | ||
2458 | struct extent_buffer *src, | ||
2459 | int start_slot, int nr, int inode_only) | ||
2460 | { | ||
2461 | unsigned long src_offset; | ||
2462 | unsigned long dst_offset; | ||
2463 | struct btrfs_file_extent_item *extent; | ||
2464 | struct btrfs_inode_item *inode_item; | ||
2465 | int ret; | ||
2466 | struct btrfs_key *ins_keys; | ||
2467 | u32 *ins_sizes; | ||
2468 | char *ins_data; | ||
2469 | int i; | ||
2470 | |||
2471 | ins_data = kmalloc(nr * sizeof(struct btrfs_key) + | ||
2472 | nr * sizeof(u32), GFP_NOFS); | ||
2473 | ins_sizes = (u32 *)ins_data; | ||
2474 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); | ||
2475 | |||
2476 | for (i = 0; i < nr; i++) { | ||
2477 | ins_sizes[i] = btrfs_item_size_nr(src, i + start_slot); | ||
2478 | btrfs_item_key_to_cpu(src, ins_keys + i, i + start_slot); | ||
2479 | } | ||
2480 | ret = btrfs_insert_empty_items(trans, log, dst_path, | ||
2481 | ins_keys, ins_sizes, nr); | ||
2482 | BUG_ON(ret); | ||
2483 | |||
2484 | for (i = 0; i < nr; i++) { | ||
2485 | dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], | ||
2486 | dst_path->slots[0]); | ||
2487 | |||
2488 | src_offset = btrfs_item_ptr_offset(src, start_slot + i); | ||
2489 | |||
2490 | copy_extent_buffer(dst_path->nodes[0], src, dst_offset, | ||
2491 | src_offset, ins_sizes[i]); | ||
2492 | |||
2493 | if (inode_only == LOG_INODE_EXISTS && | ||
2494 | ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { | ||
2495 | inode_item = btrfs_item_ptr(dst_path->nodes[0], | ||
2496 | dst_path->slots[0], | ||
2497 | struct btrfs_inode_item); | ||
2498 | btrfs_set_inode_size(dst_path->nodes[0], inode_item, 0); | ||
2499 | |||
2500 | /* set the generation to zero so the recover code | ||
2501 | * can tell the difference between an logging | ||
2502 | * just to say 'this inode exists' and a logging | ||
2503 | * to say 'update this inode with these values' | ||
2504 | */ | ||
2505 | btrfs_set_inode_generation(dst_path->nodes[0], | ||
2506 | inode_item, 0); | ||
2507 | } | ||
2508 | /* take a reference on file data extents so that truncates | ||
2509 | * or deletes of this inode don't have to relog the inode | ||
2510 | * again | ||
2511 | */ | ||
2512 | if (btrfs_key_type(ins_keys + i) == BTRFS_EXTENT_DATA_KEY) { | ||
2513 | int found_type; | ||
2514 | extent = btrfs_item_ptr(src, start_slot + i, | ||
2515 | struct btrfs_file_extent_item); | ||
2516 | |||
2517 | found_type = btrfs_file_extent_type(src, extent); | ||
2518 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
2519 | u64 ds = btrfs_file_extent_disk_bytenr(src, | ||
2520 | extent); | ||
2521 | u64 dl = btrfs_file_extent_disk_num_bytes(src, | ||
2522 | extent); | ||
2523 | /* ds == 0 is a hole */ | ||
2524 | if (ds != 0) { | ||
2525 | ret = btrfs_inc_extent_ref(trans, log, | ||
2526 | ds, dl, | ||
2527 | BTRFS_TREE_LOG_OBJECTID, | ||
2528 | 0, ins_keys[i].objectid, | ||
2529 | ins_keys[i].offset); | ||
2530 | BUG_ON(ret); | ||
2531 | } | ||
2532 | } | ||
2533 | } | ||
2534 | dst_path->slots[0]++; | ||
2535 | } | ||
2536 | |||
2537 | btrfs_mark_buffer_dirty(dst_path->nodes[0]); | ||
2538 | btrfs_release_path(log, dst_path); | ||
2539 | kfree(ins_data); | ||
2540 | return 0; | ||
2541 | } | ||
2542 | |||
2455 | /* log a single inode in the tree log. | 2543 | /* log a single inode in the tree log. |
2456 | * At least one parent directory for this inode must exist in the tree | 2544 | * At least one parent directory for this inode must exist in the tree |
2457 | * or be logged already. | 2545 | * or be logged already. |
@@ -2475,14 +2563,12 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
2475 | struct btrfs_key min_key; | 2563 | struct btrfs_key min_key; |
2476 | struct btrfs_key max_key; | 2564 | struct btrfs_key max_key; |
2477 | struct btrfs_root *log = root->log_root; | 2565 | struct btrfs_root *log = root->log_root; |
2478 | unsigned long src_offset; | 2566 | struct extent_buffer *src = NULL; |
2479 | unsigned long dst_offset; | ||
2480 | struct extent_buffer *src; | ||
2481 | struct btrfs_file_extent_item *extent; | ||
2482 | struct btrfs_inode_item *inode_item; | ||
2483 | u32 size; | 2567 | u32 size; |
2484 | int ret; | 2568 | int ret; |
2485 | int nritems; | 2569 | int nritems; |
2570 | int ins_start_slot = 0; | ||
2571 | int ins_nr; | ||
2486 | 2572 | ||
2487 | log = root->log_root; | 2573 | log = root->log_root; |
2488 | 2574 | ||
@@ -2536,75 +2622,35 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
2536 | path->keep_locks = 1; | 2622 | path->keep_locks = 1; |
2537 | 2623 | ||
2538 | while(1) { | 2624 | while(1) { |
2625 | ins_nr = 0; | ||
2539 | ret = btrfs_search_forward(root, &min_key, &max_key, | 2626 | ret = btrfs_search_forward(root, &min_key, &max_key, |
2540 | path, 0, trans->transid); | 2627 | path, 0, trans->transid); |
2541 | if (ret != 0) | 2628 | if (ret != 0) |
2542 | break; | 2629 | break; |
2543 | again: | 2630 | again: |
2631 | /* note, ins_nr might be > 0 here, cleanup outside the loop */ | ||
2544 | if (min_key.objectid != inode->i_ino) | 2632 | if (min_key.objectid != inode->i_ino) |
2545 | break; | 2633 | break; |
2546 | if (min_key.type > max_key.type) | 2634 | if (min_key.type > max_key.type) |
2547 | break; | 2635 | break; |
2636 | |||
2548 | src = path->nodes[0]; | 2637 | src = path->nodes[0]; |
2549 | size = btrfs_item_size_nr(src, path->slots[0]); | 2638 | size = btrfs_item_size_nr(src, path->slots[0]); |
2550 | ret = btrfs_insert_empty_item(trans, log, dst_path, &min_key, | 2639 | if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { |
2551 | size); | 2640 | ins_nr++; |
2552 | if (ret) | 2641 | goto next_slot; |
2553 | BUG(); | 2642 | } else if (!ins_nr) { |
2554 | 2643 | ins_start_slot = path->slots[0]; | |
2555 | dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], | 2644 | ins_nr = 1; |
2556 | dst_path->slots[0]); | 2645 | goto next_slot; |
2557 | |||
2558 | src_offset = btrfs_item_ptr_offset(src, path->slots[0]); | ||
2559 | |||
2560 | copy_extent_buffer(dst_path->nodes[0], src, dst_offset, | ||
2561 | src_offset, size); | ||
2562 | |||
2563 | if (inode_only == LOG_INODE_EXISTS && | ||
2564 | min_key.type == BTRFS_INODE_ITEM_KEY) { | ||
2565 | inode_item = btrfs_item_ptr(dst_path->nodes[0], | ||
2566 | dst_path->slots[0], | ||
2567 | struct btrfs_inode_item); | ||
2568 | btrfs_set_inode_size(dst_path->nodes[0], inode_item, 0); | ||
2569 | |||
2570 | /* set the generation to zero so the recover code | ||
2571 | * can tell the difference between an logging | ||
2572 | * just to say 'this inode exists' and a logging | ||
2573 | * to say 'update this inode with these values' | ||
2574 | */ | ||
2575 | btrfs_set_inode_generation(dst_path->nodes[0], | ||
2576 | inode_item, 0); | ||
2577 | } | ||
2578 | /* take a reference on file data extents so that truncates | ||
2579 | * or deletes of this inode don't have to relog the inode | ||
2580 | * again | ||
2581 | */ | ||
2582 | if (btrfs_key_type(&min_key) == BTRFS_EXTENT_DATA_KEY) { | ||
2583 | int found_type; | ||
2584 | extent = btrfs_item_ptr(src, path->slots[0], | ||
2585 | struct btrfs_file_extent_item); | ||
2586 | |||
2587 | found_type = btrfs_file_extent_type(src, extent); | ||
2588 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
2589 | u64 ds = btrfs_file_extent_disk_bytenr(src, | ||
2590 | extent); | ||
2591 | u64 dl = btrfs_file_extent_disk_num_bytes(src, | ||
2592 | extent); | ||
2593 | /* ds == 0 is a hole */ | ||
2594 | if (ds != 0) { | ||
2595 | ret = btrfs_inc_extent_ref(trans, log, | ||
2596 | ds, dl, | ||
2597 | log->root_key.objectid, | ||
2598 | 0, | ||
2599 | inode->i_ino, | ||
2600 | min_key.offset); | ||
2601 | BUG_ON(ret); | ||
2602 | } | ||
2603 | } | ||
2604 | } | 2646 | } |
2605 | 2647 | ||
2606 | btrfs_mark_buffer_dirty(dst_path->nodes[0]); | 2648 | ret = copy_items(trans, log, dst_path, src, ins_start_slot, |
2607 | btrfs_release_path(log, dst_path); | 2649 | ins_nr, inode_only); |
2650 | BUG_ON(ret); | ||
2651 | ins_nr = 1; | ||
2652 | ins_start_slot = path->slots[0]; | ||
2653 | next_slot: | ||
2608 | 2654 | ||
2609 | nritems = btrfs_header_nritems(path->nodes[0]); | 2655 | nritems = btrfs_header_nritems(path->nodes[0]); |
2610 | path->slots[0]++; | 2656 | path->slots[0]++; |
@@ -2613,6 +2659,13 @@ again: | |||
2613 | path->slots[0]); | 2659 | path->slots[0]); |
2614 | goto again; | 2660 | goto again; |
2615 | } | 2661 | } |
2662 | if (ins_nr) { | ||
2663 | ret = copy_items(trans, log, dst_path, src, | ||
2664 | ins_start_slot, | ||
2665 | ins_nr, inode_only); | ||
2666 | BUG_ON(ret); | ||
2667 | ins_nr = 0; | ||
2668 | } | ||
2616 | btrfs_release_path(root, path); | 2669 | btrfs_release_path(root, path); |
2617 | 2670 | ||
2618 | if (min_key.offset < (u64)-1) | 2671 | if (min_key.offset < (u64)-1) |
@@ -2624,6 +2677,14 @@ again: | |||
2624 | else | 2677 | else |
2625 | break; | 2678 | break; |
2626 | } | 2679 | } |
2680 | if (ins_nr) { | ||
2681 | ret = copy_items(trans, log, dst_path, src, | ||
2682 | ins_start_slot, | ||
2683 | ins_nr, inode_only); | ||
2684 | BUG_ON(ret); | ||
2685 | ins_nr = 0; | ||
2686 | } | ||
2687 | WARN_ON(ins_nr); | ||
2627 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode) && | 2688 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode) && |
2628 | BTRFS_I(inode)->log_dirty_trans >= trans->transid) { | 2689 | BTRFS_I(inode)->log_dirty_trans >= trans->transid) { |
2629 | btrfs_release_path(root, path); | 2690 | btrfs_release_path(root, path); |