diff options
| -rw-r--r-- | fs/btrfs/ioctl.c | 107 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.h | 11 |
2 files changed, 93 insertions, 25 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: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 16e1442523b7..17c99ebdf960 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
| @@ -22,14 +22,21 @@ | |||
| 22 | 22 | ||
| 23 | #define BTRFS_IOCTL_MAGIC 0x94 | 23 | #define BTRFS_IOCTL_MAGIC 0x94 |
| 24 | #define BTRFS_VOL_NAME_MAX 255 | 24 | #define BTRFS_VOL_NAME_MAX 255 |
| 25 | #define BTRFS_PATH_NAME_MAX 4087 | ||
| 26 | 25 | ||
| 27 | /* this should be 4k */ | 26 | /* this should be 4k */ |
| 27 | #define BTRFS_PATH_NAME_MAX 4087 | ||
| 28 | struct btrfs_ioctl_vol_args { | 28 | struct btrfs_ioctl_vol_args { |
| 29 | __s64 fd; | 29 | __s64 fd; |
| 30 | char name[BTRFS_PATH_NAME_MAX + 1]; | 30 | char name[BTRFS_PATH_NAME_MAX + 1]; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | #define BTRFS_SNAPSHOT_NAME_MAX 4079 | ||
| 34 | struct btrfs_ioctl_async_vol_args { | ||
| 35 | __s64 fd; | ||
| 36 | __u64 transid; | ||
| 37 | char name[BTRFS_SNAPSHOT_NAME_MAX + 1]; | ||
| 38 | }; | ||
| 39 | |||
| 33 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | 40 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 |
| 34 | struct btrfs_ioctl_ino_lookup_args { | 41 | struct btrfs_ioctl_ino_lookup_args { |
| 35 | __u64 treeid; | 42 | __u64 treeid; |
| @@ -180,4 +187,6 @@ struct btrfs_ioctl_space_args { | |||
| 180 | struct btrfs_ioctl_space_args) | 187 | struct btrfs_ioctl_space_args) |
| 181 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) | 188 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) |
| 182 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | 189 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) |
| 190 | #define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \ | ||
| 191 | struct btrfs_ioctl_async_vol_args) | ||
| 183 | #endif | 192 | #endif |
