diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 131 |
1 files changed, 125 insertions, 6 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 19c0dd33b1e8..c0c95cccbb5b 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -1512,7 +1512,8 @@ cow_done: | |||
1512 | if (ret && slot > 0) | 1512 | if (ret && slot > 0) |
1513 | slot -= 1; | 1513 | slot -= 1; |
1514 | p->slots[level] = slot; | 1514 | p->slots[level] = slot; |
1515 | if (ins_len > 0 && btrfs_header_nritems(b) >= | 1515 | if ((p->search_for_split || ins_len > 0) && |
1516 | btrfs_header_nritems(b) >= | ||
1516 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { | 1517 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { |
1517 | int sret = split_node(trans, root, p, level); | 1518 | int sret = split_node(trans, root, p, level); |
1518 | BUG_ON(sret > 0); | 1519 | BUG_ON(sret > 0); |
@@ -1596,7 +1597,8 @@ cow_done: | |||
1596 | goto done; | 1597 | goto done; |
1597 | } | 1598 | } |
1598 | } | 1599 | } |
1599 | unlock_up(p, level, lowest_unlock); | 1600 | if (!p->search_for_split) |
1601 | unlock_up(p, level, lowest_unlock); | ||
1600 | goto done; | 1602 | goto done; |
1601 | } | 1603 | } |
1602 | } | 1604 | } |
@@ -2636,11 +2638,11 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, | |||
2636 | int num_doubles = 0; | 2638 | int num_doubles = 0; |
2637 | struct btrfs_disk_key disk_key; | 2639 | struct btrfs_disk_key disk_key; |
2638 | 2640 | ||
2639 | if (extend) | 2641 | if (extend && data_size) |
2640 | space_needed = data_size; | 2642 | space_needed = data_size; |
2641 | 2643 | ||
2642 | /* first try to make some room by pushing left and right */ | 2644 | /* first try to make some room by pushing left and right */ |
2643 | if (ins_key->type != BTRFS_DIR_ITEM_KEY) { | 2645 | if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { |
2644 | wret = push_leaf_right(trans, root, path, data_size, 0); | 2646 | wret = push_leaf_right(trans, root, path, data_size, 0); |
2645 | if (wret < 0) { | 2647 | if (wret < 0) { |
2646 | return wret; | 2648 | return wret; |
@@ -2721,7 +2723,7 @@ again: | |||
2721 | } else { | 2723 | } else { |
2722 | if (leaf_space_used(l, 0, mid + 1) + space_needed > | 2724 | if (leaf_space_used(l, 0, mid + 1) + space_needed > |
2723 | BTRFS_LEAF_DATA_SIZE(root)) { | 2725 | BTRFS_LEAF_DATA_SIZE(root)) { |
2724 | if (!extend && slot == 0) { | 2726 | if (!extend && data_size && slot == 0) { |
2725 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | 2727 | btrfs_cpu_key_to_disk(&disk_key, ins_key); |
2726 | btrfs_set_header_nritems(right, 0); | 2728 | btrfs_set_header_nritems(right, 0); |
2727 | wret = insert_ptr(trans, root, path, | 2729 | wret = insert_ptr(trans, root, path, |
@@ -2742,7 +2744,7 @@ again: | |||
2742 | } | 2744 | } |
2743 | btrfs_mark_buffer_dirty(right); | 2745 | btrfs_mark_buffer_dirty(right); |
2744 | return ret; | 2746 | return ret; |
2745 | } else if (extend && slot == 0) { | 2747 | } else if ((extend || !data_size) && slot == 0) { |
2746 | mid = 1; | 2748 | mid = 1; |
2747 | } else { | 2749 | } else { |
2748 | mid = slot; | 2750 | mid = slot; |
@@ -2828,6 +2830,123 @@ again: | |||
2828 | } | 2830 | } |
2829 | 2831 | ||
2830 | /* | 2832 | /* |
2833 | * This function splits a single item into two items, | ||
2834 | * giving 'new_key' to the new item and splitting the | ||
2835 | * old one at split_offset (from the start of the item). | ||
2836 | * | ||
2837 | * The path may be released by this operation. After | ||
2838 | * the split, the path is pointing to the old item. The | ||
2839 | * new item is going to be in the same node as the old one. | ||
2840 | * | ||
2841 | * Note, the item being split must be smaller enough to live alone on | ||
2842 | * a tree block with room for one extra struct btrfs_item | ||
2843 | * | ||
2844 | * This allows us to split the item in place, keeping a lock on the | ||
2845 | * leaf the entire time. | ||
2846 | */ | ||
2847 | int btrfs_split_item(struct btrfs_trans_handle *trans, | ||
2848 | struct btrfs_root *root, | ||
2849 | struct btrfs_path *path, | ||
2850 | struct btrfs_key *new_key, | ||
2851 | unsigned long split_offset) | ||
2852 | { | ||
2853 | u32 item_size; | ||
2854 | struct extent_buffer *leaf; | ||
2855 | struct btrfs_key orig_key; | ||
2856 | struct btrfs_item *item; | ||
2857 | struct btrfs_item *new_item; | ||
2858 | int ret = 0; | ||
2859 | int slot; | ||
2860 | u32 nritems; | ||
2861 | u32 orig_offset; | ||
2862 | struct btrfs_disk_key disk_key; | ||
2863 | char *buf; | ||
2864 | |||
2865 | leaf = path->nodes[0]; | ||
2866 | btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]); | ||
2867 | if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item)) | ||
2868 | goto split; | ||
2869 | |||
2870 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
2871 | btrfs_release_path(root, path); | ||
2872 | |||
2873 | path->search_for_split = 1; | ||
2874 | path->keep_locks = 1; | ||
2875 | |||
2876 | ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1); | ||
2877 | path->search_for_split = 0; | ||
2878 | |||
2879 | /* if our item isn't there or got smaller, return now */ | ||
2880 | if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0], | ||
2881 | path->slots[0])) { | ||
2882 | path->keep_locks = 0; | ||
2883 | return -EAGAIN; | ||
2884 | } | ||
2885 | |||
2886 | ret = split_leaf(trans, root, &orig_key, path, 0, 0); | ||
2887 | path->keep_locks = 0; | ||
2888 | BUG_ON(ret); | ||
2889 | |||
2890 | BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); | ||
2891 | leaf = path->nodes[0]; | ||
2892 | |||
2893 | split: | ||
2894 | item = btrfs_item_nr(leaf, path->slots[0]); | ||
2895 | orig_offset = btrfs_item_offset(leaf, item); | ||
2896 | item_size = btrfs_item_size(leaf, item); | ||
2897 | |||
2898 | |||
2899 | buf = kmalloc(item_size, GFP_NOFS); | ||
2900 | read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, | ||
2901 | path->slots[0]), item_size); | ||
2902 | slot = path->slots[0] + 1; | ||
2903 | leaf = path->nodes[0]; | ||
2904 | |||
2905 | nritems = btrfs_header_nritems(leaf); | ||
2906 | |||
2907 | if (slot != nritems) { | ||
2908 | /* shift the items */ | ||
2909 | memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), | ||
2910 | btrfs_item_nr_offset(slot), | ||
2911 | (nritems - slot) * sizeof(struct btrfs_item)); | ||
2912 | |||
2913 | } | ||
2914 | |||
2915 | btrfs_cpu_key_to_disk(&disk_key, new_key); | ||
2916 | btrfs_set_item_key(leaf, &disk_key, slot); | ||
2917 | |||
2918 | new_item = btrfs_item_nr(leaf, slot); | ||
2919 | |||
2920 | btrfs_set_item_offset(leaf, new_item, orig_offset); | ||
2921 | btrfs_set_item_size(leaf, new_item, item_size - split_offset); | ||
2922 | |||
2923 | btrfs_set_item_offset(leaf, item, | ||
2924 | orig_offset + item_size - split_offset); | ||
2925 | btrfs_set_item_size(leaf, item, split_offset); | ||
2926 | |||
2927 | btrfs_set_header_nritems(leaf, nritems + 1); | ||
2928 | |||
2929 | /* write the data for the start of the original item */ | ||
2930 | write_extent_buffer(leaf, buf, | ||
2931 | btrfs_item_ptr_offset(leaf, path->slots[0]), | ||
2932 | split_offset); | ||
2933 | |||
2934 | /* write the data for the new item */ | ||
2935 | write_extent_buffer(leaf, buf + split_offset, | ||
2936 | btrfs_item_ptr_offset(leaf, slot), | ||
2937 | item_size - split_offset); | ||
2938 | btrfs_mark_buffer_dirty(leaf); | ||
2939 | |||
2940 | ret = 0; | ||
2941 | if (btrfs_leaf_free_space(root, leaf) < 0) { | ||
2942 | btrfs_print_leaf(root, leaf); | ||
2943 | BUG(); | ||
2944 | } | ||
2945 | kfree(buf); | ||
2946 | return ret; | ||
2947 | } | ||
2948 | |||
2949 | /* | ||
2831 | * make the item pointed to by the path smaller. new_size indicates | 2950 | * make the item pointed to by the path smaller. new_size indicates |
2832 | * how small to make it, and from_end tells us if we just chop bytes | 2951 | * how small to make it, and from_end tells us if we just chop bytes |
2833 | * off the end of the item or if we shift the item to chop bytes off | 2952 | * off the end of the item or if we shift the item to chop bytes off |