aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c183
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
2455static 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;
2543again: 2630again:
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];
2653next_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);