diff options
-rw-r--r-- | fs/btrfs/ctree.c | 458 |
1 files changed, 278 insertions, 180 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index bebc9fd16665..3764248bdc05 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -2266,66 +2266,27 @@ noinline int btrfs_leaf_free_space(struct btrfs_root *root, | |||
2266 | return ret; | 2266 | return ret; |
2267 | } | 2267 | } |
2268 | 2268 | ||
2269 | /* | 2269 | static noinline int __push_leaf_right(struct btrfs_trans_handle *trans, |
2270 | * push some data in the path leaf to the right, trying to free up at | 2270 | struct btrfs_root *root, |
2271 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 2271 | struct btrfs_path *path, |
2272 | * | 2272 | int data_size, int empty, |
2273 | * returns 1 if the push failed because the other node didn't have enough | 2273 | struct extent_buffer *right, |
2274 | * room, 0 if everything worked out and < 0 if there were major errors. | 2274 | int free_space, u32 left_nritems) |
2275 | */ | ||
2276 | static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | ||
2277 | *root, struct btrfs_path *path, int data_size, | ||
2278 | int empty) | ||
2279 | { | 2275 | { |
2280 | struct extent_buffer *left = path->nodes[0]; | 2276 | struct extent_buffer *left = path->nodes[0]; |
2281 | struct extent_buffer *right; | 2277 | struct extent_buffer *upper = path->nodes[1]; |
2282 | struct extent_buffer *upper; | ||
2283 | struct btrfs_disk_key disk_key; | 2278 | struct btrfs_disk_key disk_key; |
2284 | int slot; | 2279 | int slot; |
2285 | u32 i; | 2280 | u32 i; |
2286 | int free_space; | ||
2287 | int push_space = 0; | 2281 | int push_space = 0; |
2288 | int push_items = 0; | 2282 | int push_items = 0; |
2289 | struct btrfs_item *item; | 2283 | struct btrfs_item *item; |
2290 | u32 left_nritems; | ||
2291 | u32 nr; | 2284 | u32 nr; |
2292 | u32 right_nritems; | 2285 | u32 right_nritems; |
2293 | u32 data_end; | 2286 | u32 data_end; |
2294 | u32 this_item_size; | 2287 | u32 this_item_size; |
2295 | int ret; | 2288 | int ret; |
2296 | 2289 | ||
2297 | slot = path->slots[1]; | ||
2298 | if (!path->nodes[1]) | ||
2299 | return 1; | ||
2300 | |||
2301 | upper = path->nodes[1]; | ||
2302 | if (slot >= btrfs_header_nritems(upper) - 1) | ||
2303 | return 1; | ||
2304 | |||
2305 | btrfs_assert_tree_locked(path->nodes[1]); | ||
2306 | |||
2307 | right = read_node_slot(root, upper, slot + 1); | ||
2308 | btrfs_tree_lock(right); | ||
2309 | btrfs_set_lock_blocking(right); | ||
2310 | |||
2311 | free_space = btrfs_leaf_free_space(root, right); | ||
2312 | if (free_space < data_size) | ||
2313 | goto out_unlock; | ||
2314 | |||
2315 | /* cow and double check */ | ||
2316 | ret = btrfs_cow_block(trans, root, right, upper, | ||
2317 | slot + 1, &right); | ||
2318 | if (ret) | ||
2319 | goto out_unlock; | ||
2320 | |||
2321 | free_space = btrfs_leaf_free_space(root, right); | ||
2322 | if (free_space < data_size) | ||
2323 | goto out_unlock; | ||
2324 | |||
2325 | left_nritems = btrfs_header_nritems(left); | ||
2326 | if (left_nritems == 0) | ||
2327 | goto out_unlock; | ||
2328 | |||
2329 | if (empty) | 2290 | if (empty) |
2330 | nr = 0; | 2291 | nr = 0; |
2331 | else | 2292 | else |
@@ -2334,6 +2295,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2334 | if (path->slots[0] >= left_nritems) | 2295 | if (path->slots[0] >= left_nritems) |
2335 | push_space += data_size; | 2296 | push_space += data_size; |
2336 | 2297 | ||
2298 | slot = path->slots[1]; | ||
2337 | i = left_nritems - 1; | 2299 | i = left_nritems - 1; |
2338 | while (i >= nr) { | 2300 | while (i >= nr) { |
2339 | item = btrfs_item_nr(left, i); | 2301 | item = btrfs_item_nr(left, i); |
@@ -2465,24 +2427,82 @@ out_unlock: | |||
2465 | } | 2427 | } |
2466 | 2428 | ||
2467 | /* | 2429 | /* |
2430 | * push some data in the path leaf to the right, trying to free up at | ||
2431 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | ||
2432 | * | ||
2433 | * returns 1 if the push failed because the other node didn't have enough | ||
2434 | * room, 0 if everything worked out and < 0 if there were major errors. | ||
2435 | */ | ||
2436 | static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root | ||
2437 | *root, struct btrfs_path *path, int data_size, | ||
2438 | int empty) | ||
2439 | { | ||
2440 | struct extent_buffer *left = path->nodes[0]; | ||
2441 | struct extent_buffer *right; | ||
2442 | struct extent_buffer *upper; | ||
2443 | int slot; | ||
2444 | int free_space; | ||
2445 | u32 left_nritems; | ||
2446 | int ret; | ||
2447 | |||
2448 | if (!path->nodes[1]) | ||
2449 | return 1; | ||
2450 | |||
2451 | slot = path->slots[1]; | ||
2452 | upper = path->nodes[1]; | ||
2453 | if (slot >= btrfs_header_nritems(upper) - 1) | ||
2454 | return 1; | ||
2455 | |||
2456 | btrfs_assert_tree_locked(path->nodes[1]); | ||
2457 | |||
2458 | right = read_node_slot(root, upper, slot + 1); | ||
2459 | btrfs_tree_lock(right); | ||
2460 | btrfs_set_lock_blocking(right); | ||
2461 | |||
2462 | free_space = btrfs_leaf_free_space(root, right); | ||
2463 | if (free_space < data_size) | ||
2464 | goto out_unlock; | ||
2465 | |||
2466 | /* cow and double check */ | ||
2467 | ret = btrfs_cow_block(trans, root, right, upper, | ||
2468 | slot + 1, &right); | ||
2469 | if (ret) | ||
2470 | goto out_unlock; | ||
2471 | |||
2472 | free_space = btrfs_leaf_free_space(root, right); | ||
2473 | if (free_space < data_size) | ||
2474 | goto out_unlock; | ||
2475 | |||
2476 | left_nritems = btrfs_header_nritems(left); | ||
2477 | if (left_nritems == 0) | ||
2478 | goto out_unlock; | ||
2479 | |||
2480 | return __push_leaf_right(trans, root, path, data_size, empty, | ||
2481 | right, free_space, left_nritems); | ||
2482 | out_unlock: | ||
2483 | btrfs_tree_unlock(right); | ||
2484 | free_extent_buffer(right); | ||
2485 | return 1; | ||
2486 | } | ||
2487 | |||
2488 | /* | ||
2468 | * push some data in the path leaf to the left, trying to free up at | 2489 | * push some data in the path leaf to the left, trying to free up at |
2469 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | 2490 | * least data_size bytes. returns zero if the push worked, nonzero otherwise |
2470 | */ | 2491 | */ |
2471 | static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | 2492 | static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, |
2472 | *root, struct btrfs_path *path, int data_size, | 2493 | struct btrfs_root *root, |
2473 | int empty) | 2494 | struct btrfs_path *path, int data_size, |
2495 | int empty, struct extent_buffer *left, | ||
2496 | int free_space, int right_nritems) | ||
2474 | { | 2497 | { |
2475 | struct btrfs_disk_key disk_key; | 2498 | struct btrfs_disk_key disk_key; |
2476 | struct extent_buffer *right = path->nodes[0]; | 2499 | struct extent_buffer *right = path->nodes[0]; |
2477 | struct extent_buffer *left; | ||
2478 | int slot; | 2500 | int slot; |
2479 | int i; | 2501 | int i; |
2480 | int free_space; | ||
2481 | int push_space = 0; | 2502 | int push_space = 0; |
2482 | int push_items = 0; | 2503 | int push_items = 0; |
2483 | struct btrfs_item *item; | 2504 | struct btrfs_item *item; |
2484 | u32 old_left_nritems; | 2505 | u32 old_left_nritems; |
2485 | u32 right_nritems; | ||
2486 | u32 nr; | 2506 | u32 nr; |
2487 | int ret = 0; | 2507 | int ret = 0; |
2488 | int wret; | 2508 | int wret; |
@@ -2490,41 +2510,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2490 | u32 old_left_item_size; | 2510 | u32 old_left_item_size; |
2491 | 2511 | ||
2492 | slot = path->slots[1]; | 2512 | slot = path->slots[1]; |
2493 | if (slot == 0) | ||
2494 | return 1; | ||
2495 | if (!path->nodes[1]) | ||
2496 | return 1; | ||
2497 | |||
2498 | right_nritems = btrfs_header_nritems(right); | ||
2499 | if (right_nritems == 0) | ||
2500 | return 1; | ||
2501 | |||
2502 | btrfs_assert_tree_locked(path->nodes[1]); | ||
2503 | |||
2504 | left = read_node_slot(root, path->nodes[1], slot - 1); | ||
2505 | btrfs_tree_lock(left); | ||
2506 | btrfs_set_lock_blocking(left); | ||
2507 | |||
2508 | free_space = btrfs_leaf_free_space(root, left); | ||
2509 | if (free_space < data_size) { | ||
2510 | ret = 1; | ||
2511 | goto out; | ||
2512 | } | ||
2513 | |||
2514 | /* cow and double check */ | ||
2515 | ret = btrfs_cow_block(trans, root, left, | ||
2516 | path->nodes[1], slot - 1, &left); | ||
2517 | if (ret) { | ||
2518 | /* we hit -ENOSPC, but it isn't fatal here */ | ||
2519 | ret = 1; | ||
2520 | goto out; | ||
2521 | } | ||
2522 | |||
2523 | free_space = btrfs_leaf_free_space(root, left); | ||
2524 | if (free_space < data_size) { | ||
2525 | ret = 1; | ||
2526 | goto out; | ||
2527 | } | ||
2528 | 2513 | ||
2529 | if (empty) | 2514 | if (empty) |
2530 | nr = right_nritems; | 2515 | nr = right_nritems; |
@@ -2692,6 +2677,154 @@ out: | |||
2692 | } | 2677 | } |
2693 | 2678 | ||
2694 | /* | 2679 | /* |
2680 | * push some data in the path leaf to the left, trying to free up at | ||
2681 | * least data_size bytes. returns zero if the push worked, nonzero otherwise | ||
2682 | */ | ||
2683 | static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root | ||
2684 | *root, struct btrfs_path *path, int data_size, | ||
2685 | int empty) | ||
2686 | { | ||
2687 | struct extent_buffer *right = path->nodes[0]; | ||
2688 | struct extent_buffer *left; | ||
2689 | int slot; | ||
2690 | int free_space; | ||
2691 | u32 right_nritems; | ||
2692 | int ret = 0; | ||
2693 | |||
2694 | slot = path->slots[1]; | ||
2695 | if (slot == 0) | ||
2696 | return 1; | ||
2697 | if (!path->nodes[1]) | ||
2698 | return 1; | ||
2699 | |||
2700 | right_nritems = btrfs_header_nritems(right); | ||
2701 | if (right_nritems == 0) | ||
2702 | return 1; | ||
2703 | |||
2704 | btrfs_assert_tree_locked(path->nodes[1]); | ||
2705 | |||
2706 | left = read_node_slot(root, path->nodes[1], slot - 1); | ||
2707 | btrfs_tree_lock(left); | ||
2708 | btrfs_set_lock_blocking(left); | ||
2709 | |||
2710 | free_space = btrfs_leaf_free_space(root, left); | ||
2711 | if (free_space < data_size) { | ||
2712 | ret = 1; | ||
2713 | goto out; | ||
2714 | } | ||
2715 | |||
2716 | /* cow and double check */ | ||
2717 | ret = btrfs_cow_block(trans, root, left, | ||
2718 | path->nodes[1], slot - 1, &left); | ||
2719 | if (ret) { | ||
2720 | /* we hit -ENOSPC, but it isn't fatal here */ | ||
2721 | ret = 1; | ||
2722 | goto out; | ||
2723 | } | ||
2724 | |||
2725 | free_space = btrfs_leaf_free_space(root, left); | ||
2726 | if (free_space < data_size) { | ||
2727 | ret = 1; | ||
2728 | goto out; | ||
2729 | } | ||
2730 | |||
2731 | return __push_leaf_left(trans, root, path, data_size, | ||
2732 | empty, left, free_space, right_nritems); | ||
2733 | out: | ||
2734 | btrfs_tree_unlock(left); | ||
2735 | free_extent_buffer(left); | ||
2736 | return ret; | ||
2737 | } | ||
2738 | |||
2739 | /* | ||
2740 | * split the path's leaf in two, making sure there is at least data_size | ||
2741 | * available for the resulting leaf level of the path. | ||
2742 | * | ||
2743 | * returns 0 if all went well and < 0 on failure. | ||
2744 | */ | ||
2745 | static noinline int copy_for_split(struct btrfs_trans_handle *trans, | ||
2746 | struct btrfs_root *root, | ||
2747 | struct btrfs_path *path, | ||
2748 | struct extent_buffer *l, | ||
2749 | struct extent_buffer *right, | ||
2750 | int slot, int mid, int nritems) | ||
2751 | { | ||
2752 | int data_copy_size; | ||
2753 | int rt_data_off; | ||
2754 | int i; | ||
2755 | int ret = 0; | ||
2756 | int wret; | ||
2757 | struct btrfs_disk_key disk_key; | ||
2758 | |||
2759 | nritems = nritems - mid; | ||
2760 | btrfs_set_header_nritems(right, nritems); | ||
2761 | data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); | ||
2762 | |||
2763 | copy_extent_buffer(right, l, btrfs_item_nr_offset(0), | ||
2764 | btrfs_item_nr_offset(mid), | ||
2765 | nritems * sizeof(struct btrfs_item)); | ||
2766 | |||
2767 | copy_extent_buffer(right, l, | ||
2768 | btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - | ||
2769 | data_copy_size, btrfs_leaf_data(l) + | ||
2770 | leaf_data_end(root, l), data_copy_size); | ||
2771 | |||
2772 | rt_data_off = BTRFS_LEAF_DATA_SIZE(root) - | ||
2773 | btrfs_item_end_nr(l, mid); | ||
2774 | |||
2775 | for (i = 0; i < nritems; i++) { | ||
2776 | struct btrfs_item *item = btrfs_item_nr(right, i); | ||
2777 | u32 ioff; | ||
2778 | |||
2779 | if (!right->map_token) { | ||
2780 | map_extent_buffer(right, (unsigned long)item, | ||
2781 | sizeof(struct btrfs_item), | ||
2782 | &right->map_token, &right->kaddr, | ||
2783 | &right->map_start, &right->map_len, | ||
2784 | KM_USER1); | ||
2785 | } | ||
2786 | |||
2787 | ioff = btrfs_item_offset(right, item); | ||
2788 | btrfs_set_item_offset(right, item, ioff + rt_data_off); | ||
2789 | } | ||
2790 | |||
2791 | if (right->map_token) { | ||
2792 | unmap_extent_buffer(right, right->map_token, KM_USER1); | ||
2793 | right->map_token = NULL; | ||
2794 | } | ||
2795 | |||
2796 | btrfs_set_header_nritems(l, mid); | ||
2797 | ret = 0; | ||
2798 | btrfs_item_key(right, &disk_key, 0); | ||
2799 | wret = insert_ptr(trans, root, path, &disk_key, right->start, | ||
2800 | path->slots[1] + 1, 1); | ||
2801 | if (wret) | ||
2802 | ret = wret; | ||
2803 | |||
2804 | btrfs_mark_buffer_dirty(right); | ||
2805 | btrfs_mark_buffer_dirty(l); | ||
2806 | BUG_ON(path->slots[0] != slot); | ||
2807 | |||
2808 | ret = btrfs_update_ref(trans, root, l, right, 0, nritems); | ||
2809 | BUG_ON(ret); | ||
2810 | |||
2811 | if (mid <= slot) { | ||
2812 | btrfs_tree_unlock(path->nodes[0]); | ||
2813 | free_extent_buffer(path->nodes[0]); | ||
2814 | path->nodes[0] = right; | ||
2815 | path->slots[0] -= mid; | ||
2816 | path->slots[1] += 1; | ||
2817 | } else { | ||
2818 | btrfs_tree_unlock(right); | ||
2819 | free_extent_buffer(right); | ||
2820 | } | ||
2821 | |||
2822 | BUG_ON(path->slots[0] < 0); | ||
2823 | |||
2824 | return ret; | ||
2825 | } | ||
2826 | |||
2827 | /* | ||
2695 | * split the path's leaf in two, making sure there is at least data_size | 2828 | * split the path's leaf in two, making sure there is at least data_size |
2696 | * available for the resulting leaf level of the path. | 2829 | * available for the resulting leaf level of the path. |
2697 | * | 2830 | * |
@@ -2708,14 +2841,10 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, | |||
2708 | int mid; | 2841 | int mid; |
2709 | int slot; | 2842 | int slot; |
2710 | struct extent_buffer *right; | 2843 | struct extent_buffer *right; |
2711 | int data_copy_size; | ||
2712 | int rt_data_off; | ||
2713 | int i; | ||
2714 | int ret = 0; | 2844 | int ret = 0; |
2715 | int wret; | 2845 | int wret; |
2716 | int double_split; | 2846 | int double_split; |
2717 | int num_doubles = 0; | 2847 | int num_doubles = 0; |
2718 | struct btrfs_disk_key disk_key; | ||
2719 | 2848 | ||
2720 | /* first try to make some room by pushing left and right */ | 2849 | /* first try to make some room by pushing left and right */ |
2721 | if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { | 2850 | if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { |
@@ -2767,11 +2896,14 @@ again: | |||
2767 | write_extent_buffer(right, root->fs_info->chunk_tree_uuid, | 2896 | write_extent_buffer(right, root->fs_info->chunk_tree_uuid, |
2768 | (unsigned long)btrfs_header_chunk_tree_uuid(right), | 2897 | (unsigned long)btrfs_header_chunk_tree_uuid(right), |
2769 | BTRFS_UUID_SIZE); | 2898 | BTRFS_UUID_SIZE); |
2899 | |||
2770 | if (mid <= slot) { | 2900 | if (mid <= slot) { |
2771 | if (nritems == 1 || | 2901 | if (nritems == 1 || |
2772 | leaf_space_used(l, mid, nritems - mid) + data_size > | 2902 | leaf_space_used(l, mid, nritems - mid) + data_size > |
2773 | BTRFS_LEAF_DATA_SIZE(root)) { | 2903 | BTRFS_LEAF_DATA_SIZE(root)) { |
2774 | if (slot >= nritems) { | 2904 | if (slot >= nritems) { |
2905 | struct btrfs_disk_key disk_key; | ||
2906 | |||
2775 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | 2907 | btrfs_cpu_key_to_disk(&disk_key, ins_key); |
2776 | btrfs_set_header_nritems(right, 0); | 2908 | btrfs_set_header_nritems(right, 0); |
2777 | wret = insert_ptr(trans, root, path, | 2909 | wret = insert_ptr(trans, root, path, |
@@ -2799,6 +2931,8 @@ again: | |||
2799 | if (leaf_space_used(l, 0, mid) + data_size > | 2931 | if (leaf_space_used(l, 0, mid) + data_size > |
2800 | BTRFS_LEAF_DATA_SIZE(root)) { | 2932 | BTRFS_LEAF_DATA_SIZE(root)) { |
2801 | if (!extend && data_size && slot == 0) { | 2933 | if (!extend && data_size && slot == 0) { |
2934 | struct btrfs_disk_key disk_key; | ||
2935 | |||
2802 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | 2936 | btrfs_cpu_key_to_disk(&disk_key, ins_key); |
2803 | btrfs_set_header_nritems(right, 0); | 2937 | btrfs_set_header_nritems(right, 0); |
2804 | wret = insert_ptr(trans, root, path, | 2938 | wret = insert_ptr(trans, root, path, |
@@ -2831,76 +2965,16 @@ again: | |||
2831 | } | 2965 | } |
2832 | } | 2966 | } |
2833 | } | 2967 | } |
2834 | nritems = nritems - mid; | ||
2835 | btrfs_set_header_nritems(right, nritems); | ||
2836 | data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); | ||
2837 | |||
2838 | copy_extent_buffer(right, l, btrfs_item_nr_offset(0), | ||
2839 | btrfs_item_nr_offset(mid), | ||
2840 | nritems * sizeof(struct btrfs_item)); | ||
2841 | |||
2842 | copy_extent_buffer(right, l, | ||
2843 | btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - | ||
2844 | data_copy_size, btrfs_leaf_data(l) + | ||
2845 | leaf_data_end(root, l), data_copy_size); | ||
2846 | |||
2847 | rt_data_off = BTRFS_LEAF_DATA_SIZE(root) - | ||
2848 | btrfs_item_end_nr(l, mid); | ||
2849 | 2968 | ||
2850 | for (i = 0; i < nritems; i++) { | 2969 | ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems); |
2851 | struct btrfs_item *item = btrfs_item_nr(right, i); | ||
2852 | u32 ioff; | ||
2853 | |||
2854 | if (!right->map_token) { | ||
2855 | map_extent_buffer(right, (unsigned long)item, | ||
2856 | sizeof(struct btrfs_item), | ||
2857 | &right->map_token, &right->kaddr, | ||
2858 | &right->map_start, &right->map_len, | ||
2859 | KM_USER1); | ||
2860 | } | ||
2861 | |||
2862 | ioff = btrfs_item_offset(right, item); | ||
2863 | btrfs_set_item_offset(right, item, ioff + rt_data_off); | ||
2864 | } | ||
2865 | |||
2866 | if (right->map_token) { | ||
2867 | unmap_extent_buffer(right, right->map_token, KM_USER1); | ||
2868 | right->map_token = NULL; | ||
2869 | } | ||
2870 | |||
2871 | btrfs_set_header_nritems(l, mid); | ||
2872 | ret = 0; | ||
2873 | btrfs_item_key(right, &disk_key, 0); | ||
2874 | wret = insert_ptr(trans, root, path, &disk_key, right->start, | ||
2875 | path->slots[1] + 1, 1); | ||
2876 | if (wret) | ||
2877 | ret = wret; | ||
2878 | |||
2879 | btrfs_mark_buffer_dirty(right); | ||
2880 | btrfs_mark_buffer_dirty(l); | ||
2881 | BUG_ON(path->slots[0] != slot); | ||
2882 | |||
2883 | ret = btrfs_update_ref(trans, root, l, right, 0, nritems); | ||
2884 | BUG_ON(ret); | 2970 | BUG_ON(ret); |
2885 | 2971 | ||
2886 | if (mid <= slot) { | ||
2887 | btrfs_tree_unlock(path->nodes[0]); | ||
2888 | free_extent_buffer(path->nodes[0]); | ||
2889 | path->nodes[0] = right; | ||
2890 | path->slots[0] -= mid; | ||
2891 | path->slots[1] += 1; | ||
2892 | } else { | ||
2893 | btrfs_tree_unlock(right); | ||
2894 | free_extent_buffer(right); | ||
2895 | } | ||
2896 | |||
2897 | BUG_ON(path->slots[0] < 0); | ||
2898 | |||
2899 | if (double_split) { | 2972 | if (double_split) { |
2900 | BUG_ON(num_doubles != 0); | 2973 | BUG_ON(num_doubles != 0); |
2901 | num_doubles++; | 2974 | num_doubles++; |
2902 | goto again; | 2975 | goto again; |
2903 | } | 2976 | } |
2977 | |||
2904 | return ret; | 2978 | return ret; |
2905 | } | 2979 | } |
2906 | 2980 | ||
@@ -3382,39 +3456,27 @@ out: | |||
3382 | } | 3456 | } |
3383 | 3457 | ||
3384 | /* | 3458 | /* |
3385 | * Given a key and some data, insert items into the tree. | 3459 | * this is a helper for btrfs_insert_empty_items, the main goal here is |
3386 | * This does all the path init required, making room in the tree if needed. | 3460 | * to save stack depth by doing the bulk of the work in a function |
3461 | * that doesn't call btrfs_search_slot | ||
3387 | */ | 3462 | */ |
3388 | int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | 3463 | static noinline_for_stack int |
3389 | struct btrfs_root *root, | 3464 | setup_items_for_insert(struct btrfs_trans_handle *trans, |
3390 | struct btrfs_path *path, | 3465 | struct btrfs_root *root, struct btrfs_path *path, |
3391 | struct btrfs_key *cpu_key, u32 *data_size, | 3466 | struct btrfs_key *cpu_key, u32 *data_size, |
3392 | int nr) | 3467 | u32 total_data, u32 total_size, int nr) |
3393 | { | 3468 | { |
3394 | struct extent_buffer *leaf; | ||
3395 | struct btrfs_item *item; | 3469 | struct btrfs_item *item; |
3396 | int ret = 0; | ||
3397 | int slot; | ||
3398 | int slot_orig; | ||
3399 | int i; | 3470 | int i; |
3400 | u32 nritems; | 3471 | u32 nritems; |
3401 | u32 total_size = 0; | ||
3402 | u32 total_data = 0; | ||
3403 | unsigned int data_end; | 3472 | unsigned int data_end; |
3404 | struct btrfs_disk_key disk_key; | 3473 | struct btrfs_disk_key disk_key; |
3474 | int ret; | ||
3475 | struct extent_buffer *leaf; | ||
3476 | int slot; | ||
3405 | 3477 | ||
3406 | for (i = 0; i < nr; i++) | ||
3407 | total_data += data_size[i]; | ||
3408 | |||
3409 | total_size = total_data + (nr * sizeof(struct btrfs_item)); | ||
3410 | ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); | ||
3411 | if (ret == 0) | ||
3412 | return -EEXIST; | ||
3413 | if (ret < 0) | ||
3414 | goto out; | ||
3415 | |||
3416 | slot_orig = path->slots[0]; | ||
3417 | leaf = path->nodes[0]; | 3478 | leaf = path->nodes[0]; |
3479 | slot = path->slots[0]; | ||
3418 | 3480 | ||
3419 | nritems = btrfs_header_nritems(leaf); | 3481 | nritems = btrfs_header_nritems(leaf); |
3420 | data_end = leaf_data_end(root, leaf); | 3482 | data_end = leaf_data_end(root, leaf); |
@@ -3426,9 +3488,6 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
3426 | BUG(); | 3488 | BUG(); |
3427 | } | 3489 | } |
3428 | 3490 | ||
3429 | slot = path->slots[0]; | ||
3430 | BUG_ON(slot < 0); | ||
3431 | |||
3432 | if (slot != nritems) { | 3491 | if (slot != nritems) { |
3433 | unsigned int old_data = btrfs_item_end_nr(leaf, slot); | 3492 | unsigned int old_data = btrfs_item_end_nr(leaf, slot); |
3434 | 3493 | ||
@@ -3484,11 +3543,13 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
3484 | data_end -= data_size[i]; | 3543 | data_end -= data_size[i]; |
3485 | btrfs_set_item_size(leaf, item, data_size[i]); | 3544 | btrfs_set_item_size(leaf, item, data_size[i]); |
3486 | } | 3545 | } |
3546 | |||
3487 | btrfs_set_header_nritems(leaf, nritems + nr); | 3547 | btrfs_set_header_nritems(leaf, nritems + nr); |
3488 | btrfs_mark_buffer_dirty(leaf); | 3548 | btrfs_mark_buffer_dirty(leaf); |
3489 | 3549 | ||
3490 | ret = 0; | 3550 | ret = 0; |
3491 | if (slot == 0) { | 3551 | if (slot == 0) { |
3552 | struct btrfs_disk_key disk_key; | ||
3492 | btrfs_cpu_key_to_disk(&disk_key, cpu_key); | 3553 | btrfs_cpu_key_to_disk(&disk_key, cpu_key); |
3493 | ret = fixup_low_keys(trans, root, path, &disk_key, 1); | 3554 | ret = fixup_low_keys(trans, root, path, &disk_key, 1); |
3494 | } | 3555 | } |
@@ -3497,6 +3558,43 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
3497 | btrfs_print_leaf(root, leaf); | 3558 | btrfs_print_leaf(root, leaf); |
3498 | BUG(); | 3559 | BUG(); |
3499 | } | 3560 | } |
3561 | return ret; | ||
3562 | } | ||
3563 | |||
3564 | /* | ||
3565 | * Given a key and some data, insert items into the tree. | ||
3566 | * This does all the path init required, making room in the tree if needed. | ||
3567 | */ | ||
3568 | int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | ||
3569 | struct btrfs_root *root, | ||
3570 | struct btrfs_path *path, | ||
3571 | struct btrfs_key *cpu_key, u32 *data_size, | ||
3572 | int nr) | ||
3573 | { | ||
3574 | struct extent_buffer *leaf; | ||
3575 | int ret = 0; | ||
3576 | int slot; | ||
3577 | int i; | ||
3578 | u32 total_size = 0; | ||
3579 | u32 total_data = 0; | ||
3580 | |||
3581 | for (i = 0; i < nr; i++) | ||
3582 | total_data += data_size[i]; | ||
3583 | |||
3584 | total_size = total_data + (nr * sizeof(struct btrfs_item)); | ||
3585 | ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); | ||
3586 | if (ret == 0) | ||
3587 | return -EEXIST; | ||
3588 | if (ret < 0) | ||
3589 | goto out; | ||
3590 | |||
3591 | leaf = path->nodes[0]; | ||
3592 | slot = path->slots[0]; | ||
3593 | BUG_ON(slot < 0); | ||
3594 | |||
3595 | ret = setup_items_for_insert(trans, root, path, cpu_key, data_size, | ||
3596 | total_data, total_size, nr); | ||
3597 | |||
3500 | out: | 3598 | out: |
3501 | btrfs_unlock_up_safe(path, 1); | 3599 | btrfs_unlock_up_safe(path, 1); |
3502 | return ret; | 3600 | return ret; |