diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f1c9bb4079ed..f87552a1d7ea 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -947,23 +947,42 @@ out: | |||
947 | 947 | ||
948 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 948 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
949 | void __user *arg, int subvol, | 949 | void __user *arg, int subvol, |
950 | int async) | 950 | int v2) |
951 | { | 951 | { |
952 | struct btrfs_ioctl_vol_args *vol_args = NULL; | 952 | struct btrfs_ioctl_vol_args *vol_args = NULL; |
953 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | 953 | struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; |
954 | char *name; | 954 | char *name; |
955 | u64 fd; | 955 | u64 fd; |
956 | u64 transid = 0; | ||
957 | int ret; | 956 | int ret; |
958 | 957 | ||
959 | if (async) { | 958 | if (v2) { |
960 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | 959 | u64 transid = 0; |
961 | if (IS_ERR(async_vol_args)) | 960 | u64 *ptr = NULL; |
962 | return PTR_ERR(async_vol_args); | ||
963 | 961 | ||
964 | name = async_vol_args->name; | 962 | vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); |
965 | fd = async_vol_args->fd; | 963 | if (IS_ERR(vol_args_v2)) |
966 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | 964 | return PTR_ERR(vol_args_v2); |
965 | |||
966 | if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { | ||
967 | ret = -EINVAL; | ||
968 | goto out; | ||
969 | } | ||
970 | |||
971 | name = vol_args_v2->name; | ||
972 | fd = vol_args_v2->fd; | ||
973 | vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | ||
974 | |||
975 | if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) | ||
976 | ptr = &transid; | ||
977 | |||
978 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
979 | subvol, ptr); | ||
980 | |||
981 | if (ret == 0 && ptr && | ||
982 | copy_to_user(arg + | ||
983 | offsetof(struct btrfs_ioctl_vol_args_v2, | ||
984 | transid), ptr, sizeof(*ptr))) | ||
985 | ret = -EFAULT; | ||
967 | } else { | 986 | } else { |
968 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 987 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
969 | if (IS_ERR(vol_args)) | 988 | if (IS_ERR(vol_args)) |
@@ -971,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
971 | name = vol_args->name; | 990 | name = vol_args->name; |
972 | fd = vol_args->fd; | 991 | fd = vol_args->fd; |
973 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 992 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
974 | } | ||
975 | |||
976 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
977 | subvol, &transid); | ||
978 | 993 | ||
979 | if (!ret && async) { | 994 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, |
980 | if (copy_to_user(arg + | 995 | subvol, NULL); |
981 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
982 | transid), &transid, sizeof(transid))) | ||
983 | return -EFAULT; | ||
984 | } | 996 | } |
985 | 997 | out: | |
986 | kfree(vol_args); | 998 | kfree(vol_args); |
987 | kfree(async_vol_args); | 999 | kfree(vol_args_v2); |
988 | 1000 | ||
989 | return ret; | 1001 | return ret; |
990 | } | 1002 | } |
@@ -2246,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2246 | return btrfs_ioctl_getversion(file, argp); | 2258 | return btrfs_ioctl_getversion(file, argp); |
2247 | case BTRFS_IOC_SNAP_CREATE: | 2259 | case BTRFS_IOC_SNAP_CREATE: |
2248 | return btrfs_ioctl_snap_create(file, argp, 0, 0); | 2260 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
2249 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | 2261 | case BTRFS_IOC_SNAP_CREATE_V2: |
2250 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | 2262 | return btrfs_ioctl_snap_create(file, argp, 0, 1); |
2251 | case BTRFS_IOC_SUBVOL_CREATE: | 2263 | case BTRFS_IOC_SUBVOL_CREATE: |
2252 | return btrfs_ioctl_snap_create(file, argp, 1, 0); | 2264 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |