Skip to content

Commit

Permalink
Btrfs: Update clone file ioctl
Browse files Browse the repository at this point in the history
This patch updates the file clone ioctl for the tree locking and new
data ordered code.

---

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Yan Zheng authored and Chris Mason committed Sep 25, 2008
1 parent b48652c commit ae01a0a
Showing 1 changed file with 70 additions and 80 deletions.
150 changes: 70 additions & 80 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,55 +517,48 @@ long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
return ret;
}

int dup_item_to_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct extent_buffer *leaf,
int slot,
struct btrfs_key *key,
u64 destino)
{
char *dup;
int len = btrfs_item_size_nr(leaf, slot);
struct btrfs_key ckey = *key;
int ret = 0;

dup = kmalloc(len, GFP_NOFS);
if (!dup)
return -ENOMEM;

read_extent_buffer(leaf, dup, btrfs_item_ptr_offset(leaf, slot), len);
btrfs_release_path(root, path);

ckey.objectid = destino;
ret = btrfs_insert_item(trans, root, &ckey, dup, len);
kfree(dup);
return ret;
}

long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
{
struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct file *src_file;
struct inode *src;
struct btrfs_trans_handle *trans;
int ret;
u64 pos;
struct btrfs_ordered_extent *ordered;
struct btrfs_path *path;
struct btrfs_key key;
struct extent_buffer *leaf;
char *buf;
struct btrfs_key key;
struct btrfs_key new_key;
u32 size;
u32 nritems;
int slot;
int ret;

src_file = fget(src_fd);
if (!src_file)
return -EBADF;
src = src_file->f_dentry->d_inode;

ret = -EISDIR;
if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
goto out_fput;

ret = -EXDEV;
if (src->i_sb != inode->i_sb)
if (src->i_sb != inode->i_sb || BTRFS_I(src)->root != root)
goto out_fput;

ret = -ENOMEM;
buf = vmalloc(btrfs_level_size(root, 0));
if (!buf)
goto out_fput;

path = btrfs_alloc_path();
if (!path) {
vfree(buf);
goto out_fput;
}
path->reada = 2;

if (inode < src) {
mutex_lock(&inode->i_mutex);
Expand All @@ -582,24 +575,22 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
/* do any pending delalloc/csum calc on src, one way or
another, and lock file content */
while (1) {
filemap_write_and_wait(src->i_mapping);
lock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
if (BTRFS_I(src)->delalloc_bytes == 0)
ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered)
break;
unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
if (ordered)
btrfs_put_ordered_extent(ordered);
btrfs_wait_ordered_range(src, 0, (u64)-1);
}

trans = btrfs_start_transaction(root, 0);
path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto out;
}
key.offset = 0;
key.type = BTRFS_EXTENT_DATA_KEY;
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);

key.objectid = src->i_ino;
pos = 0;
path->reada = 2;
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = 0;

while (1) {
/*
Expand All @@ -610,85 +601,84 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
if (ret < 0)
goto out;

if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
nritems = btrfs_header_nritems(path->nodes[0]);
if (path->slots[0] >= nritems) {
ret = btrfs_next_leaf(root, path);
if (ret < 0)
goto out;
if (ret > 0)
break;
nritems = btrfs_header_nritems(path->nodes[0]);
}
leaf = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(leaf, &key, slot);
nritems = btrfs_header_nritems(leaf);

btrfs_item_key_to_cpu(leaf, &key, slot);
if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY ||
key.objectid != src->i_ino)
break;

if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
struct btrfs_file_extent_item *extent;
int found_type;
pos = key.offset;

extent = btrfs_item_ptr(leaf, slot,
struct btrfs_file_extent_item);
found_type = btrfs_file_extent_type(leaf, extent);
if (found_type == BTRFS_FILE_EXTENT_REG) {
u64 len = btrfs_file_extent_num_bytes(leaf,
extent);
u64 ds = btrfs_file_extent_disk_bytenr(leaf,
extent);
u64 dl = btrfs_file_extent_disk_num_bytes(leaf,
extent);
u64 off = btrfs_file_extent_offset(leaf,
extent);
btrfs_insert_file_extent(trans, root,
inode->i_ino, pos,
ds, dl, len, off);
/* ds == 0 means there's a hole */
if (ds != 0) {
btrfs_inc_extent_ref(trans, root,
ret = btrfs_inc_extent_ref(trans, root,
ds, dl,
root->root_key.objectid,
trans->transid,
inode->i_ino, pos);
inode->i_ino, key.offset);
if (ret)
goto out;
}
pos = key.offset + len;
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
ret = dup_item_to_inode(trans, root, path,
leaf, slot, &key,
inode->i_ino);
if (ret)
goto out;
pos = key.offset + btrfs_item_size_nr(leaf,
slot);
}
} else if (btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) {
ret = dup_item_to_inode(trans, root, path, leaf,
slot, &key, inode->i_ino);
}

if (ret)
goto out;
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY ||
btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) {
size = btrfs_item_size_nr(leaf, slot);
read_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, slot),
size);
btrfs_release_path(root, path);
memcpy(&new_key, &key, sizeof(new_key));
new_key.objectid = inode->i_ino;
ret = btrfs_insert_item(trans, root, &new_key,
buf, size);
BUG_ON(ret);
} else {
btrfs_release_path(root, path);
}
key.offset++;
btrfs_release_path(root, path);
}

ret = 0;
out:
btrfs_free_path(path);

inode->i_blocks = src->i_blocks;
i_size_write(inode, src->i_size);
btrfs_update_inode(trans, root, inode);

unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);

btrfs_release_path(root, path);
if (ret == 0) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = src->i_blocks;
btrfs_i_size_write(inode, src->i_size);
BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
ret = btrfs_update_inode(trans, root, inode);
}
btrfs_end_transaction(trans, root);

unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
if (ret)
vmtruncate(inode, 0);
out_unlock:
mutex_unlock(&src->i_mutex);
mutex_unlock(&inode->i_mutex);
vfree(buf);
btrfs_free_path(path);
out_fput:
fput(src_file);
return ret;
Expand Down

0 comments on commit ae01a0a

Please sign in to comment.