diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-05-05 06:26:21 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
commit | 5d9cd9ecbf40b8bd5045a3c2f1feb35db6a12266 (patch) | |
tree | cbc4df08ed0b34e02e24949b5c114acd8dc6949b /fs/btrfs | |
parent | b9d86667c94e5fe4bf9f6aa500e7ff1138e717ff (diff) |
Btrfs: Fix clone ioctl to not hold the path over inserts
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/inode.c | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5204599e4309..f7beb9b0d37a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3101,7 +3101,7 @@ out: | |||
3101 | return ret; | 3101 | return ret; |
3102 | } | 3102 | } |
3103 | 3103 | ||
3104 | void dup_item_to_inode(struct btrfs_trans_handle *trans, | 3104 | int dup_item_to_inode(struct btrfs_trans_handle *trans, |
3105 | struct btrfs_root *root, | 3105 | struct btrfs_root *root, |
3106 | struct btrfs_path *path, | 3106 | struct btrfs_path *path, |
3107 | struct extent_buffer *leaf, | 3107 | struct extent_buffer *leaf, |
@@ -3109,19 +3109,22 @@ void dup_item_to_inode(struct btrfs_trans_handle *trans, | |||
3109 | struct btrfs_key *key, | 3109 | struct btrfs_key *key, |
3110 | u64 destino) | 3110 | u64 destino) |
3111 | { | 3111 | { |
3112 | struct btrfs_path *cpath = btrfs_alloc_path(); | 3112 | char *dup; |
3113 | int len = btrfs_item_size_nr(leaf, slot); | 3113 | int len = btrfs_item_size_nr(leaf, slot); |
3114 | int dstoff; | ||
3115 | struct btrfs_key ckey = *key; | 3114 | struct btrfs_key ckey = *key; |
3116 | int ret; | 3115 | int ret = 0; |
3116 | |||
3117 | dup = kmalloc(len, GFP_NOFS); | ||
3118 | if (!dup) | ||
3119 | return -ENOMEM; | ||
3120 | |||
3121 | read_extent_buffer(leaf, dup, btrfs_item_ptr_offset(leaf, slot), len); | ||
3122 | btrfs_release_path(root, path); | ||
3117 | 3123 | ||
3118 | ckey.objectid = destino; | 3124 | ckey.objectid = destino; |
3119 | ret = btrfs_insert_empty_item(trans, root, cpath, &ckey, len); | 3125 | ret = btrfs_insert_item(trans, root, &ckey, dup, len); |
3120 | dstoff = btrfs_item_ptr_offset(cpath->nodes[0], cpath->slots[0]); | 3126 | kfree(dup); |
3121 | copy_extent_buffer(cpath->nodes[0], leaf, dstoff, | 3127 | return ret; |
3122 | btrfs_item_ptr_offset(leaf, slot), | ||
3123 | len); | ||
3124 | btrfs_release_path(root, cpath); | ||
3125 | } | 3128 | } |
3126 | 3129 | ||
3127 | long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | 3130 | long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) |
@@ -3137,7 +3140,6 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
3137 | struct btrfs_key key; | 3140 | struct btrfs_key key; |
3138 | struct extent_buffer *leaf; | 3141 | struct extent_buffer *leaf; |
3139 | u32 nritems; | 3142 | u32 nritems; |
3140 | int nextret; | ||
3141 | int slot; | 3143 | int slot; |
3142 | 3144 | ||
3143 | src_file = fget(src_fd); | 3145 | src_file = fget(src_fd); |
@@ -3174,20 +3176,32 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
3174 | mutex_lock(&root->fs_info->fs_mutex); | 3176 | mutex_lock(&root->fs_info->fs_mutex); |
3175 | trans = btrfs_start_transaction(root, 0); | 3177 | trans = btrfs_start_transaction(root, 0); |
3176 | path = btrfs_alloc_path(); | 3178 | path = btrfs_alloc_path(); |
3179 | if (!path) { | ||
3180 | ret = -ENOMEM; | ||
3181 | goto out; | ||
3182 | } | ||
3183 | key.offset = 0; | ||
3184 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3185 | key.objectid = src->i_ino; | ||
3177 | pos = 0; | 3186 | pos = 0; |
3187 | path->reada = 2; | ||
3188 | |||
3178 | while (1) { | 3189 | while (1) { |
3179 | ret = btrfs_lookup_file_extent(trans, root, path, src->i_ino, | 3190 | /* |
3180 | pos, 0); | 3191 | * note the key will change type as we walk through the |
3192 | * tree. | ||
3193 | */ | ||
3194 | ret = btrfs_search_slot(trans, root, &key, path, 0, 0); | ||
3181 | if (ret < 0) | 3195 | if (ret < 0) |
3182 | goto out; | 3196 | goto out; |
3183 | if (ret > 0) { | 3197 | |
3184 | if (path->slots[0] == 0) { | 3198 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { |
3185 | ret = 0; | 3199 | ret = btrfs_next_leaf(root, path); |
3200 | if (ret < 0) | ||
3186 | goto out; | 3201 | goto out; |
3187 | } | 3202 | if (ret > 0) |
3188 | path->slots[0]--; | 3203 | break; |
3189 | } | 3204 | } |
3190 | next_slot: | ||
3191 | leaf = path->nodes[0]; | 3205 | leaf = path->nodes[0]; |
3192 | slot = path->slots[0]; | 3206 | slot = path->slots[0]; |
3193 | btrfs_item_key_to_cpu(leaf, &key, slot); | 3207 | btrfs_item_key_to_cpu(leaf, &key, slot); |
@@ -3195,7 +3209,8 @@ next_slot: | |||
3195 | 3209 | ||
3196 | if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY || | 3210 | if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY || |
3197 | key.objectid != src->i_ino) | 3211 | key.objectid != src->i_ino) |
3198 | goto out; | 3212 | break; |
3213 | |||
3199 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { | 3214 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { |
3200 | struct btrfs_file_extent_item *extent; | 3215 | struct btrfs_file_extent_item *extent; |
3201 | int found_type; | 3216 | int found_type; |
@@ -3225,28 +3240,28 @@ next_slot: | |||
3225 | } | 3240 | } |
3226 | pos = key.offset + len; | 3241 | pos = key.offset + len; |
3227 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 3242 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
3228 | dup_item_to_inode(trans, root, path, leaf, slot, | 3243 | ret = dup_item_to_inode(trans, root, path, |
3229 | &key, inode->i_ino); | 3244 | leaf, slot, &key, |
3245 | inode->i_ino); | ||
3246 | if (ret) | ||
3247 | goto out; | ||
3230 | pos = key.offset + btrfs_item_size_nr(leaf, | 3248 | pos = key.offset + btrfs_item_size_nr(leaf, |
3231 | slot); | 3249 | slot); |
3232 | } | 3250 | } |
3233 | } else if (btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) | 3251 | } else if (btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) { |
3234 | dup_item_to_inode(trans, root, path, leaf, slot, &key, | 3252 | ret = dup_item_to_inode(trans, root, path, leaf, |
3235 | inode->i_ino); | 3253 | slot, &key, inode->i_ino); |
3236 | 3254 | ||
3237 | if (slot >= nritems - 1) { | 3255 | if (ret) |
3238 | nextret = btrfs_next_leaf(root, path); | ||
3239 | if (nextret) | ||
3240 | goto out; | 3256 | goto out; |
3241 | } else { | ||
3242 | path->slots[0]++; | ||
3243 | } | 3257 | } |
3244 | goto next_slot; | 3258 | key.offset++; |
3259 | btrfs_release_path(root, path); | ||
3245 | } | 3260 | } |
3246 | 3261 | ||
3262 | ret = 0; | ||
3247 | out: | 3263 | out: |
3248 | btrfs_free_path(path); | 3264 | btrfs_free_path(path); |
3249 | ret = 0; | ||
3250 | 3265 | ||
3251 | inode->i_blocks = src->i_blocks; | 3266 | inode->i_blocks = src->i_blocks; |
3252 | i_size_write(inode, src->i_size); | 3267 | i_size_write(inode, src->i_size); |