Merge branch 'send-v2' of git://github.com/ablock84/linux-btrfs into for-linus
This is the kernel portion of btrfs send/receive Conflicts: fs/btrfs/Makefile fs/btrfs/backref.h fs/btrfs/ctree.c fs/btrfs/ioctl.c fs/btrfs/ioctl.h Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
114
fs/btrfs/ioctl.c
114
fs/btrfs/ioctl.c
@@ -41,6 +41,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/uuid.h>
|
||||
#include "compat.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "inode-map.h"
|
||||
#include "backref.h"
|
||||
#include "rcu-string.h"
|
||||
#include "send.h"
|
||||
|
||||
/* Mask out flags that are inappropriate for the given type of inode. */
|
||||
static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
|
||||
@@ -347,11 +349,13 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||
struct btrfs_root *new_root;
|
||||
struct dentry *parent = dentry->d_parent;
|
||||
struct inode *dir;
|
||||
struct timespec cur_time = CURRENT_TIME;
|
||||
int ret;
|
||||
int err;
|
||||
u64 objectid;
|
||||
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
u64 index = 0;
|
||||
uuid_le new_uuid;
|
||||
|
||||
ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
|
||||
if (ret)
|
||||
@@ -395,8 +399,9 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||
BTRFS_UUID_SIZE);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
|
||||
memset(&root_item, 0, sizeof(root_item));
|
||||
|
||||
inode_item = &root_item.inode;
|
||||
memset(inode_item, 0, sizeof(*inode_item));
|
||||
inode_item->generation = cpu_to_le64(1);
|
||||
inode_item->size = cpu_to_le64(3);
|
||||
inode_item->nlink = cpu_to_le32(1);
|
||||
@@ -414,8 +419,15 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||
btrfs_set_root_used(&root_item, leaf->len);
|
||||
btrfs_set_root_last_snapshot(&root_item, 0);
|
||||
|
||||
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
|
||||
root_item.drop_level = 0;
|
||||
btrfs_set_root_generation_v2(&root_item,
|
||||
btrfs_root_generation(&root_item));
|
||||
uuid_le_gen(&new_uuid);
|
||||
memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE);
|
||||
root_item.otime.sec = cpu_to_le64(cur_time.tv_sec);
|
||||
root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec);
|
||||
root_item.ctime = root_item.otime;
|
||||
btrfs_set_root_ctransid(&root_item, trans->transid);
|
||||
btrfs_set_root_otransid(&root_item, trans->transid);
|
||||
|
||||
btrfs_tree_unlock(leaf);
|
||||
free_extent_buffer(leaf);
|
||||
@@ -2370,6 +2382,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
goto out_drop_write;
|
||||
}
|
||||
|
||||
ret = -EXDEV;
|
||||
if (src_file->f_path.mnt != file->f_path.mnt)
|
||||
goto out_fput;
|
||||
|
||||
src = src_file->f_dentry->d_inode;
|
||||
|
||||
ret = -EINVAL;
|
||||
@@ -2390,7 +2406,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
goto out_fput;
|
||||
|
||||
ret = -EXDEV;
|
||||
if (src->i_sb != inode->i_sb || BTRFS_I(src)->root != root)
|
||||
if (src->i_sb != inode->i_sb)
|
||||
goto out_fput;
|
||||
|
||||
ret = -ENOMEM;
|
||||
@@ -2464,13 +2480,14 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
* note the key will change type as we walk through the
|
||||
* tree.
|
||||
*/
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path,
|
||||
0, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
if (path->slots[0] >= nritems) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
ret = btrfs_next_leaf(BTRFS_I(src)->root, path);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret > 0)
|
||||
@@ -3589,6 +3606,87 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long btrfs_ioctl_set_received_subvol(struct file *file,
|
||||
void __user *arg)
|
||||
{
|
||||
struct btrfs_ioctl_received_subvol_args *sa = NULL;
|
||||
struct inode *inode = fdentry(file)->d_inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_root_item *root_item = &root->root_item;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct timespec ct = CURRENT_TIME;
|
||||
int ret = 0;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
down_write(&root->fs_info->subvol_sem);
|
||||
|
||||
if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (btrfs_root_readonly(root)) {
|
||||
ret = -EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!inode_owner_or_capable(inode)) {
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sa = memdup_user(arg, sizeof(*sa));
|
||||
if (IS_ERR(sa)) {
|
||||
ret = PTR_ERR(sa);
|
||||
sa = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
trans = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sa->rtransid = trans->transid;
|
||||
sa->rtime.sec = ct.tv_sec;
|
||||
sa->rtime.nsec = ct.tv_nsec;
|
||||
|
||||
memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
|
||||
btrfs_set_root_stransid(root_item, sa->stransid);
|
||||
btrfs_set_root_rtransid(root_item, sa->rtransid);
|
||||
root_item->stime.sec = cpu_to_le64(sa->stime.sec);
|
||||
root_item->stime.nsec = cpu_to_le32(sa->stime.nsec);
|
||||
root_item->rtime.sec = cpu_to_le64(sa->rtime.sec);
|
||||
root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec);
|
||||
|
||||
ret = btrfs_update_root(trans, root->fs_info->tree_root,
|
||||
&root->root_key, &root->root_item);
|
||||
if (ret < 0) {
|
||||
btrfs_end_transaction(trans, root);
|
||||
trans = NULL;
|
||||
goto out;
|
||||
} else {
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = copy_to_user(arg, sa, sizeof(*sa));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
|
||||
out:
|
||||
kfree(sa);
|
||||
up_write(&root->fs_info->subvol_sem);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long btrfs_ioctl(struct file *file, unsigned int
|
||||
cmd, unsigned long arg)
|
||||
{
|
||||
@@ -3673,6 +3771,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||
return btrfs_ioctl_balance_ctl(root, arg);
|
||||
case BTRFS_IOC_BALANCE_PROGRESS:
|
||||
return btrfs_ioctl_balance_progress(root, argp);
|
||||
case BTRFS_IOC_SET_RECEIVED_SUBVOL:
|
||||
return btrfs_ioctl_set_received_subvol(file, argp);
|
||||
case BTRFS_IOC_SEND:
|
||||
return btrfs_ioctl_send(file, argp);
|
||||
case BTRFS_IOC_GET_DEV_STATS:
|
||||
return btrfs_ioctl_get_dev_stats(root, argp);
|
||||
case BTRFS_IOC_QUOTA_CTL:
|
||||
|
Reference in New Issue
Block a user