#include <linux/compat.h>
#include <linux/bit_spinlock.h>
#include <linux/security.h>
-#include <linux/version.h>
#include <linux/xattr.h>
#include <linux/vmalloc.h>
#include "compat.h"
if (ret)
goto fail;
+ btrfs_i_size_write(dir, dir->i_size + namelen * 2);
+ ret = btrfs_update_inode(trans, root, dir);
+ BUG_ON(ret);
+
/* add the backref first */
ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
objectid, BTRFS_ROOT_BACKREF_KEY,
trans = btrfs_start_transaction(new_root, 1);
BUG_ON(!trans);
- ret = btrfs_create_subvol_root(new_root, dentry, trans, new_dirid,
+ ret = btrfs_create_subvol_root(trans, new_root, dentry, new_dirid,
BTRFS_I(dir)->block_group);
if (ret)
goto fail;
* to see if is references the subvolume where we are
* placing this new snapshot.
*/
- while(1) {
+ while (1) {
if (!test ||
dir == snap_src->fs_info->sb->s_root ||
test == snap_src->fs_info->sb->s_root ||
break;
}
if (S_ISLNK(test->d_inode->i_mode)) {
- printk("Symlink in snapshot path, failed\n");
+ printk(KERN_INFO "Btrfs symlink in snapshot "
+ "path, failed\n");
error = -EMLINK;
btrfs_free_path(path);
goto out_drop_write;
ret = btrfs_find_root_ref(snap_src->fs_info->tree_root,
path, test_oid, parent_oid);
if (ret == 0) {
- printk("Snapshot creation failed, looping\n");
+ printk(KERN_INFO "Btrfs snapshot creation "
+ "failed, looping\n");
error = -EMLINK;
btrfs_free_path(path);
goto out_drop_write;
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
if (!vol_args)
src_inode = src_file->f_path.dentry->d_inode;
if (src_inode->i_sb != file->f_path.dentry->d_inode->i_sb) {
- printk("btrfs: Snapshot src from another FS\n");
+ printk(KERN_INFO "btrfs: Snapshot src from "
+ "another FS\n");
ret = -EINVAL;
fput(src_file);
goto out;
switch (inode->i_mode & S_IFMT) {
case S_IFDIR:
+ if (!capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto out;
+ }
btrfs_defrag_root(root, 0);
btrfs_defrag_root(root->fs_info->extent_root, 0);
break;
case S_IFREG:
+ if (!(file->f_mode & FMODE_WRITE)) {
+ ret = -EINVAL;
+ goto out;
+ }
btrfs_defrag_file(file);
break;
}
-
- return 0;
+out:
+ mnt_drop_write(file->f_path.mnt);
+ return ret;
}
static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
struct btrfs_ioctl_vol_args *vol_args;
int ret;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
if (!vol_args)
struct btrfs_ioctl_vol_args *vol_args;
int ret;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
u64 len = olen;
u64 bs = root->fs_info->sb->s_blocksize;
u64 hint_byte;
- u16 csum_size =
- btrfs_super_csum_size(&root->fs_info->super_copy);
+
/*
* TODO:
* - split compressed inline extents. annoying: we need to
* they don't overlap)?
*/
+ /* the destination must be opened for writing */
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
ret = mnt_want_write(file->f_path.mnt);
if (ret)
return ret;
src_file = fget(srcfd);
- if (!src_file)
- return -EBADF;
+ if (!src_file) {
+ ret = -EBADF;
+ goto out_drop_write;
+ }
src = src_file->f_dentry->d_inode;
ret = -EINVAL;
((off + len) & (bs-1)))
goto out_unlock;
- printk("final src extent is %llu~%llu\n", off, len);
- printk("final dst extent is %llu~%llu\n", destoff, len);
-
/* do any pending delalloc/csum calc on src, one way or
another, and lock file content */
while (1) {
slot = path->slots[0];
btrfs_item_key_to_cpu(leaf, &key, slot);
- if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY ||
+ if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
key.objectid != src->i_ino)
break;
comp = btrfs_file_extent_compression(leaf, extent);
type = btrfs_file_extent_type(leaf, extent);
if (type == BTRFS_FILE_EXTENT_REG) {
- disko = btrfs_file_extent_disk_bytenr(leaf, extent);
- diskl = btrfs_file_extent_disk_num_bytes(leaf, extent);
+ disko = btrfs_file_extent_disk_bytenr(leaf,
+ extent);
+ diskl = btrfs_file_extent_disk_num_bytes(leaf,
+ extent);
datao = btrfs_file_extent_offset(leaf, extent);
- datal = btrfs_file_extent_num_bytes(leaf, extent);
+ datal = btrfs_file_extent_num_bytes(leaf,
+ extent);
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
/* take upper bound, may be compressed */
datal = btrfs_file_extent_ram_bytes(leaf,
extent = btrfs_item_ptr(leaf, slot,
struct btrfs_file_extent_item);
- printk(" orig disk %llu~%llu data %llu~%llu\n",
- disko, diskl, datao, datal);
if (off > key.offset) {
datao += off - key.offset;
/* disko == 0 means it's a hole */
if (!disko)
datao = 0;
- printk(" final disk %llu~%llu data %llu~%llu\n",
- disko, diskl, datao, datal);
btrfs_set_file_extent_offset(leaf, extent,
datao);
skip = off - key.offset;
new_key.offset += skip;
}
+
if (key.offset + datal > off+len)
trim = key.offset + datal - (off+len);
- printk("len %lld skip %lld trim %lld\n",
- datal, skip, trim);
+
if (comp && (skip || trim)) {
- printk("btrfs clone_range can't split compressed inline extents yet\n");
ret = -EINVAL;
goto out;
}
goto out;
if (skip) {
- u32 start = btrfs_file_extent_calc_inline_size(0);
+ u32 start =
+ btrfs_file_extent_calc_inline_size(0);
memmove(buf+start, buf+start+skip,
datal);
}
btrfs_mark_buffer_dirty(leaf);
}
- if (btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) {
- u32 size;
- struct btrfs_key new_key;
- u64 coverslen;
- int coff, clen;
-
- size = btrfs_item_size_nr(leaf, slot);
- coverslen = (size / csum_size) <<
- root->fs_info->sb->s_blocksize_bits;
- printk("csums for %llu~%llu\n",
- key.offset, coverslen);
- if (key.offset + coverslen < off ||
- key.offset >= off+len)
- goto next;
-
- read_extent_buffer(leaf, buf,
- btrfs_item_ptr_offset(leaf, slot),
- size);
- btrfs_release_path(root, path);
-
- coff = 0;
- if (off > key.offset)
- coff = ((off - key.offset) >>
- root->fs_info->sb->s_blocksize_bits) *
- csum_size;
- clen = size - coff;
- if (key.offset + coverslen > off+len)
- clen -= ((key.offset+coverslen-off-len) >>
- root->fs_info->sb->s_blocksize_bits) *
- csum_size;
- printk(" will dup %d~%d of %d\n",
- coff, clen, size);
-
- memcpy(&new_key, &key, sizeof(new_key));
- new_key.objectid = inode->i_ino;
- new_key.offset = key.offset + destoff - off;
-
- ret = btrfs_insert_empty_item(trans, root, path,
- &new_key, clen);
- if (ret)
- goto out;
-
- leaf = path->nodes[0];
- slot = path->slots[0];
- write_extent_buffer(leaf, buf + coff,
- btrfs_item_ptr_offset(leaf, slot),
- clen);
- btrfs_mark_buffer_dirty(leaf);
- }
-
- next:
+next:
btrfs_release_path(root, path);
key.offset++;
}
btrfs_free_path(path);
out_fput:
fput(src_file);
+out_drop_write:
+ mnt_drop_write(file->f_path.mnt);
return ret;
}
root->fs_info->open_ioctl_trans--;
mutex_unlock(&root->fs_info->trans_mutex);
+ mnt_drop_write(file->f_path.mnt);
+
out:
return ret;
}