aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-05-05 06:26:21 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commit5d9cd9ecbf40b8bd5045a3c2f1feb35db6a12266 (patch)
treecbc4df08ed0b34e02e24949b5c114acd8dc6949b /fs/btrfs
parentb9d86667c94e5fe4bf9f6aa500e7ff1138e717ff (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.c79
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
3104void dup_item_to_inode(struct btrfs_trans_handle *trans, 3104int 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
3127long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) 3130long 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 }
3190next_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;
3247out: 3263out:
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);