diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 481 |
1 files changed, 395 insertions, 86 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 0e92e5763005..7bb755677a22 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/vmalloc.h> | 41 | #include <linux/vmalloc.h> |
| 42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
| 43 | #include <linux/blkdev.h> | 43 | #include <linux/blkdev.h> |
| 44 | #include <linux/uuid.h> | ||
| 44 | #include "compat.h" | 45 | #include "compat.h" |
| 45 | #include "ctree.h" | 46 | #include "ctree.h" |
| 46 | #include "disk-io.h" | 47 | #include "disk-io.h" |
| @@ -53,6 +54,7 @@ | |||
| 53 | #include "inode-map.h" | 54 | #include "inode-map.h" |
| 54 | #include "backref.h" | 55 | #include "backref.h" |
| 55 | #include "rcu-string.h" | 56 | #include "rcu-string.h" |
| 57 | #include "send.h" | ||
| 56 | 58 | ||
| 57 | /* Mask out flags that are inappropriate for the given type of inode. */ | 59 | /* Mask out flags that are inappropriate for the given type of inode. */ |
| 58 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) | 60 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) |
| @@ -193,6 +195,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 193 | if (!inode_owner_or_capable(inode)) | 195 | if (!inode_owner_or_capable(inode)) |
| 194 | return -EACCES; | 196 | return -EACCES; |
| 195 | 197 | ||
| 198 | ret = mnt_want_write_file(file); | ||
| 199 | if (ret) | ||
| 200 | return ret; | ||
| 201 | |||
| 196 | mutex_lock(&inode->i_mutex); | 202 | mutex_lock(&inode->i_mutex); |
| 197 | 203 | ||
| 198 | ip_oldflags = ip->flags; | 204 | ip_oldflags = ip->flags; |
| @@ -207,10 +213,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 207 | } | 213 | } |
| 208 | } | 214 | } |
| 209 | 215 | ||
| 210 | ret = mnt_want_write_file(file); | ||
| 211 | if (ret) | ||
| 212 | goto out_unlock; | ||
| 213 | |||
| 214 | if (flags & FS_SYNC_FL) | 216 | if (flags & FS_SYNC_FL) |
| 215 | ip->flags |= BTRFS_INODE_SYNC; | 217 | ip->flags |= BTRFS_INODE_SYNC; |
| 216 | else | 218 | else |
| @@ -273,9 +275,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 273 | inode->i_flags = i_oldflags; | 275 | inode->i_flags = i_oldflags; |
| 274 | } | 276 | } |
| 275 | 277 | ||
| 276 | mnt_drop_write_file(file); | ||
| 277 | out_unlock: | 278 | out_unlock: |
| 278 | mutex_unlock(&inode->i_mutex); | 279 | mutex_unlock(&inode->i_mutex); |
| 280 | mnt_drop_write_file(file); | ||
| 279 | return ret; | 281 | return ret; |
| 280 | } | 282 | } |
| 281 | 283 | ||
| @@ -336,7 +338,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
| 336 | static noinline int create_subvol(struct btrfs_root *root, | 338 | static noinline int create_subvol(struct btrfs_root *root, |
| 337 | struct dentry *dentry, | 339 | struct dentry *dentry, |
| 338 | char *name, int namelen, | 340 | char *name, int namelen, |
| 339 | u64 *async_transid) | 341 | u64 *async_transid, |
| 342 | struct btrfs_qgroup_inherit **inherit) | ||
| 340 | { | 343 | { |
| 341 | struct btrfs_trans_handle *trans; | 344 | struct btrfs_trans_handle *trans; |
| 342 | struct btrfs_key key; | 345 | struct btrfs_key key; |
| @@ -346,11 +349,13 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 346 | struct btrfs_root *new_root; | 349 | struct btrfs_root *new_root; |
| 347 | struct dentry *parent = dentry->d_parent; | 350 | struct dentry *parent = dentry->d_parent; |
| 348 | struct inode *dir; | 351 | struct inode *dir; |
| 352 | struct timespec cur_time = CURRENT_TIME; | ||
| 349 | int ret; | 353 | int ret; |
| 350 | int err; | 354 | int err; |
| 351 | u64 objectid; | 355 | u64 objectid; |
| 352 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | 356 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
| 353 | u64 index = 0; | 357 | u64 index = 0; |
| 358 | uuid_le new_uuid; | ||
| 354 | 359 | ||
| 355 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); | 360 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); |
| 356 | if (ret) | 361 | if (ret) |
| @@ -368,6 +373,11 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 368 | if (IS_ERR(trans)) | 373 | if (IS_ERR(trans)) |
| 369 | return PTR_ERR(trans); | 374 | return PTR_ERR(trans); |
| 370 | 375 | ||
| 376 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, | ||
| 377 | inherit ? *inherit : NULL); | ||
| 378 | if (ret) | ||
| 379 | goto fail; | ||
| 380 | |||
| 371 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, | 381 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, |
| 372 | 0, objectid, NULL, 0, 0, 0); | 382 | 0, objectid, NULL, 0, 0, 0); |
| 373 | if (IS_ERR(leaf)) { | 383 | if (IS_ERR(leaf)) { |
| @@ -389,8 +399,9 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 389 | BTRFS_UUID_SIZE); | 399 | BTRFS_UUID_SIZE); |
| 390 | btrfs_mark_buffer_dirty(leaf); | 400 | btrfs_mark_buffer_dirty(leaf); |
| 391 | 401 | ||
| 402 | memset(&root_item, 0, sizeof(root_item)); | ||
| 403 | |||
| 392 | inode_item = &root_item.inode; | 404 | inode_item = &root_item.inode; |
| 393 | memset(inode_item, 0, sizeof(*inode_item)); | ||
| 394 | inode_item->generation = cpu_to_le64(1); | 405 | inode_item->generation = cpu_to_le64(1); |
| 395 | inode_item->size = cpu_to_le64(3); | 406 | inode_item->size = cpu_to_le64(3); |
| 396 | inode_item->nlink = cpu_to_le32(1); | 407 | inode_item->nlink = cpu_to_le32(1); |
| @@ -408,8 +419,15 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 408 | btrfs_set_root_used(&root_item, leaf->len); | 419 | btrfs_set_root_used(&root_item, leaf->len); |
| 409 | btrfs_set_root_last_snapshot(&root_item, 0); | 420 | btrfs_set_root_last_snapshot(&root_item, 0); |
| 410 | 421 | ||
| 411 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); | 422 | btrfs_set_root_generation_v2(&root_item, |
| 412 | root_item.drop_level = 0; | 423 | btrfs_root_generation(&root_item)); |
| 424 | uuid_le_gen(&new_uuid); | ||
| 425 | memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE); | ||
| 426 | root_item.otime.sec = cpu_to_le64(cur_time.tv_sec); | ||
| 427 | root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec); | ||
| 428 | root_item.ctime = root_item.otime; | ||
| 429 | btrfs_set_root_ctransid(&root_item, trans->transid); | ||
| 430 | btrfs_set_root_otransid(&root_item, trans->transid); | ||
| 413 | 431 | ||
| 414 | btrfs_tree_unlock(leaf); | 432 | btrfs_tree_unlock(leaf); |
| 415 | free_extent_buffer(leaf); | 433 | free_extent_buffer(leaf); |
| @@ -484,7 +502,7 @@ fail: | |||
| 484 | 502 | ||
| 485 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | 503 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
| 486 | char *name, int namelen, u64 *async_transid, | 504 | char *name, int namelen, u64 *async_transid, |
| 487 | bool readonly) | 505 | bool readonly, struct btrfs_qgroup_inherit **inherit) |
| 488 | { | 506 | { |
| 489 | struct inode *inode; | 507 | struct inode *inode; |
| 490 | struct btrfs_pending_snapshot *pending_snapshot; | 508 | struct btrfs_pending_snapshot *pending_snapshot; |
| @@ -502,6 +520,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
| 502 | pending_snapshot->dentry = dentry; | 520 | pending_snapshot->dentry = dentry; |
| 503 | pending_snapshot->root = root; | 521 | pending_snapshot->root = root; |
| 504 | pending_snapshot->readonly = readonly; | 522 | pending_snapshot->readonly = readonly; |
| 523 | if (inherit) { | ||
| 524 | pending_snapshot->inherit = *inherit; | ||
| 525 | *inherit = NULL; /* take responsibility to free it */ | ||
| 526 | } | ||
| 505 | 527 | ||
| 506 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); | 528 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); |
| 507 | if (IS_ERR(trans)) { | 529 | if (IS_ERR(trans)) { |
| @@ -635,7 +657,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
| 635 | static noinline int btrfs_mksubvol(struct path *parent, | 657 | static noinline int btrfs_mksubvol(struct path *parent, |
| 636 | char *name, int namelen, | 658 | char *name, int namelen, |
| 637 | struct btrfs_root *snap_src, | 659 | struct btrfs_root *snap_src, |
| 638 | u64 *async_transid, bool readonly) | 660 | u64 *async_transid, bool readonly, |
| 661 | struct btrfs_qgroup_inherit **inherit) | ||
| 639 | { | 662 | { |
| 640 | struct inode *dir = parent->dentry->d_inode; | 663 | struct inode *dir = parent->dentry->d_inode; |
| 641 | struct dentry *dentry; | 664 | struct dentry *dentry; |
| @@ -652,13 +675,9 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
| 652 | if (dentry->d_inode) | 675 | if (dentry->d_inode) |
| 653 | goto out_dput; | 676 | goto out_dput; |
| 654 | 677 | ||
| 655 | error = mnt_want_write(parent->mnt); | ||
| 656 | if (error) | ||
| 657 | goto out_dput; | ||
| 658 | |||
| 659 | error = btrfs_may_create(dir, dentry); | 678 | error = btrfs_may_create(dir, dentry); |
| 660 | if (error) | 679 | if (error) |
| 661 | goto out_drop_write; | 680 | goto out_dput; |
| 662 | 681 | ||
| 663 | down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); | 682 | down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
| 664 | 683 | ||
| @@ -666,18 +685,16 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
| 666 | goto out_up_read; | 685 | goto out_up_read; |
| 667 | 686 | ||
| 668 | if (snap_src) { | 687 | if (snap_src) { |
| 669 | error = create_snapshot(snap_src, dentry, | 688 | error = create_snapshot(snap_src, dentry, name, namelen, |
| 670 | name, namelen, async_transid, readonly); | 689 | async_transid, readonly, inherit); |
| 671 | } else { | 690 | } else { |
| 672 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 691 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
| 673 | name, namelen, async_transid); | 692 | name, namelen, async_transid, inherit); |
| 674 | } | 693 | } |
| 675 | if (!error) | 694 | if (!error) |
| 676 | fsnotify_mkdir(dir, dentry); | 695 | fsnotify_mkdir(dir, dentry); |
| 677 | out_up_read: | 696 | out_up_read: |
| 678 | up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); | 697 | up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
| 679 | out_drop_write: | ||
| 680 | mnt_drop_write(parent->mnt); | ||
| 681 | out_dput: | 698 | out_dput: |
| 682 | dput(dentry); | 699 | dput(dentry); |
| 683 | out_unlock: | 700 | out_unlock: |
| @@ -832,7 +849,8 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) | |||
| 832 | } | 849 | } |
| 833 | 850 | ||
| 834 | static int should_defrag_range(struct inode *inode, u64 start, int thresh, | 851 | static int should_defrag_range(struct inode *inode, u64 start, int thresh, |
| 835 | u64 *last_len, u64 *skip, u64 *defrag_end) | 852 | u64 *last_len, u64 *skip, u64 *defrag_end, |
| 853 | int compress) | ||
| 836 | { | 854 | { |
| 837 | struct extent_map *em; | 855 | struct extent_map *em; |
| 838 | int ret = 1; | 856 | int ret = 1; |
| @@ -863,7 +881,7 @@ static int should_defrag_range(struct inode *inode, u64 start, int thresh, | |||
| 863 | * we hit a real extent, if it is big or the next extent is not a | 881 | * we hit a real extent, if it is big or the next extent is not a |
| 864 | * real extent, don't bother defragging it | 882 | * real extent, don't bother defragging it |
| 865 | */ | 883 | */ |
| 866 | if ((*last_len == 0 || *last_len >= thresh) && | 884 | if (!compress && (*last_len == 0 || *last_len >= thresh) && |
| 867 | (em->len >= thresh || !next_mergeable)) | 885 | (em->len >= thresh || !next_mergeable)) |
| 868 | ret = 0; | 886 | ret = 0; |
| 869 | out: | 887 | out: |
| @@ -1047,11 +1065,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
| 1047 | u64 newer_than, unsigned long max_to_defrag) | 1065 | u64 newer_than, unsigned long max_to_defrag) |
| 1048 | { | 1066 | { |
| 1049 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1067 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 1050 | struct btrfs_super_block *disk_super; | ||
| 1051 | struct file_ra_state *ra = NULL; | 1068 | struct file_ra_state *ra = NULL; |
| 1052 | unsigned long last_index; | 1069 | unsigned long last_index; |
| 1053 | u64 isize = i_size_read(inode); | 1070 | u64 isize = i_size_read(inode); |
| 1054 | u64 features; | ||
| 1055 | u64 last_len = 0; | 1071 | u64 last_len = 0; |
| 1056 | u64 skip = 0; | 1072 | u64 skip = 0; |
| 1057 | u64 defrag_end = 0; | 1073 | u64 defrag_end = 0; |
| @@ -1145,7 +1161,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
| 1145 | 1161 | ||
| 1146 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | 1162 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, |
| 1147 | extent_thresh, &last_len, &skip, | 1163 | extent_thresh, &last_len, &skip, |
| 1148 | &defrag_end)) { | 1164 | &defrag_end, range->flags & |
| 1165 | BTRFS_DEFRAG_RANGE_COMPRESS)) { | ||
| 1149 | unsigned long next; | 1166 | unsigned long next; |
| 1150 | /* | 1167 | /* |
| 1151 | * the should_defrag function tells us how much to skip | 1168 | * the should_defrag function tells us how much to skip |
| @@ -1237,11 +1254,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
| 1237 | mutex_unlock(&inode->i_mutex); | 1254 | mutex_unlock(&inode->i_mutex); |
| 1238 | } | 1255 | } |
| 1239 | 1256 | ||
| 1240 | disk_super = root->fs_info->super_copy; | ||
| 1241 | features = btrfs_super_incompat_flags(disk_super); | ||
| 1242 | if (range->compress_type == BTRFS_COMPRESS_LZO) { | 1257 | if (range->compress_type == BTRFS_COMPRESS_LZO) { |
| 1243 | features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; | 1258 | btrfs_set_fs_incompat(root->fs_info, COMPRESS_LZO); |
| 1244 | btrfs_set_super_incompat_flags(disk_super, features); | ||
| 1245 | } | 1259 | } |
| 1246 | 1260 | ||
| 1247 | ret = defrag_count; | 1261 | ret = defrag_count; |
| @@ -1379,41 +1393,39 @@ out: | |||
| 1379 | } | 1393 | } |
| 1380 | 1394 | ||
| 1381 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | 1395 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
| 1382 | char *name, | 1396 | char *name, unsigned long fd, int subvol, |
| 1383 | unsigned long fd, | 1397 | u64 *transid, bool readonly, |
| 1384 | int subvol, | 1398 | struct btrfs_qgroup_inherit **inherit) |
| 1385 | u64 *transid, | ||
| 1386 | bool readonly) | ||
| 1387 | { | 1399 | { |
| 1388 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
| 1389 | struct file *src_file; | 1400 | struct file *src_file; |
| 1390 | int namelen; | 1401 | int namelen; |
| 1391 | int ret = 0; | 1402 | int ret = 0; |
| 1392 | 1403 | ||
| 1393 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 1404 | ret = mnt_want_write_file(file); |
| 1394 | return -EROFS; | 1405 | if (ret) |
| 1406 | goto out; | ||
| 1395 | 1407 | ||
| 1396 | namelen = strlen(name); | 1408 | namelen = strlen(name); |
| 1397 | if (strchr(name, '/')) { | 1409 | if (strchr(name, '/')) { |
| 1398 | ret = -EINVAL; | 1410 | ret = -EINVAL; |
| 1399 | goto out; | 1411 | goto out_drop_write; |
| 1400 | } | 1412 | } |
| 1401 | 1413 | ||
| 1402 | if (name[0] == '.' && | 1414 | if (name[0] == '.' && |
| 1403 | (namelen == 1 || (name[1] == '.' && namelen == 2))) { | 1415 | (namelen == 1 || (name[1] == '.' && namelen == 2))) { |
| 1404 | ret = -EEXIST; | 1416 | ret = -EEXIST; |
| 1405 | goto out; | 1417 | goto out_drop_write; |
| 1406 | } | 1418 | } |
| 1407 | 1419 | ||
| 1408 | if (subvol) { | 1420 | if (subvol) { |
| 1409 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 1421 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
| 1410 | NULL, transid, readonly); | 1422 | NULL, transid, readonly, inherit); |
| 1411 | } else { | 1423 | } else { |
| 1412 | struct inode *src_inode; | 1424 | struct inode *src_inode; |
| 1413 | src_file = fget(fd); | 1425 | src_file = fget(fd); |
| 1414 | if (!src_file) { | 1426 | if (!src_file) { |
| 1415 | ret = -EINVAL; | 1427 | ret = -EINVAL; |
| 1416 | goto out; | 1428 | goto out_drop_write; |
| 1417 | } | 1429 | } |
| 1418 | 1430 | ||
| 1419 | src_inode = src_file->f_path.dentry->d_inode; | 1431 | src_inode = src_file->f_path.dentry->d_inode; |
| @@ -1422,13 +1434,15 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
| 1422 | "another FS\n"); | 1434 | "another FS\n"); |
| 1423 | ret = -EINVAL; | 1435 | ret = -EINVAL; |
| 1424 | fput(src_file); | 1436 | fput(src_file); |
| 1425 | goto out; | 1437 | goto out_drop_write; |
| 1426 | } | 1438 | } |
| 1427 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 1439 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
| 1428 | BTRFS_I(src_inode)->root, | 1440 | BTRFS_I(src_inode)->root, |
| 1429 | transid, readonly); | 1441 | transid, readonly, inherit); |
| 1430 | fput(src_file); | 1442 | fput(src_file); |
| 1431 | } | 1443 | } |
| 1444 | out_drop_write: | ||
| 1445 | mnt_drop_write_file(file); | ||
| 1432 | out: | 1446 | out: |
| 1433 | return ret; | 1447 | return ret; |
| 1434 | } | 1448 | } |
| @@ -1446,7 +1460,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 1446 | 1460 | ||
| 1447 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 1461 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
| 1448 | vol_args->fd, subvol, | 1462 | vol_args->fd, subvol, |
| 1449 | NULL, false); | 1463 | NULL, false, NULL); |
| 1450 | 1464 | ||
| 1451 | kfree(vol_args); | 1465 | kfree(vol_args); |
| 1452 | return ret; | 1466 | return ret; |
| @@ -1460,6 +1474,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
| 1460 | u64 transid = 0; | 1474 | u64 transid = 0; |
| 1461 | u64 *ptr = NULL; | 1475 | u64 *ptr = NULL; |
| 1462 | bool readonly = false; | 1476 | bool readonly = false; |
| 1477 | struct btrfs_qgroup_inherit *inherit = NULL; | ||
| 1463 | 1478 | ||
| 1464 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1479 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
| 1465 | if (IS_ERR(vol_args)) | 1480 | if (IS_ERR(vol_args)) |
| @@ -1467,7 +1482,8 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
| 1467 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | 1482 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; |
| 1468 | 1483 | ||
| 1469 | if (vol_args->flags & | 1484 | if (vol_args->flags & |
| 1470 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { | 1485 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY | |
| 1486 | BTRFS_SUBVOL_QGROUP_INHERIT)) { | ||
| 1471 | ret = -EOPNOTSUPP; | 1487 | ret = -EOPNOTSUPP; |
| 1472 | goto out; | 1488 | goto out; |
| 1473 | } | 1489 | } |
| @@ -1476,10 +1492,21 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
| 1476 | ptr = &transid; | 1492 | ptr = &transid; |
| 1477 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) | 1493 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) |
| 1478 | readonly = true; | 1494 | readonly = true; |
| 1495 | if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) { | ||
| 1496 | if (vol_args->size > PAGE_CACHE_SIZE) { | ||
| 1497 | ret = -EINVAL; | ||
| 1498 | goto out; | ||
| 1499 | } | ||
| 1500 | inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size); | ||
| 1501 | if (IS_ERR(inherit)) { | ||
| 1502 | ret = PTR_ERR(inherit); | ||
| 1503 | goto out; | ||
| 1504 | } | ||
| 1505 | } | ||
| 1479 | 1506 | ||
| 1480 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 1507 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
| 1481 | vol_args->fd, subvol, | 1508 | vol_args->fd, subvol, ptr, |
| 1482 | ptr, readonly); | 1509 | readonly, &inherit); |
| 1483 | 1510 | ||
| 1484 | if (ret == 0 && ptr && | 1511 | if (ret == 0 && ptr && |
| 1485 | copy_to_user(arg + | 1512 | copy_to_user(arg + |
| @@ -1488,6 +1515,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
| 1488 | ret = -EFAULT; | 1515 | ret = -EFAULT; |
| 1489 | out: | 1516 | out: |
| 1490 | kfree(vol_args); | 1517 | kfree(vol_args); |
| 1518 | kfree(inherit); | ||
| 1491 | return ret; | 1519 | return ret; |
| 1492 | } | 1520 | } |
| 1493 | 1521 | ||
| @@ -1523,29 +1551,40 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
| 1523 | u64 flags; | 1551 | u64 flags; |
| 1524 | int ret = 0; | 1552 | int ret = 0; |
| 1525 | 1553 | ||
| 1526 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 1554 | ret = mnt_want_write_file(file); |
| 1527 | return -EROFS; | 1555 | if (ret) |
| 1556 | goto out; | ||
| 1528 | 1557 | ||
| 1529 | if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) | 1558 | if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { |
| 1530 | return -EINVAL; | 1559 | ret = -EINVAL; |
| 1560 | goto out_drop_write; | ||
| 1561 | } | ||
| 1531 | 1562 | ||
| 1532 | if (copy_from_user(&flags, arg, sizeof(flags))) | 1563 | if (copy_from_user(&flags, arg, sizeof(flags))) { |
| 1533 | return -EFAULT; | 1564 | ret = -EFAULT; |
| 1565 | goto out_drop_write; | ||
| 1566 | } | ||
| 1534 | 1567 | ||
| 1535 | if (flags & BTRFS_SUBVOL_CREATE_ASYNC) | 1568 | if (flags & BTRFS_SUBVOL_CREATE_ASYNC) { |
| 1536 | return -EINVAL; | 1569 | ret = -EINVAL; |
| 1570 | goto out_drop_write; | ||
| 1571 | } | ||
| 1537 | 1572 | ||
| 1538 | if (flags & ~BTRFS_SUBVOL_RDONLY) | 1573 | if (flags & ~BTRFS_SUBVOL_RDONLY) { |
| 1539 | return -EOPNOTSUPP; | 1574 | ret = -EOPNOTSUPP; |
| 1575 | goto out_drop_write; | ||
| 1576 | } | ||
| 1540 | 1577 | ||
| 1541 | if (!inode_owner_or_capable(inode)) | 1578 | if (!inode_owner_or_capable(inode)) { |
| 1542 | return -EACCES; | 1579 | ret = -EACCES; |
| 1580 | goto out_drop_write; | ||
| 1581 | } | ||
| 1543 | 1582 | ||
| 1544 | down_write(&root->fs_info->subvol_sem); | 1583 | down_write(&root->fs_info->subvol_sem); |
| 1545 | 1584 | ||
| 1546 | /* nothing to do */ | 1585 | /* nothing to do */ |
| 1547 | if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) | 1586 | if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) |
| 1548 | goto out; | 1587 | goto out_drop_sem; |
| 1549 | 1588 | ||
| 1550 | root_flags = btrfs_root_flags(&root->root_item); | 1589 | root_flags = btrfs_root_flags(&root->root_item); |
| 1551 | if (flags & BTRFS_SUBVOL_RDONLY) | 1590 | if (flags & BTRFS_SUBVOL_RDONLY) |
| @@ -1568,8 +1607,11 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
| 1568 | out_reset: | 1607 | out_reset: |
| 1569 | if (ret) | 1608 | if (ret) |
| 1570 | btrfs_set_root_flags(&root->root_item, root_flags); | 1609 | btrfs_set_root_flags(&root->root_item, root_flags); |
| 1571 | out: | 1610 | out_drop_sem: |
| 1572 | up_write(&root->fs_info->subvol_sem); | 1611 | up_write(&root->fs_info->subvol_sem); |
| 1612 | out_drop_write: | ||
| 1613 | mnt_drop_write_file(file); | ||
| 1614 | out: | ||
| 1573 | return ret; | 1615 | return ret; |
| 1574 | } | 1616 | } |
| 1575 | 1617 | ||
| @@ -2340,6 +2382,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2340 | goto out_drop_write; | 2382 | goto out_drop_write; |
| 2341 | } | 2383 | } |
| 2342 | 2384 | ||
| 2385 | ret = -EXDEV; | ||
| 2386 | if (src_file->f_path.mnt != file->f_path.mnt) | ||
| 2387 | goto out_fput; | ||
| 2388 | |||
| 2343 | src = src_file->f_dentry->d_inode; | 2389 | src = src_file->f_dentry->d_inode; |
| 2344 | 2390 | ||
| 2345 | ret = -EINVAL; | 2391 | ret = -EINVAL; |
| @@ -2360,7 +2406,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2360 | goto out_fput; | 2406 | goto out_fput; |
| 2361 | 2407 | ||
| 2362 | ret = -EXDEV; | 2408 | ret = -EXDEV; |
| 2363 | if (src->i_sb != inode->i_sb || BTRFS_I(src)->root != root) | 2409 | if (src->i_sb != inode->i_sb) |
| 2364 | goto out_fput; | 2410 | goto out_fput; |
| 2365 | 2411 | ||
| 2366 | ret = -ENOMEM; | 2412 | ret = -ENOMEM; |
| @@ -2434,13 +2480,14 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 2434 | * note the key will change type as we walk through the | 2480 | * note the key will change type as we walk through the |
| 2435 | * tree. | 2481 | * tree. |
| 2436 | */ | 2482 | */ |
| 2437 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 2483 | ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, |
| 2484 | 0, 0); | ||
| 2438 | if (ret < 0) | 2485 | if (ret < 0) |
| 2439 | goto out; | 2486 | goto out; |
| 2440 | 2487 | ||
| 2441 | nritems = btrfs_header_nritems(path->nodes[0]); | 2488 | nritems = btrfs_header_nritems(path->nodes[0]); |
| 2442 | if (path->slots[0] >= nritems) { | 2489 | if (path->slots[0] >= nritems) { |
| 2443 | ret = btrfs_next_leaf(root, path); | 2490 | ret = btrfs_next_leaf(BTRFS_I(src)->root, path); |
| 2444 | if (ret < 0) | 2491 | if (ret < 0) |
| 2445 | goto out; | 2492 | goto out; |
| 2446 | if (ret > 0) | 2493 | if (ret > 0) |
| @@ -2749,8 +2796,6 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
| 2749 | struct btrfs_path *path; | 2796 | struct btrfs_path *path; |
| 2750 | struct btrfs_key location; | 2797 | struct btrfs_key location; |
| 2751 | struct btrfs_disk_key disk_key; | 2798 | struct btrfs_disk_key disk_key; |
| 2752 | struct btrfs_super_block *disk_super; | ||
| 2753 | u64 features; | ||
| 2754 | u64 objectid = 0; | 2799 | u64 objectid = 0; |
| 2755 | u64 dir_id; | 2800 | u64 dir_id; |
| 2756 | 2801 | ||
| @@ -2801,12 +2846,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
| 2801 | btrfs_mark_buffer_dirty(path->nodes[0]); | 2846 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 2802 | btrfs_free_path(path); | 2847 | btrfs_free_path(path); |
| 2803 | 2848 | ||
| 2804 | disk_super = root->fs_info->super_copy; | 2849 | btrfs_set_fs_incompat(root->fs_info, DEFAULT_SUBVOL); |
| 2805 | features = btrfs_super_incompat_flags(disk_super); | ||
| 2806 | if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { | ||
| 2807 | features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; | ||
| 2808 | btrfs_set_super_incompat_flags(disk_super, features); | ||
| 2809 | } | ||
| 2810 | btrfs_end_transaction(trans, root); | 2850 | btrfs_end_transaction(trans, root); |
| 2811 | 2851 | ||
| 2812 | return 0; | 2852 | return 0; |
| @@ -3063,19 +3103,21 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, | |||
| 3063 | } | 3103 | } |
| 3064 | 3104 | ||
| 3065 | static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root, | 3105 | static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root, |
| 3066 | void __user *arg, int reset_after_read) | 3106 | void __user *arg) |
| 3067 | { | 3107 | { |
| 3068 | struct btrfs_ioctl_get_dev_stats *sa; | 3108 | struct btrfs_ioctl_get_dev_stats *sa; |
| 3069 | int ret; | 3109 | int ret; |
| 3070 | 3110 | ||
| 3071 | if (reset_after_read && !capable(CAP_SYS_ADMIN)) | ||
| 3072 | return -EPERM; | ||
| 3073 | |||
| 3074 | sa = memdup_user(arg, sizeof(*sa)); | 3111 | sa = memdup_user(arg, sizeof(*sa)); |
| 3075 | if (IS_ERR(sa)) | 3112 | if (IS_ERR(sa)) |
| 3076 | return PTR_ERR(sa); | 3113 | return PTR_ERR(sa); |
| 3077 | 3114 | ||
| 3078 | ret = btrfs_get_dev_stats(root, sa, reset_after_read); | 3115 | if ((sa->flags & BTRFS_DEV_STATS_RESET) && !capable(CAP_SYS_ADMIN)) { |
| 3116 | kfree(sa); | ||
| 3117 | return -EPERM; | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | ret = btrfs_get_dev_stats(root, sa); | ||
| 3079 | 3121 | ||
| 3080 | if (copy_to_user(arg, sa, sizeof(*sa))) | 3122 | if (copy_to_user(arg, sa, sizeof(*sa))) |
| 3081 | ret = -EFAULT; | 3123 | ret = -EFAULT; |
| @@ -3265,10 +3307,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) | |||
| 3265 | if (!capable(CAP_SYS_ADMIN)) | 3307 | if (!capable(CAP_SYS_ADMIN)) |
| 3266 | return -EPERM; | 3308 | return -EPERM; |
| 3267 | 3309 | ||
| 3268 | if (fs_info->sb->s_flags & MS_RDONLY) | 3310 | ret = mnt_want_write_file(file); |
| 3269 | return -EROFS; | ||
| 3270 | |||
| 3271 | ret = mnt_want_write(file->f_path.mnt); | ||
| 3272 | if (ret) | 3311 | if (ret) |
| 3273 | return ret; | 3312 | return ret; |
| 3274 | 3313 | ||
| @@ -3338,7 +3377,7 @@ out_bargs: | |||
| 3338 | out: | 3377 | out: |
| 3339 | mutex_unlock(&fs_info->balance_mutex); | 3378 | mutex_unlock(&fs_info->balance_mutex); |
| 3340 | mutex_unlock(&fs_info->volume_mutex); | 3379 | mutex_unlock(&fs_info->volume_mutex); |
| 3341 | mnt_drop_write(file->f_path.mnt); | 3380 | mnt_drop_write_file(file); |
| 3342 | return ret; | 3381 | return ret; |
| 3343 | } | 3382 | } |
| 3344 | 3383 | ||
| @@ -3390,6 +3429,264 @@ out: | |||
| 3390 | return ret; | 3429 | return ret; |
| 3391 | } | 3430 | } |
| 3392 | 3431 | ||
| 3432 | static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg) | ||
| 3433 | { | ||
| 3434 | struct btrfs_ioctl_quota_ctl_args *sa; | ||
| 3435 | struct btrfs_trans_handle *trans = NULL; | ||
| 3436 | int ret; | ||
| 3437 | int err; | ||
| 3438 | |||
| 3439 | if (!capable(CAP_SYS_ADMIN)) | ||
| 3440 | return -EPERM; | ||
| 3441 | |||
| 3442 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 3443 | return -EROFS; | ||
| 3444 | |||
| 3445 | sa = memdup_user(arg, sizeof(*sa)); | ||
| 3446 | if (IS_ERR(sa)) | ||
| 3447 | return PTR_ERR(sa); | ||
| 3448 | |||
| 3449 | if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) { | ||
| 3450 | trans = btrfs_start_transaction(root, 2); | ||
| 3451 | if (IS_ERR(trans)) { | ||
| 3452 | ret = PTR_ERR(trans); | ||
| 3453 | goto out; | ||
| 3454 | } | ||
| 3455 | } | ||
| 3456 | |||
| 3457 | switch (sa->cmd) { | ||
| 3458 | case BTRFS_QUOTA_CTL_ENABLE: | ||
| 3459 | ret = btrfs_quota_enable(trans, root->fs_info); | ||
| 3460 | break; | ||
| 3461 | case BTRFS_QUOTA_CTL_DISABLE: | ||
| 3462 | ret = btrfs_quota_disable(trans, root->fs_info); | ||
| 3463 | break; | ||
| 3464 | case BTRFS_QUOTA_CTL_RESCAN: | ||
| 3465 | ret = btrfs_quota_rescan(root->fs_info); | ||
| 3466 | break; | ||
| 3467 | default: | ||
| 3468 | ret = -EINVAL; | ||
| 3469 | break; | ||
| 3470 | } | ||
| 3471 | |||
| 3472 | if (copy_to_user(arg, sa, sizeof(*sa))) | ||
| 3473 | ret = -EFAULT; | ||
| 3474 | |||
| 3475 | if (trans) { | ||
| 3476 | err = btrfs_commit_transaction(trans, root); | ||
| 3477 | if (err && !ret) | ||
| 3478 | ret = err; | ||
| 3479 | } | ||
| 3480 | |||
| 3481 | out: | ||
| 3482 | kfree(sa); | ||
| 3483 | return ret; | ||
| 3484 | } | ||
| 3485 | |||
| 3486 | static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg) | ||
| 3487 | { | ||
| 3488 | struct btrfs_ioctl_qgroup_assign_args *sa; | ||
| 3489 | struct btrfs_trans_handle *trans; | ||
| 3490 | int ret; | ||
| 3491 | int err; | ||
| 3492 | |||
| 3493 | if (!capable(CAP_SYS_ADMIN)) | ||
| 3494 | return -EPERM; | ||
| 3495 | |||
| 3496 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 3497 | return -EROFS; | ||
| 3498 | |||
| 3499 | sa = memdup_user(arg, sizeof(*sa)); | ||
| 3500 | if (IS_ERR(sa)) | ||
| 3501 | return PTR_ERR(sa); | ||
| 3502 | |||
| 3503 | trans = btrfs_join_transaction(root); | ||
| 3504 | if (IS_ERR(trans)) { | ||
| 3505 | ret = PTR_ERR(trans); | ||
| 3506 | goto out; | ||
| 3507 | } | ||
| 3508 | |||
| 3509 | /* FIXME: check if the IDs really exist */ | ||
| 3510 | if (sa->assign) { | ||
| 3511 | ret = btrfs_add_qgroup_relation(trans, root->fs_info, | ||
| 3512 | sa->src, sa->dst); | ||
| 3513 | } else { | ||
| 3514 | ret = btrfs_del_qgroup_relation(trans, root->fs_info, | ||
| 3515 | sa->src, sa->dst); | ||
| 3516 | } | ||
| 3517 | |||
| 3518 | err = btrfs_end_transaction(trans, root); | ||
| 3519 | if (err && !ret) | ||
| 3520 | ret = err; | ||
| 3521 | |||
| 3522 | out: | ||
| 3523 | kfree(sa); | ||
| 3524 | return ret; | ||
| 3525 | } | ||
| 3526 | |||
| 3527 | static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg) | ||
| 3528 | { | ||
| 3529 | struct btrfs_ioctl_qgroup_create_args *sa; | ||
| 3530 | struct btrfs_trans_handle *trans; | ||
| 3531 | int ret; | ||
| 3532 | int err; | ||
| 3533 | |||
| 3534 | if (!capable(CAP_SYS_ADMIN)) | ||
| 3535 | return -EPERM; | ||
| 3536 | |||
| 3537 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 3538 | return -EROFS; | ||
| 3539 | |||
| 3540 | sa = memdup_user(arg, sizeof(*sa)); | ||
| 3541 | if (IS_ERR(sa)) | ||
| 3542 | return PTR_ERR(sa); | ||
| 3543 | |||
| 3544 | trans = btrfs_join_transaction(root); | ||
| 3545 | if (IS_ERR(trans)) { | ||
| 3546 | ret = PTR_ERR(trans); | ||
| 3547 | goto out; | ||
| 3548 | } | ||
| 3549 | |||
| 3550 | /* FIXME: check if the IDs really exist */ | ||
| 3551 | if (sa->create) { | ||
| 3552 | ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid, | ||
| 3553 | NULL); | ||
| 3554 | } else { | ||
| 3555 | ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid); | ||
| 3556 | } | ||
| 3557 | |||
| 3558 | err = btrfs_end_transaction(trans, root); | ||
| 3559 | if (err && !ret) | ||
| 3560 | ret = err; | ||
| 3561 | |||
| 3562 | out: | ||
| 3563 | kfree(sa); | ||
| 3564 | return ret; | ||
| 3565 | } | ||
| 3566 | |||
| 3567 | static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg) | ||
| 3568 | { | ||
| 3569 | struct btrfs_ioctl_qgroup_limit_args *sa; | ||
| 3570 | struct btrfs_trans_handle *trans; | ||
| 3571 | int ret; | ||
| 3572 | int err; | ||
| 3573 | u64 qgroupid; | ||
| 3574 | |||
| 3575 | if (!capable(CAP_SYS_ADMIN)) | ||
| 3576 | return -EPERM; | ||
| 3577 | |||
| 3578 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 3579 | return -EROFS; | ||
| 3580 | |||
| 3581 | sa = memdup_user(arg, sizeof(*sa)); | ||
| 3582 | if (IS_ERR(sa)) | ||
| 3583 | return PTR_ERR(sa); | ||
| 3584 | |||
| 3585 | trans = btrfs_join_transaction(root); | ||
| 3586 | if (IS_ERR(trans)) { | ||
| 3587 | ret = PTR_ERR(trans); | ||
| 3588 | goto out; | ||
| 3589 | } | ||
| 3590 | |||
| 3591 | qgroupid = sa->qgroupid; | ||
| 3592 | if (!qgroupid) { | ||
| 3593 | /* take the current subvol as qgroup */ | ||
| 3594 | qgroupid = root->root_key.objectid; | ||
| 3595 | } | ||
| 3596 | |||
| 3597 | /* FIXME: check if the IDs really exist */ | ||
| 3598 | ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim); | ||
| 3599 | |||
| 3600 | err = btrfs_end_transaction(trans, root); | ||
| 3601 | if (err && !ret) | ||
| 3602 | ret = err; | ||
| 3603 | |||
| 3604 | out: | ||
| 3605 | kfree(sa); | ||
| 3606 | return ret; | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | static long btrfs_ioctl_set_received_subvol(struct file *file, | ||
| 3610 | void __user *arg) | ||
| 3611 | { | ||
| 3612 | struct btrfs_ioctl_received_subvol_args *sa = NULL; | ||
| 3613 | struct inode *inode = fdentry(file)->d_inode; | ||
| 3614 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
| 3615 | struct btrfs_root_item *root_item = &root->root_item; | ||
| 3616 | struct btrfs_trans_handle *trans; | ||
| 3617 | struct timespec ct = CURRENT_TIME; | ||
| 3618 | int ret = 0; | ||
| 3619 | |||
| 3620 | ret = mnt_want_write_file(file); | ||
| 3621 | if (ret < 0) | ||
| 3622 | return ret; | ||
| 3623 | |||
| 3624 | down_write(&root->fs_info->subvol_sem); | ||
| 3625 | |||
| 3626 | if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { | ||
| 3627 | ret = -EINVAL; | ||
| 3628 | goto out; | ||
| 3629 | } | ||
| 3630 | |||
| 3631 | if (btrfs_root_readonly(root)) { | ||
| 3632 | ret = -EROFS; | ||
| 3633 | goto out; | ||
| 3634 | } | ||
| 3635 | |||
| 3636 | if (!inode_owner_or_capable(inode)) { | ||
| 3637 | ret = -EACCES; | ||
| 3638 | goto out; | ||
| 3639 | } | ||
| 3640 | |||
| 3641 | sa = memdup_user(arg, sizeof(*sa)); | ||
| 3642 | if (IS_ERR(sa)) { | ||
| 3643 | ret = PTR_ERR(sa); | ||
| 3644 | sa = NULL; | ||
| 3645 | goto out; | ||
| 3646 | } | ||
| 3647 | |||
| 3648 | trans = btrfs_start_transaction(root, 1); | ||
| 3649 | if (IS_ERR(trans)) { | ||
| 3650 | ret = PTR_ERR(trans); | ||
| 3651 | trans = NULL; | ||
| 3652 | goto out; | ||
| 3653 | } | ||
| 3654 | |||
| 3655 | sa->rtransid = trans->transid; | ||
| 3656 | sa->rtime.sec = ct.tv_sec; | ||
| 3657 | sa->rtime.nsec = ct.tv_nsec; | ||
| 3658 | |||
| 3659 | memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE); | ||
| 3660 | btrfs_set_root_stransid(root_item, sa->stransid); | ||
| 3661 | btrfs_set_root_rtransid(root_item, sa->rtransid); | ||
| 3662 | root_item->stime.sec = cpu_to_le64(sa->stime.sec); | ||
| 3663 | root_item->stime.nsec = cpu_to_le32(sa->stime.nsec); | ||
| 3664 | root_item->rtime.sec = cpu_to_le64(sa->rtime.sec); | ||
| 3665 | root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec); | ||
| 3666 | |||
| 3667 | ret = btrfs_update_root(trans, root->fs_info->tree_root, | ||
| 3668 | &root->root_key, &root->root_item); | ||
| 3669 | if (ret < 0) { | ||
| 3670 | btrfs_end_transaction(trans, root); | ||
| 3671 | trans = NULL; | ||
| 3672 | goto out; | ||
| 3673 | } else { | ||
| 3674 | ret = btrfs_commit_transaction(trans, root); | ||
| 3675 | if (ret < 0) | ||
| 3676 | goto out; | ||
| 3677 | } | ||
| 3678 | |||
| 3679 | ret = copy_to_user(arg, sa, sizeof(*sa)); | ||
| 3680 | if (ret) | ||
| 3681 | ret = -EFAULT; | ||
| 3682 | |||
| 3683 | out: | ||
| 3684 | kfree(sa); | ||
| 3685 | up_write(&root->fs_info->subvol_sem); | ||
| 3686 | mnt_drop_write_file(file); | ||
| 3687 | return ret; | ||
| 3688 | } | ||
| 3689 | |||
| 3393 | long btrfs_ioctl(struct file *file, unsigned int | 3690 | long btrfs_ioctl(struct file *file, unsigned int |
| 3394 | cmd, unsigned long arg) | 3691 | cmd, unsigned long arg) |
| 3395 | { | 3692 | { |
| @@ -3411,6 +3708,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 3411 | return btrfs_ioctl_snap_create_v2(file, argp, 0); | 3708 | return btrfs_ioctl_snap_create_v2(file, argp, 0); |
| 3412 | case BTRFS_IOC_SUBVOL_CREATE: | 3709 | case BTRFS_IOC_SUBVOL_CREATE: |
| 3413 | return btrfs_ioctl_snap_create(file, argp, 1); | 3710 | return btrfs_ioctl_snap_create(file, argp, 1); |
| 3711 | case BTRFS_IOC_SUBVOL_CREATE_V2: | ||
| 3712 | return btrfs_ioctl_snap_create_v2(file, argp, 1); | ||
| 3414 | case BTRFS_IOC_SNAP_DESTROY: | 3713 | case BTRFS_IOC_SNAP_DESTROY: |
| 3415 | return btrfs_ioctl_snap_destroy(file, argp); | 3714 | return btrfs_ioctl_snap_destroy(file, argp); |
| 3416 | case BTRFS_IOC_SUBVOL_GETFLAGS: | 3715 | case BTRFS_IOC_SUBVOL_GETFLAGS: |
| @@ -3472,10 +3771,20 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 3472 | return btrfs_ioctl_balance_ctl(root, arg); | 3771 | return btrfs_ioctl_balance_ctl(root, arg); |
| 3473 | case BTRFS_IOC_BALANCE_PROGRESS: | 3772 | case BTRFS_IOC_BALANCE_PROGRESS: |
| 3474 | return btrfs_ioctl_balance_progress(root, argp); | 3773 | return btrfs_ioctl_balance_progress(root, argp); |
| 3774 | case BTRFS_IOC_SET_RECEIVED_SUBVOL: | ||
| 3775 | return btrfs_ioctl_set_received_subvol(file, argp); | ||
| 3776 | case BTRFS_IOC_SEND: | ||
| 3777 | return btrfs_ioctl_send(file, argp); | ||
| 3475 | case BTRFS_IOC_GET_DEV_STATS: | 3778 | case BTRFS_IOC_GET_DEV_STATS: |
| 3476 | return btrfs_ioctl_get_dev_stats(root, argp, 0); | 3779 | return btrfs_ioctl_get_dev_stats(root, argp); |
| 3477 | case BTRFS_IOC_GET_AND_RESET_DEV_STATS: | 3780 | case BTRFS_IOC_QUOTA_CTL: |
| 3478 | return btrfs_ioctl_get_dev_stats(root, argp, 1); | 3781 | return btrfs_ioctl_quota_ctl(root, argp); |
| 3782 | case BTRFS_IOC_QGROUP_ASSIGN: | ||
| 3783 | return btrfs_ioctl_qgroup_assign(root, argp); | ||
| 3784 | case BTRFS_IOC_QGROUP_CREATE: | ||
| 3785 | return btrfs_ioctl_qgroup_create(root, argp); | ||
| 3786 | case BTRFS_IOC_QGROUP_LIMIT: | ||
| 3787 | return btrfs_ioctl_qgroup_limit(root, argp); | ||
| 3479 | } | 3788 | } |
| 3480 | 3789 | ||
| 3481 | return -ENOTTY; | 3790 | return -ENOTTY; |
