diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 87 |
1 files changed, 55 insertions, 32 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 463d91b4dd3a..f87552a1d7ea 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -233,7 +233,8 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
233 | struct btrfs_inode_item *inode_item; | 233 | struct btrfs_inode_item *inode_item; |
234 | struct extent_buffer *leaf; | 234 | struct extent_buffer *leaf; |
235 | struct btrfs_root *new_root; | 235 | struct btrfs_root *new_root; |
236 | struct inode *dir = dentry->d_parent->d_inode; | 236 | struct dentry *parent = dget_parent(dentry); |
237 | struct inode *dir; | ||
237 | int ret; | 238 | int ret; |
238 | int err; | 239 | int err; |
239 | u64 objectid; | 240 | u64 objectid; |
@@ -242,8 +243,13 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
242 | 243 | ||
243 | ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, | 244 | ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, |
244 | 0, &objectid); | 245 | 0, &objectid); |
245 | if (ret) | 246 | if (ret) { |
247 | dput(parent); | ||
246 | return ret; | 248 | return ret; |
249 | } | ||
250 | |||
251 | dir = parent->d_inode; | ||
252 | |||
247 | /* | 253 | /* |
248 | * 1 - inode item | 254 | * 1 - inode item |
249 | * 2 - refs | 255 | * 2 - refs |
@@ -251,8 +257,10 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
251 | * 2 - dir items | 257 | * 2 - dir items |
252 | */ | 258 | */ |
253 | trans = btrfs_start_transaction(root, 6); | 259 | trans = btrfs_start_transaction(root, 6); |
254 | if (IS_ERR(trans)) | 260 | if (IS_ERR(trans)) { |
261 | dput(parent); | ||
255 | return PTR_ERR(trans); | 262 | return PTR_ERR(trans); |
263 | } | ||
256 | 264 | ||
257 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, | 265 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, |
258 | 0, objectid, NULL, 0, 0, 0); | 266 | 0, objectid, NULL, 0, 0, 0); |
@@ -339,6 +347,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
339 | 347 | ||
340 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 348 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
341 | fail: | 349 | fail: |
350 | dput(parent); | ||
342 | if (async_transid) { | 351 | if (async_transid) { |
343 | *async_transid = trans->transid; | 352 | *async_transid = trans->transid; |
344 | err = btrfs_commit_transaction_async(trans, root, 1); | 353 | err = btrfs_commit_transaction_async(trans, root, 1); |
@@ -354,6 +363,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
354 | char *name, int namelen, u64 *async_transid) | 363 | char *name, int namelen, u64 *async_transid) |
355 | { | 364 | { |
356 | struct inode *inode; | 365 | struct inode *inode; |
366 | struct dentry *parent; | ||
357 | struct btrfs_pending_snapshot *pending_snapshot; | 367 | struct btrfs_pending_snapshot *pending_snapshot; |
358 | struct btrfs_trans_handle *trans; | 368 | struct btrfs_trans_handle *trans; |
359 | int ret; | 369 | int ret; |
@@ -396,7 +406,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
396 | 406 | ||
397 | btrfs_orphan_cleanup(pending_snapshot->snap); | 407 | btrfs_orphan_cleanup(pending_snapshot->snap); |
398 | 408 | ||
399 | inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); | 409 | parent = dget_parent(dentry); |
410 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); | ||
411 | dput(parent); | ||
400 | if (IS_ERR(inode)) { | 412 | if (IS_ERR(inode)) { |
401 | ret = PTR_ERR(inode); | 413 | ret = PTR_ERR(inode); |
402 | goto fail; | 414 | goto fail; |
@@ -935,23 +947,42 @@ out: | |||
935 | 947 | ||
936 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 948 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
937 | void __user *arg, int subvol, | 949 | void __user *arg, int subvol, |
938 | int async) | 950 | int v2) |
939 | { | 951 | { |
940 | struct btrfs_ioctl_vol_args *vol_args = NULL; | 952 | struct btrfs_ioctl_vol_args *vol_args = NULL; |
941 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | 953 | struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; |
942 | char *name; | 954 | char *name; |
943 | u64 fd; | 955 | u64 fd; |
944 | u64 transid = 0; | ||
945 | int ret; | 956 | int ret; |
946 | 957 | ||
947 | if (async) { | 958 | if (v2) { |
948 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | 959 | u64 transid = 0; |
949 | if (IS_ERR(async_vol_args)) | 960 | u64 *ptr = NULL; |
950 | return PTR_ERR(async_vol_args); | 961 | |
962 | vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); | ||
963 | if (IS_ERR(vol_args_v2)) | ||
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); | ||
951 | 980 | ||
952 | name = async_vol_args->name; | 981 | if (ret == 0 && ptr && |
953 | fd = async_vol_args->fd; | 982 | copy_to_user(arg + |
954 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | 983 | offsetof(struct btrfs_ioctl_vol_args_v2, |
984 | transid), ptr, sizeof(*ptr))) | ||
985 | ret = -EFAULT; | ||
955 | } else { | 986 | } else { |
956 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 987 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
957 | if (IS_ERR(vol_args)) | 988 | if (IS_ERR(vol_args)) |
@@ -959,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
959 | name = vol_args->name; | 990 | name = vol_args->name; |
960 | fd = vol_args->fd; | 991 | fd = vol_args->fd; |
961 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 992 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
962 | } | ||
963 | |||
964 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
965 | subvol, &transid); | ||
966 | 993 | ||
967 | if (!ret && async) { | 994 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, |
968 | if (copy_to_user(arg + | 995 | subvol, NULL); |
969 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
970 | transid), &transid, sizeof(transid))) | ||
971 | return -EFAULT; | ||
972 | } | 996 | } |
973 | 997 | out: | |
974 | kfree(vol_args); | 998 | kfree(vol_args); |
975 | kfree(async_vol_args); | 999 | kfree(vol_args_v2); |
976 | 1000 | ||
977 | return ret; | 1001 | return ret; |
978 | } | 1002 | } |
@@ -1669,12 +1693,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1669 | olen = len = src->i_size - off; | 1693 | olen = len = src->i_size - off; |
1670 | /* if we extend to eof, continue to block boundary */ | 1694 | /* if we extend to eof, continue to block boundary */ |
1671 | if (off + len == src->i_size) | 1695 | if (off + len == src->i_size) |
1672 | len = ((src->i_size + bs-1) & ~(bs-1)) | 1696 | len = ALIGN(src->i_size, bs) - off; |
1673 | - off; | ||
1674 | 1697 | ||
1675 | /* verify the end result is block aligned */ | 1698 | /* verify the end result is block aligned */ |
1676 | if ((off & (bs-1)) || | 1699 | if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || |
1677 | ((off + len) & (bs-1))) | 1700 | !IS_ALIGNED(destoff, bs)) |
1678 | goto out_unlock; | 1701 | goto out_unlock; |
1679 | 1702 | ||
1680 | /* do any pending delalloc/csum calc on src, one way or | 1703 | /* do any pending delalloc/csum calc on src, one way or |
@@ -1874,8 +1897,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1874 | * but shouldn't round up the file size | 1897 | * but shouldn't round up the file size |
1875 | */ | 1898 | */ |
1876 | endoff = new_key.offset + datal; | 1899 | endoff = new_key.offset + datal; |
1877 | if (endoff > off+olen) | 1900 | if (endoff > destoff+olen) |
1878 | endoff = off+olen; | 1901 | endoff = destoff+olen; |
1879 | if (endoff > inode->i_size) | 1902 | if (endoff > inode->i_size) |
1880 | btrfs_i_size_write(inode, endoff); | 1903 | btrfs_i_size_write(inode, endoff); |
1881 | 1904 | ||
@@ -2235,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2235 | return btrfs_ioctl_getversion(file, argp); | 2258 | return btrfs_ioctl_getversion(file, argp); |
2236 | case BTRFS_IOC_SNAP_CREATE: | 2259 | case BTRFS_IOC_SNAP_CREATE: |
2237 | return btrfs_ioctl_snap_create(file, argp, 0, 0); | 2260 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
2238 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | 2261 | case BTRFS_IOC_SNAP_CREATE_V2: |
2239 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | 2262 | return btrfs_ioctl_snap_create(file, argp, 0, 1); |
2240 | case BTRFS_IOC_SUBVOL_CREATE: | 2263 | case BTRFS_IOC_SUBVOL_CREATE: |
2241 | return btrfs_ioctl_snap_create(file, argp, 1, 0); | 2264 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |