diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 107 |
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 | ||
225 | static noinline int create_subvol(struct btrfs_root *root, | 225 | static 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)); |
340 | fail: | 341 | fail: |
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 | ||
347 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | 353 | static 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 | */ |
413 | static noinline int btrfs_mksubvol(struct path *parent, | 427 | static 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 | ||
802 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 818 | static 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 | } |
848 | out: | 862 | out: |
863 | return ret; | ||
864 | } | ||
865 | |||
866 | static 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: |