aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c107
1 files changed, 83 insertions, 24 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index dc5a19ed07f3..e8a26a3aac3e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -224,7 +224,8 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
224 224
225static noinline int create_subvol(struct btrfs_root *root, 225static noinline int create_subvol(struct btrfs_root *root,
226 struct dentry *dentry, 226 struct dentry *dentry,
227 char *name, int namelen) 227 char *name, int namelen,
228 u64 *async_transid)
228{ 229{
229 struct btrfs_trans_handle *trans; 230 struct btrfs_trans_handle *trans;
230 struct btrfs_key key; 231 struct btrfs_key key;
@@ -338,13 +339,19 @@ static noinline int create_subvol(struct btrfs_root *root,
338 339
339 d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); 340 d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
340fail: 341fail:
341 err = btrfs_commit_transaction(trans, root); 342 if (async_transid) {
343 *async_transid = trans->transid;
344 err = btrfs_commit_transaction_async(trans, root, 1);
345 } else {
346 err = btrfs_commit_transaction(trans, root);
347 }
342 if (err && !ret) 348 if (err && !ret)
343 ret = err; 349 ret = err;
344 return ret; 350 return ret;
345} 351}
346 352
347static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) 353static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
354 char *name, int namelen, u64 *async_transid)
348{ 355{
349 struct inode *inode; 356 struct inode *inode;
350 struct btrfs_pending_snapshot *pending_snapshot; 357 struct btrfs_pending_snapshot *pending_snapshot;
@@ -373,7 +380,14 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry)
373 380
374 list_add(&pending_snapshot->list, 381 list_add(&pending_snapshot->list,
375 &trans->transaction->pending_snapshots); 382 &trans->transaction->pending_snapshots);
376 ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); 383 if (async_transid) {
384 *async_transid = trans->transid;
385 ret = btrfs_commit_transaction_async(trans,
386 root->fs_info->extent_root, 1);
387 } else {
388 ret = btrfs_commit_transaction(trans,
389 root->fs_info->extent_root);
390 }
377 BUG_ON(ret); 391 BUG_ON(ret);
378 392
379 ret = pending_snapshot->error; 393 ret = pending_snapshot->error;
@@ -412,7 +426,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
412 */ 426 */
413static noinline int btrfs_mksubvol(struct path *parent, 427static noinline int btrfs_mksubvol(struct path *parent,
414 char *name, int namelen, 428 char *name, int namelen,
415 struct btrfs_root *snap_src) 429 struct btrfs_root *snap_src,
430 u64 *async_transid)
416{ 431{
417 struct inode *dir = parent->dentry->d_inode; 432 struct inode *dir = parent->dentry->d_inode;
418 struct dentry *dentry; 433 struct dentry *dentry;
@@ -443,10 +458,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
443 goto out_up_read; 458 goto out_up_read;
444 459
445 if (snap_src) { 460 if (snap_src) {
446 error = create_snapshot(snap_src, dentry); 461 error = create_snapshot(snap_src, dentry,
462 name, namelen, async_transid);
447 } else { 463 } else {
448 error = create_subvol(BTRFS_I(dir)->root, dentry, 464 error = create_subvol(BTRFS_I(dir)->root, dentry,
449 name, namelen); 465 name, namelen, async_transid);
450 } 466 }
451 if (!error) 467 if (!error)
452 fsnotify_mkdir(dir, dentry); 468 fsnotify_mkdir(dir, dentry);
@@ -799,11 +815,13 @@ out_unlock:
799 return ret; 815 return ret;
800} 816}
801 817
802static noinline int btrfs_ioctl_snap_create(struct file *file, 818static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
803 void __user *arg, int subvol) 819 char *name,
820 unsigned long fd,
821 int subvol,
822 u64 *transid)
804{ 823{
805 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; 824 struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
806 struct btrfs_ioctl_vol_args *vol_args;
807 struct file *src_file; 825 struct file *src_file;
808 int namelen; 826 int namelen;
809 int ret = 0; 827 int ret = 0;
@@ -811,23 +829,18 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
811 if (root->fs_info->sb->s_flags & MS_RDONLY) 829 if (root->fs_info->sb->s_flags & MS_RDONLY)
812 return -EROFS; 830 return -EROFS;
813 831
814 vol_args = memdup_user(arg, sizeof(*vol_args)); 832 namelen = strlen(name);
815 if (IS_ERR(vol_args)) 833 if (strchr(name, '/')) {
816 return PTR_ERR(vol_args);
817
818 vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
819 namelen = strlen(vol_args->name);
820 if (strchr(vol_args->name, '/')) {
821 ret = -EINVAL; 834 ret = -EINVAL;
822 goto out; 835 goto out;
823 } 836 }
824 837
825 if (subvol) { 838 if (subvol) {
826 ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, 839 ret = btrfs_mksubvol(&file->f_path, name, namelen,
827 NULL); 840 NULL, transid);
828 } else { 841 } else {
829 struct inode *src_inode; 842 struct inode *src_inode;
830 src_file = fget(vol_args->fd); 843 src_file = fget(fd);
831 if (!src_file) { 844 if (!src_file) {
832 ret = -EINVAL; 845 ret = -EINVAL;
833 goto out; 846 goto out;
@@ -841,12 +854,56 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
841 fput(src_file); 854 fput(src_file);
842 goto out; 855 goto out;
843 } 856 }
844 ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, 857 ret = btrfs_mksubvol(&file->f_path, name, namelen,
845 BTRFS_I(src_inode)->root); 858 BTRFS_I(src_inode)->root,
859 transid);
846 fput(src_file); 860 fput(src_file);
847 } 861 }
848out: 862out:
863 return ret;
864}
865
866static noinline int btrfs_ioctl_snap_create(struct file *file,
867 void __user *arg, int subvol,
868 int async)
869{
870 struct btrfs_ioctl_vol_args *vol_args = NULL;
871 struct btrfs_ioctl_async_vol_args *async_vol_args = NULL;
872 char *name;
873 u64 fd;
874 u64 transid = 0;
875 int ret;
876
877 if (async) {
878 async_vol_args = memdup_user(arg, sizeof(*async_vol_args));
879 if (IS_ERR(async_vol_args))
880 return PTR_ERR(async_vol_args);
881
882 name = async_vol_args->name;
883 fd = async_vol_args->fd;
884 async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0';
885 } else {
886 vol_args = memdup_user(arg, sizeof(*vol_args));
887 if (IS_ERR(vol_args))
888 return PTR_ERR(vol_args);
889 name = vol_args->name;
890 fd = vol_args->fd;
891 vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
892 }
893
894 ret = btrfs_ioctl_snap_create_transid(file, name, fd,
895 subvol, &transid);
896
897 if (!ret && async) {
898 if (copy_to_user(arg +
899 offsetof(struct btrfs_ioctl_async_vol_args,
900 transid), &transid, sizeof(transid)))
901 return -EFAULT;
902 }
903
849 kfree(vol_args); 904 kfree(vol_args);
905 kfree(async_vol_args);
906
850 return ret; 907 return ret;
851} 908}
852 909
@@ -2072,9 +2129,11 @@ long btrfs_ioctl(struct file *file, unsigned int
2072 case FS_IOC_GETVERSION: 2129 case FS_IOC_GETVERSION:
2073 return btrfs_ioctl_getversion(file, argp); 2130 return btrfs_ioctl_getversion(file, argp);
2074 case BTRFS_IOC_SNAP_CREATE: 2131 case BTRFS_IOC_SNAP_CREATE:
2075 return btrfs_ioctl_snap_create(file, argp, 0); 2132 return btrfs_ioctl_snap_create(file, argp, 0, 0);
2133 case BTRFS_IOC_SNAP_CREATE_ASYNC:
2134 return btrfs_ioctl_snap_create(file, argp, 0, 1);
2076 case BTRFS_IOC_SUBVOL_CREATE: 2135 case BTRFS_IOC_SUBVOL_CREATE:
2077 return btrfs_ioctl_snap_create(file, argp, 1); 2136 return btrfs_ioctl_snap_create(file, argp, 1, 0);
2078 case BTRFS_IOC_SNAP_DESTROY: 2137 case BTRFS_IOC_SNAP_DESTROY:
2079 return btrfs_ioctl_snap_destroy(file, argp); 2138 return btrfs_ioctl_snap_destroy(file, argp);
2080 case BTRFS_IOC_DEFAULT_SUBVOL: 2139 case BTRFS_IOC_DEFAULT_SUBVOL: