diff options
-rw-r--r-- | fs/btrfs/ctree.c | 198 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 4 |
2 files changed, 143 insertions, 59 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ec96f3a6d536..9d4ba3470c17 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -37,6 +37,11 @@ static int balance_node_right(struct btrfs_trans_handle *trans, | |||
37 | struct extent_buffer *src_buf); | 37 | struct extent_buffer *src_buf); |
38 | static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 38 | static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
39 | struct btrfs_path *path, int level, int slot); | 39 | struct btrfs_path *path, int level, int slot); |
40 | static int setup_items_for_insert(struct btrfs_trans_handle *trans, | ||
41 | struct btrfs_root *root, struct btrfs_path *path, | ||
42 | struct btrfs_key *cpu_key, u32 *data_size, | ||
43 | u32 total_data, u32 total_size, int nr); | ||
44 | |||
40 | 45 | ||
41 | struct btrfs_path *btrfs_alloc_path(void) | 46 | struct btrfs_path *btrfs_alloc_path(void) |
42 | { | 47 | { |
@@ -2997,75 +3002,85 @@ again: | |||
2997 | return ret; | 3002 | return ret; |
2998 | } | 3003 | } |
2999 | 3004 | ||
3000 | /* | 3005 | static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, |
3001 | * This function splits a single item into two items, | 3006 | struct btrfs_root *root, |
3002 | * giving 'new_key' to the new item and splitting the | 3007 | struct btrfs_path *path, int ins_len) |
3003 | * old one at split_offset (from the start of the item). | ||
3004 | * | ||
3005 | * The path may be released by this operation. After | ||
3006 | * the split, the path is pointing to the old item. The | ||
3007 | * new item is going to be in the same node as the old one. | ||
3008 | * | ||
3009 | * Note, the item being split must be smaller enough to live alone on | ||
3010 | * a tree block with room for one extra struct btrfs_item | ||
3011 | * | ||
3012 | * This allows us to split the item in place, keeping a lock on the | ||
3013 | * leaf the entire time. | ||
3014 | */ | ||
3015 | int btrfs_split_item(struct btrfs_trans_handle *trans, | ||
3016 | struct btrfs_root *root, | ||
3017 | struct btrfs_path *path, | ||
3018 | struct btrfs_key *new_key, | ||
3019 | unsigned long split_offset) | ||
3020 | { | 3008 | { |
3021 | u32 item_size; | 3009 | struct btrfs_key key; |
3022 | struct extent_buffer *leaf; | 3010 | struct extent_buffer *leaf; |
3023 | struct btrfs_key orig_key; | 3011 | struct btrfs_file_extent_item *fi; |
3024 | struct btrfs_item *item; | 3012 | u64 extent_len = 0; |
3025 | struct btrfs_item *new_item; | 3013 | u32 item_size; |
3026 | int ret = 0; | 3014 | int ret; |
3027 | int slot; | ||
3028 | u32 nritems; | ||
3029 | u32 orig_offset; | ||
3030 | struct btrfs_disk_key disk_key; | ||
3031 | char *buf; | ||
3032 | 3015 | ||
3033 | leaf = path->nodes[0]; | 3016 | leaf = path->nodes[0]; |
3034 | btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]); | 3017 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); |
3035 | if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item)) | 3018 | |
3036 | goto split; | 3019 | BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY && |
3020 | key.type != BTRFS_EXTENT_CSUM_KEY); | ||
3021 | |||
3022 | if (btrfs_leaf_free_space(root, leaf) >= ins_len) | ||
3023 | return 0; | ||
3037 | 3024 | ||
3038 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | 3025 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); |
3026 | if (key.type == BTRFS_EXTENT_DATA_KEY) { | ||
3027 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3028 | struct btrfs_file_extent_item); | ||
3029 | extent_len = btrfs_file_extent_num_bytes(leaf, fi); | ||
3030 | } | ||
3039 | btrfs_release_path(root, path); | 3031 | btrfs_release_path(root, path); |
3040 | 3032 | ||
3041 | path->search_for_split = 1; | ||
3042 | path->keep_locks = 1; | 3033 | path->keep_locks = 1; |
3043 | 3034 | path->search_for_split = 1; | |
3044 | ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1); | 3035 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
3045 | path->search_for_split = 0; | 3036 | path->search_for_split = 0; |
3037 | if (ret < 0) | ||
3038 | goto err; | ||
3046 | 3039 | ||
3040 | ret = -EAGAIN; | ||
3041 | leaf = path->nodes[0]; | ||
3047 | /* if our item isn't there or got smaller, return now */ | 3042 | /* if our item isn't there or got smaller, return now */ |
3048 | if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0], | 3043 | if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0])) |
3049 | path->slots[0])) { | 3044 | goto err; |
3050 | path->keep_locks = 0; | 3045 | |
3051 | return -EAGAIN; | 3046 | if (key.type == BTRFS_EXTENT_DATA_KEY) { |
3047 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3048 | struct btrfs_file_extent_item); | ||
3049 | if (extent_len != btrfs_file_extent_num_bytes(leaf, fi)) | ||
3050 | goto err; | ||
3052 | } | 3051 | } |
3053 | 3052 | ||
3054 | btrfs_set_path_blocking(path); | 3053 | btrfs_set_path_blocking(path); |
3055 | ret = split_leaf(trans, root, &orig_key, path, | 3054 | ret = split_leaf(trans, root, &key, path, ins_len, 1); |
3056 | sizeof(struct btrfs_item), 1); | ||
3057 | path->keep_locks = 0; | ||
3058 | BUG_ON(ret); | 3055 | BUG_ON(ret); |
3059 | 3056 | ||
3057 | path->keep_locks = 0; | ||
3060 | btrfs_unlock_up_safe(path, 1); | 3058 | btrfs_unlock_up_safe(path, 1); |
3059 | return 0; | ||
3060 | err: | ||
3061 | path->keep_locks = 0; | ||
3062 | return ret; | ||
3063 | } | ||
3064 | |||
3065 | static noinline int split_item(struct btrfs_trans_handle *trans, | ||
3066 | struct btrfs_root *root, | ||
3067 | struct btrfs_path *path, | ||
3068 | struct btrfs_key *new_key, | ||
3069 | unsigned long split_offset) | ||
3070 | { | ||
3071 | struct extent_buffer *leaf; | ||
3072 | struct btrfs_item *item; | ||
3073 | struct btrfs_item *new_item; | ||
3074 | int slot; | ||
3075 | char *buf; | ||
3076 | u32 nritems; | ||
3077 | u32 item_size; | ||
3078 | u32 orig_offset; | ||
3079 | struct btrfs_disk_key disk_key; | ||
3080 | |||
3061 | leaf = path->nodes[0]; | 3081 | leaf = path->nodes[0]; |
3062 | BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); | 3082 | BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); |
3063 | 3083 | ||
3064 | split: | ||
3065 | /* | ||
3066 | * make sure any changes to the path from split_leaf leave it | ||
3067 | * in a blocking state | ||
3068 | */ | ||
3069 | btrfs_set_path_blocking(path); | 3084 | btrfs_set_path_blocking(path); |
3070 | 3085 | ||
3071 | item = btrfs_item_nr(leaf, path->slots[0]); | 3086 | item = btrfs_item_nr(leaf, path->slots[0]); |
@@ -3073,19 +3088,19 @@ split: | |||
3073 | item_size = btrfs_item_size(leaf, item); | 3088 | item_size = btrfs_item_size(leaf, item); |
3074 | 3089 | ||
3075 | buf = kmalloc(item_size, GFP_NOFS); | 3090 | buf = kmalloc(item_size, GFP_NOFS); |
3091 | if (!buf) | ||
3092 | return -ENOMEM; | ||
3093 | |||
3076 | read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, | 3094 | read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, |
3077 | path->slots[0]), item_size); | 3095 | path->slots[0]), item_size); |
3078 | slot = path->slots[0] + 1; | ||
3079 | leaf = path->nodes[0]; | ||
3080 | 3096 | ||
3097 | slot = path->slots[0] + 1; | ||
3081 | nritems = btrfs_header_nritems(leaf); | 3098 | nritems = btrfs_header_nritems(leaf); |
3082 | |||
3083 | if (slot != nritems) { | 3099 | if (slot != nritems) { |
3084 | /* shift the items */ | 3100 | /* shift the items */ |
3085 | memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), | 3101 | memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), |
3086 | btrfs_item_nr_offset(slot), | 3102 | btrfs_item_nr_offset(slot), |
3087 | (nritems - slot) * sizeof(struct btrfs_item)); | 3103 | (nritems - slot) * sizeof(struct btrfs_item)); |
3088 | |||
3089 | } | 3104 | } |
3090 | 3105 | ||
3091 | btrfs_cpu_key_to_disk(&disk_key, new_key); | 3106 | btrfs_cpu_key_to_disk(&disk_key, new_key); |
@@ -3113,16 +3128,81 @@ split: | |||
3113 | item_size - split_offset); | 3128 | item_size - split_offset); |
3114 | btrfs_mark_buffer_dirty(leaf); | 3129 | btrfs_mark_buffer_dirty(leaf); |
3115 | 3130 | ||
3116 | ret = 0; | 3131 | BUG_ON(btrfs_leaf_free_space(root, leaf) < 0); |
3117 | if (btrfs_leaf_free_space(root, leaf) < 0) { | ||
3118 | btrfs_print_leaf(root, leaf); | ||
3119 | BUG(); | ||
3120 | } | ||
3121 | kfree(buf); | 3132 | kfree(buf); |
3133 | return 0; | ||
3134 | } | ||
3135 | |||
3136 | /* | ||
3137 | * This function splits a single item into two items, | ||
3138 | * giving 'new_key' to the new item and splitting the | ||
3139 | * old one at split_offset (from the start of the item). | ||
3140 | * | ||
3141 | * The path may be released by this operation. After | ||
3142 | * the split, the path is pointing to the old item. The | ||
3143 | * new item is going to be in the same node as the old one. | ||
3144 | * | ||
3145 | * Note, the item being split must be smaller enough to live alone on | ||
3146 | * a tree block with room for one extra struct btrfs_item | ||
3147 | * | ||
3148 | * This allows us to split the item in place, keeping a lock on the | ||
3149 | * leaf the entire time. | ||
3150 | */ | ||
3151 | int btrfs_split_item(struct btrfs_trans_handle *trans, | ||
3152 | struct btrfs_root *root, | ||
3153 | struct btrfs_path *path, | ||
3154 | struct btrfs_key *new_key, | ||
3155 | unsigned long split_offset) | ||
3156 | { | ||
3157 | int ret; | ||
3158 | ret = setup_leaf_for_split(trans, root, path, | ||
3159 | sizeof(struct btrfs_item)); | ||
3160 | if (ret) | ||
3161 | return ret; | ||
3162 | |||
3163 | ret = split_item(trans, root, path, new_key, split_offset); | ||
3122 | return ret; | 3164 | return ret; |
3123 | } | 3165 | } |
3124 | 3166 | ||
3125 | /* | 3167 | /* |
3168 | * This function duplicate a item, giving 'new_key' to the new item. | ||
3169 | * It guarantees both items live in the same tree leaf and the new item | ||
3170 | * is contiguous with the original item. | ||
3171 | * | ||
3172 | * This allows us to split file extent in place, keeping a lock on the | ||
3173 | * leaf the entire time. | ||
3174 | */ | ||
3175 | int btrfs_duplicate_item(struct btrfs_trans_handle *trans, | ||
3176 | struct btrfs_root *root, | ||
3177 | struct btrfs_path *path, | ||
3178 | struct btrfs_key *new_key) | ||
3179 | { | ||
3180 | struct extent_buffer *leaf; | ||
3181 | int ret; | ||
3182 | u32 item_size; | ||
3183 | |||
3184 | leaf = path->nodes[0]; | ||
3185 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
3186 | ret = setup_leaf_for_split(trans, root, path, | ||
3187 | item_size + sizeof(struct btrfs_item)); | ||
3188 | if (ret) | ||
3189 | return ret; | ||
3190 | |||
3191 | path->slots[0]++; | ||
3192 | ret = setup_items_for_insert(trans, root, path, new_key, &item_size, | ||
3193 | item_size, item_size + | ||
3194 | sizeof(struct btrfs_item), 1); | ||
3195 | BUG_ON(ret); | ||
3196 | |||
3197 | leaf = path->nodes[0]; | ||
3198 | memcpy_extent_buffer(leaf, | ||
3199 | btrfs_item_ptr_offset(leaf, path->slots[0]), | ||
3200 | btrfs_item_ptr_offset(leaf, path->slots[0] - 1), | ||
3201 | item_size); | ||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3205 | /* | ||
3126 | * make the item pointed to by the path smaller. new_size indicates | 3206 | * make the item pointed to by the path smaller. new_size indicates |
3127 | * how small to make it, and from_end tells us if we just chop bytes | 3207 | * how small to make it, and from_end tells us if we just chop bytes |
3128 | * off the end of the item or if we shift the item to chop bytes off | 3208 | * off the end of the item or if we shift the item to chop bytes off |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 444b3e9b92a4..e3b58001162d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2089,6 +2089,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans, | |||
2089 | struct btrfs_path *path, | 2089 | struct btrfs_path *path, |
2090 | struct btrfs_key *new_key, | 2090 | struct btrfs_key *new_key, |
2091 | unsigned long split_offset); | 2091 | unsigned long split_offset); |
2092 | int btrfs_duplicate_item(struct btrfs_trans_handle *trans, | ||
2093 | struct btrfs_root *root, | ||
2094 | struct btrfs_path *path, | ||
2095 | struct btrfs_key *new_key); | ||
2092 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | 2096 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root |
2093 | *root, struct btrfs_key *key, struct btrfs_path *p, int | 2097 | *root, struct btrfs_key *key, struct btrfs_path *p, int |
2094 | ins_len, int cow); | 2098 | ins_len, int cow); |