diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 339 |
1 files changed, 187 insertions, 152 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index bd88f25889f7..a8577a7f26ab 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -230,8 +230,8 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 230 | struct btrfs_root_item root_item; | 230 | struct btrfs_root_item root_item; |
| 231 | struct btrfs_inode_item *inode_item; | 231 | struct btrfs_inode_item *inode_item; |
| 232 | struct extent_buffer *leaf; | 232 | struct extent_buffer *leaf; |
| 233 | struct btrfs_root *new_root = root; | 233 | struct btrfs_root *new_root; |
| 234 | struct inode *dir; | 234 | struct inode *dir = dentry->d_parent->d_inode; |
| 235 | int ret; | 235 | int ret; |
| 236 | int err; | 236 | int err; |
| 237 | u64 objectid; | 237 | u64 objectid; |
| @@ -241,7 +241,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 241 | 241 | ||
| 242 | ret = btrfs_check_metadata_free_space(root); | 242 | ret = btrfs_check_metadata_free_space(root); |
| 243 | if (ret) | 243 | if (ret) |
| 244 | goto fail_commit; | 244 | return ret; |
| 245 | 245 | ||
| 246 | trans = btrfs_start_transaction(root, 1); | 246 | trans = btrfs_start_transaction(root, 1); |
| 247 | BUG_ON(!trans); | 247 | BUG_ON(!trans); |
| @@ -304,11 +304,17 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 304 | if (ret) | 304 | if (ret) |
| 305 | goto fail; | 305 | goto fail; |
| 306 | 306 | ||
| 307 | key.offset = (u64)-1; | ||
| 308 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); | ||
| 309 | BUG_ON(IS_ERR(new_root)); | ||
| 310 | |||
| 311 | btrfs_record_root_in_trans(trans, new_root); | ||
| 312 | |||
| 313 | ret = btrfs_create_subvol_root(trans, new_root, new_dirid, | ||
| 314 | BTRFS_I(dir)->block_group); | ||
| 307 | /* | 315 | /* |
| 308 | * insert the directory item | 316 | * insert the directory item |
| 309 | */ | 317 | */ |
| 310 | key.offset = (u64)-1; | ||
| 311 | dir = dentry->d_parent->d_inode; | ||
| 312 | ret = btrfs_set_inode_index(dir, &index); | 318 | ret = btrfs_set_inode_index(dir, &index); |
| 313 | BUG_ON(ret); | 319 | BUG_ON(ret); |
| 314 | 320 | ||
| @@ -322,44 +328,18 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
| 322 | ret = btrfs_update_inode(trans, root, dir); | 328 | ret = btrfs_update_inode(trans, root, dir); |
| 323 | BUG_ON(ret); | 329 | BUG_ON(ret); |
| 324 | 330 | ||
| 325 | /* add the backref first */ | ||
| 326 | ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, | 331 | ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, |
| 327 | objectid, BTRFS_ROOT_BACKREF_KEY, | 332 | objectid, root->root_key.objectid, |
| 328 | root->root_key.objectid, | ||
| 329 | dir->i_ino, index, name, namelen); | 333 | dir->i_ino, index, name, namelen); |
| 330 | 334 | ||
| 331 | BUG_ON(ret); | 335 | BUG_ON(ret); |
| 332 | 336 | ||
| 333 | /* now add the forward ref */ | 337 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
| 334 | ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, | ||
| 335 | root->root_key.objectid, BTRFS_ROOT_REF_KEY, | ||
| 336 | objectid, | ||
| 337 | dir->i_ino, index, name, namelen); | ||
| 338 | |||
| 339 | BUG_ON(ret); | ||
| 340 | |||
| 341 | ret = btrfs_commit_transaction(trans, root); | ||
| 342 | if (ret) | ||
| 343 | goto fail_commit; | ||
| 344 | |||
| 345 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); | ||
| 346 | BUG_ON(!new_root); | ||
| 347 | |||
| 348 | trans = btrfs_start_transaction(new_root, 1); | ||
| 349 | BUG_ON(!trans); | ||
| 350 | |||
| 351 | ret = btrfs_create_subvol_root(trans, new_root, dentry, new_dirid, | ||
| 352 | BTRFS_I(dir)->block_group); | ||
| 353 | if (ret) | ||
| 354 | goto fail; | ||
| 355 | |||
| 356 | fail: | 338 | fail: |
| 357 | nr = trans->blocks_used; | 339 | nr = trans->blocks_used; |
| 358 | err = btrfs_commit_transaction(trans, new_root); | 340 | err = btrfs_commit_transaction(trans, root); |
| 359 | if (err && !ret) | 341 | if (err && !ret) |
| 360 | ret = err; | 342 | ret = err; |
| 361 | fail_commit: | ||
| 362 | btrfs_btree_balance_dirty(root, nr); | ||
| 363 | return ret; | 343 | return ret; |
| 364 | } | 344 | } |
| 365 | 345 | ||
| @@ -420,14 +400,15 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
| 420 | * sys_mkdirat and vfs_mkdir, but we only do a single component lookup | 400 | * sys_mkdirat and vfs_mkdir, but we only do a single component lookup |
| 421 | * inside this filesystem so it's quite a bit simpler. | 401 | * inside this filesystem so it's quite a bit simpler. |
| 422 | */ | 402 | */ |
| 423 | static noinline int btrfs_mksubvol(struct path *parent, char *name, | 403 | static noinline int btrfs_mksubvol(struct path *parent, |
| 424 | int mode, int namelen, | 404 | char *name, int namelen, |
| 425 | struct btrfs_root *snap_src) | 405 | struct btrfs_root *snap_src) |
| 426 | { | 406 | { |
| 407 | struct inode *dir = parent->dentry->d_inode; | ||
| 427 | struct dentry *dentry; | 408 | struct dentry *dentry; |
| 428 | int error; | 409 | int error; |
| 429 | 410 | ||
| 430 | mutex_lock_nested(&parent->dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 411 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
| 431 | 412 | ||
| 432 | dentry = lookup_one_len(name, parent->dentry, namelen); | 413 | dentry = lookup_one_len(name, parent->dentry, namelen); |
| 433 | error = PTR_ERR(dentry); | 414 | error = PTR_ERR(dentry); |
| @@ -438,99 +419,39 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name, | |||
| 438 | if (dentry->d_inode) | 419 | if (dentry->d_inode) |
| 439 | goto out_dput; | 420 | goto out_dput; |
| 440 | 421 | ||
| 441 | if (!IS_POSIXACL(parent->dentry->d_inode)) | ||
| 442 | mode &= ~current_umask(); | ||
| 443 | |||
| 444 | error = mnt_want_write(parent->mnt); | 422 | error = mnt_want_write(parent->mnt); |
| 445 | if (error) | 423 | if (error) |
| 446 | goto out_dput; | 424 | goto out_dput; |
| 447 | 425 | ||
| 448 | error = btrfs_may_create(parent->dentry->d_inode, dentry); | 426 | error = btrfs_may_create(dir, dentry); |
| 449 | if (error) | 427 | if (error) |
| 450 | goto out_drop_write; | 428 | goto out_drop_write; |
| 451 | 429 | ||
| 452 | /* | 430 | down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
| 453 | * Actually perform the low-level subvolume creation after all | 431 | |
| 454 | * this VFS fuzz. | 432 | if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) |
| 455 | * | 433 | goto out_up_read; |
| 456 | * Eventually we want to pass in an inode under which we create this | 434 | |
| 457 | * subvolume, but for now all are under the filesystem root. | ||
| 458 | * | ||
| 459 | * Also we should pass on the mode eventually to allow creating new | ||
| 460 | * subvolume with specific mode bits. | ||
| 461 | */ | ||
| 462 | if (snap_src) { | 435 | if (snap_src) { |
| 463 | struct dentry *dir = dentry->d_parent; | 436 | error = create_snapshot(snap_src, dentry, |
| 464 | struct dentry *test = dir->d_parent; | 437 | name, namelen); |
| 465 | struct btrfs_path *path = btrfs_alloc_path(); | ||
| 466 | int ret; | ||
| 467 | u64 test_oid; | ||
| 468 | u64 parent_oid = BTRFS_I(dir->d_inode)->root->root_key.objectid; | ||
| 469 | |||
| 470 | test_oid = snap_src->root_key.objectid; | ||
| 471 | |||
| 472 | ret = btrfs_find_root_ref(snap_src->fs_info->tree_root, | ||
| 473 | path, parent_oid, test_oid); | ||
| 474 | if (ret == 0) | ||
| 475 | goto create; | ||
| 476 | btrfs_release_path(snap_src->fs_info->tree_root, path); | ||
| 477 | |||
| 478 | /* we need to make sure we aren't creating a directory loop | ||
| 479 | * by taking a snapshot of something that has our current | ||
| 480 | * subvol in its directory tree. So, this loops through | ||
| 481 | * the dentries and checks the forward refs for each subvolume | ||
| 482 | * to see if is references the subvolume where we are | ||
| 483 | * placing this new snapshot. | ||
| 484 | */ | ||
| 485 | while (1) { | ||
| 486 | if (!test || | ||
| 487 | dir == snap_src->fs_info->sb->s_root || | ||
| 488 | test == snap_src->fs_info->sb->s_root || | ||
| 489 | test->d_inode->i_sb != snap_src->fs_info->sb) { | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | if (S_ISLNK(test->d_inode->i_mode)) { | ||
| 493 | printk(KERN_INFO "Btrfs symlink in snapshot " | ||
| 494 | "path, failed\n"); | ||
| 495 | error = -EMLINK; | ||
| 496 | btrfs_free_path(path); | ||
| 497 | goto out_drop_write; | ||
| 498 | } | ||
| 499 | test_oid = | ||
| 500 | BTRFS_I(test->d_inode)->root->root_key.objectid; | ||
| 501 | ret = btrfs_find_root_ref(snap_src->fs_info->tree_root, | ||
| 502 | path, test_oid, parent_oid); | ||
| 503 | if (ret == 0) { | ||
| 504 | printk(KERN_INFO "Btrfs snapshot creation " | ||
| 505 | "failed, looping\n"); | ||
| 506 | error = -EMLINK; | ||
| 507 | btrfs_free_path(path); | ||
| 508 | goto out_drop_write; | ||
| 509 | } | ||
| 510 | btrfs_release_path(snap_src->fs_info->tree_root, path); | ||
| 511 | test = test->d_parent; | ||
| 512 | } | ||
| 513 | create: | ||
| 514 | btrfs_free_path(path); | ||
| 515 | error = create_snapshot(snap_src, dentry, name, namelen); | ||
| 516 | } else { | 438 | } else { |
| 517 | error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, | 439 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
| 518 | dentry, name, namelen); | 440 | name, namelen); |
| 519 | } | 441 | } |
| 520 | if (error) | 442 | if (!error) |
| 521 | goto out_drop_write; | 443 | fsnotify_mkdir(dir, dentry); |
| 522 | 444 | out_up_read: | |
| 523 | fsnotify_mkdir(parent->dentry->d_inode, dentry); | 445 | up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
| 524 | out_drop_write: | 446 | out_drop_write: |
| 525 | mnt_drop_write(parent->mnt); | 447 | mnt_drop_write(parent->mnt); |
| 526 | out_dput: | 448 | out_dput: |
| 527 | dput(dentry); | 449 | dput(dentry); |
| 528 | out_unlock: | 450 | out_unlock: |
| 529 | mutex_unlock(&parent->dentry->d_inode->i_mutex); | 451 | mutex_unlock(&dir->i_mutex); |
| 530 | return error; | 452 | return error; |
| 531 | } | 453 | } |
| 532 | 454 | ||
| 533 | |||
| 534 | static int btrfs_defrag_file(struct file *file) | 455 | static int btrfs_defrag_file(struct file *file) |
| 535 | { | 456 | { |
| 536 | struct inode *inode = fdentry(file)->d_inode; | 457 | struct inode *inode = fdentry(file)->d_inode; |
| @@ -596,9 +517,8 @@ again: | |||
| 596 | clear_page_dirty_for_io(page); | 517 | clear_page_dirty_for_io(page); |
| 597 | 518 | ||
| 598 | btrfs_set_extent_delalloc(inode, page_start, page_end); | 519 | btrfs_set_extent_delalloc(inode, page_start, page_end); |
| 599 | |||
| 600 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||
| 601 | set_page_dirty(page); | 520 | set_page_dirty(page); |
| 521 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||
| 602 | unlock_page(page); | 522 | unlock_page(page); |
| 603 | page_cache_release(page); | 523 | page_cache_release(page); |
| 604 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); | 524 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); |
| @@ -609,7 +529,8 @@ out_unlock: | |||
| 609 | return 0; | 529 | return 0; |
| 610 | } | 530 | } |
| 611 | 531 | ||
| 612 | static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) | 532 | static noinline int btrfs_ioctl_resize(struct btrfs_root *root, |
| 533 | void __user *arg) | ||
| 613 | { | 534 | { |
| 614 | u64 new_size; | 535 | u64 new_size; |
| 615 | u64 old_size; | 536 | u64 old_size; |
| @@ -718,10 +639,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 718 | { | 639 | { |
| 719 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 640 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
| 720 | struct btrfs_ioctl_vol_args *vol_args; | 641 | struct btrfs_ioctl_vol_args *vol_args; |
| 721 | struct btrfs_dir_item *di; | ||
| 722 | struct btrfs_path *path; | ||
| 723 | struct file *src_file; | 642 | struct file *src_file; |
| 724 | u64 root_dirid; | ||
| 725 | int namelen; | 643 | int namelen; |
| 726 | int ret = 0; | 644 | int ret = 0; |
| 727 | 645 | ||
| @@ -739,32 +657,9 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 739 | goto out; | 657 | goto out; |
| 740 | } | 658 | } |
| 741 | 659 | ||
| 742 | path = btrfs_alloc_path(); | ||
| 743 | if (!path) { | ||
| 744 | ret = -ENOMEM; | ||
| 745 | goto out; | ||
| 746 | } | ||
| 747 | |||
| 748 | root_dirid = root->fs_info->sb->s_root->d_inode->i_ino, | ||
| 749 | di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, | ||
| 750 | path, root_dirid, | ||
| 751 | vol_args->name, namelen, 0); | ||
| 752 | btrfs_free_path(path); | ||
| 753 | |||
| 754 | if (di && !IS_ERR(di)) { | ||
| 755 | ret = -EEXIST; | ||
| 756 | goto out; | ||
| 757 | } | ||
| 758 | |||
| 759 | if (IS_ERR(di)) { | ||
| 760 | ret = PTR_ERR(di); | ||
| 761 | goto out; | ||
| 762 | } | ||
| 763 | |||
| 764 | if (subvol) { | 660 | if (subvol) { |
| 765 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | 661 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, |
| 766 | file->f_path.dentry->d_inode->i_mode, | 662 | NULL); |
| 767 | namelen, NULL); | ||
| 768 | } else { | 663 | } else { |
| 769 | struct inode *src_inode; | 664 | struct inode *src_inode; |
| 770 | src_file = fget(vol_args->fd); | 665 | src_file = fget(vol_args->fd); |
| @@ -781,17 +676,156 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
| 781 | fput(src_file); | 676 | fput(src_file); |
| 782 | goto out; | 677 | goto out; |
| 783 | } | 678 | } |
| 784 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | 679 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, |
| 785 | file->f_path.dentry->d_inode->i_mode, | 680 | BTRFS_I(src_inode)->root); |
| 786 | namelen, BTRFS_I(src_inode)->root); | ||
| 787 | fput(src_file); | 681 | fput(src_file); |
| 788 | } | 682 | } |
| 789 | |||
| 790 | out: | 683 | out: |
| 791 | kfree(vol_args); | 684 | kfree(vol_args); |
| 792 | return ret; | 685 | return ret; |
| 793 | } | 686 | } |
| 794 | 687 | ||
| 688 | /* | ||
| 689 | * helper to check if the subvolume references other subvolumes | ||
| 690 | */ | ||
| 691 | static noinline int may_destroy_subvol(struct btrfs_root *root) | ||
| 692 | { | ||
| 693 | struct btrfs_path *path; | ||
| 694 | struct btrfs_key key; | ||
| 695 | int ret; | ||
| 696 | |||
| 697 | path = btrfs_alloc_path(); | ||
| 698 | if (!path) | ||
| 699 | return -ENOMEM; | ||
| 700 | |||
| 701 | key.objectid = root->root_key.objectid; | ||
| 702 | key.type = BTRFS_ROOT_REF_KEY; | ||
| 703 | key.offset = (u64)-1; | ||
| 704 | |||
| 705 | ret = btrfs_search_slot(NULL, root->fs_info->tree_root, | ||
| 706 | &key, path, 0, 0); | ||
| 707 | if (ret < 0) | ||
| 708 | goto out; | ||
| 709 | BUG_ON(ret == 0); | ||
| 710 | |||
| 711 | ret = 0; | ||
| 712 | if (path->slots[0] > 0) { | ||
| 713 | path->slots[0]--; | ||
| 714 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
| 715 | if (key.objectid == root->root_key.objectid && | ||
| 716 | key.type == BTRFS_ROOT_REF_KEY) | ||
| 717 | ret = -ENOTEMPTY; | ||
| 718 | } | ||
| 719 | out: | ||
| 720 | btrfs_free_path(path); | ||
| 721 | return ret; | ||
| 722 | } | ||
| 723 | |||
| 724 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, | ||
| 725 | void __user *arg) | ||
| 726 | { | ||
| 727 | struct dentry *parent = fdentry(file); | ||
| 728 | struct dentry *dentry; | ||
| 729 | struct inode *dir = parent->d_inode; | ||
| 730 | struct inode *inode; | ||
| 731 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
| 732 | struct btrfs_root *dest = NULL; | ||
| 733 | struct btrfs_ioctl_vol_args *vol_args; | ||
| 734 | struct btrfs_trans_handle *trans; | ||
| 735 | int namelen; | ||
| 736 | int ret; | ||
| 737 | int err = 0; | ||
| 738 | |||
| 739 | if (!capable(CAP_SYS_ADMIN)) | ||
| 740 | return -EPERM; | ||
| 741 | |||
| 742 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
| 743 | if (IS_ERR(vol_args)) | ||
| 744 | return PTR_ERR(vol_args); | ||
| 745 | |||
| 746 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
| 747 | namelen = strlen(vol_args->name); | ||
| 748 | if (strchr(vol_args->name, '/') || | ||
| 749 | strncmp(vol_args->name, "..", namelen) == 0) { | ||
| 750 | err = -EINVAL; | ||
| 751 | goto out; | ||
| 752 | } | ||
| 753 | |||
| 754 | err = mnt_want_write(file->f_path.mnt); | ||
| 755 | if (err) | ||
| 756 | goto out; | ||
| 757 | |||
| 758 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | ||
| 759 | dentry = lookup_one_len(vol_args->name, parent, namelen); | ||
| 760 | if (IS_ERR(dentry)) { | ||
| 761 | err = PTR_ERR(dentry); | ||
| 762 | goto out_unlock_dir; | ||
| 763 | } | ||
| 764 | |||
| 765 | if (!dentry->d_inode) { | ||
| 766 | err = -ENOENT; | ||
| 767 | goto out_dput; | ||
| 768 | } | ||
| 769 | |||
| 770 | inode = dentry->d_inode; | ||
| 771 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { | ||
| 772 | err = -EINVAL; | ||
| 773 | goto out_dput; | ||
| 774 | } | ||
| 775 | |||
| 776 | dest = BTRFS_I(inode)->root; | ||
| 777 | |||
| 778 | mutex_lock(&inode->i_mutex); | ||
| 779 | err = d_invalidate(dentry); | ||
| 780 | if (err) | ||
| 781 | goto out_unlock; | ||
| 782 | |||
| 783 | down_write(&root->fs_info->subvol_sem); | ||
| 784 | |||
| 785 | err = may_destroy_subvol(dest); | ||
| 786 | if (err) | ||
| 787 | goto out_up_write; | ||
| 788 | |||
| 789 | trans = btrfs_start_transaction(root, 1); | ||
| 790 | ret = btrfs_unlink_subvol(trans, root, dir, | ||
| 791 | dest->root_key.objectid, | ||
| 792 | dentry->d_name.name, | ||
| 793 | dentry->d_name.len); | ||
| 794 | BUG_ON(ret); | ||
| 795 | |||
| 796 | btrfs_record_root_in_trans(trans, dest); | ||
| 797 | |||
| 798 | memset(&dest->root_item.drop_progress, 0, | ||
| 799 | sizeof(dest->root_item.drop_progress)); | ||
| 800 | dest->root_item.drop_level = 0; | ||
| 801 | btrfs_set_root_refs(&dest->root_item, 0); | ||
| 802 | |||
| 803 | ret = btrfs_insert_orphan_item(trans, | ||
| 804 | root->fs_info->tree_root, | ||
| 805 | dest->root_key.objectid); | ||
| 806 | BUG_ON(ret); | ||
| 807 | |||
| 808 | ret = btrfs_commit_transaction(trans, root); | ||
| 809 | BUG_ON(ret); | ||
| 810 | inode->i_flags |= S_DEAD; | ||
| 811 | out_up_write: | ||
| 812 | up_write(&root->fs_info->subvol_sem); | ||
| 813 | out_unlock: | ||
| 814 | mutex_unlock(&inode->i_mutex); | ||
| 815 | if (!err) { | ||
| 816 | btrfs_invalidate_inodes(dest); | ||
| 817 | d_delete(dentry); | ||
| 818 | } | ||
| 819 | out_dput: | ||
| 820 | dput(dentry); | ||
| 821 | out_unlock_dir: | ||
| 822 | mutex_unlock(&dir->i_mutex); | ||
| 823 | mnt_drop_write(file->f_path.mnt); | ||
| 824 | out: | ||
| 825 | kfree(vol_args); | ||
| 826 | return err; | ||
| 827 | } | ||
| 828 | |||
| 795 | static int btrfs_ioctl_defrag(struct file *file) | 829 | static int btrfs_ioctl_defrag(struct file *file) |
| 796 | { | 830 | { |
| 797 | struct inode *inode = fdentry(file)->d_inode; | 831 | struct inode *inode = fdentry(file)->d_inode; |
| @@ -865,8 +899,8 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
| 865 | return ret; | 899 | return ret; |
| 866 | } | 900 | } |
| 867 | 901 | ||
| 868 | static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | 902 | static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, |
| 869 | u64 off, u64 olen, u64 destoff) | 903 | u64 off, u64 olen, u64 destoff) |
| 870 | { | 904 | { |
| 871 | struct inode *inode = fdentry(file)->d_inode; | 905 | struct inode *inode = fdentry(file)->d_inode; |
| 872 | struct btrfs_root *root = BTRFS_I(inode)->root; | 906 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| @@ -976,7 +1010,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 976 | 1010 | ||
| 977 | /* punch hole in destination first */ | 1011 | /* punch hole in destination first */ |
| 978 | btrfs_drop_extents(trans, root, inode, off, off + len, | 1012 | btrfs_drop_extents(trans, root, inode, off, off + len, |
| 979 | off + len, 0, &hint_byte); | 1013 | off + len, 0, &hint_byte, 1); |
| 980 | 1014 | ||
| 981 | /* clone data */ | 1015 | /* clone data */ |
| 982 | key.objectid = src->i_ino; | 1016 | key.objectid = src->i_ino; |
| @@ -1071,8 +1105,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
| 1071 | datao += off - key.offset; | 1105 | datao += off - key.offset; |
| 1072 | datal -= off - key.offset; | 1106 | datal -= off - key.offset; |
| 1073 | } | 1107 | } |
| 1074 | if (key.offset + datao + datal + key.offset > | 1108 | if (key.offset + datao + datal > off + len) |
| 1075 | off + len) | ||
| 1076 | datal = off + len - key.offset - datao; | 1109 | datal = off + len - key.offset - datao; |
| 1077 | /* disko == 0 means it's a hole */ | 1110 | /* disko == 0 means it's a hole */ |
| 1078 | if (!disko) | 1111 | if (!disko) |
| @@ -1258,6 +1291,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 1258 | return btrfs_ioctl_snap_create(file, argp, 0); | 1291 | return btrfs_ioctl_snap_create(file, argp, 0); |
| 1259 | case BTRFS_IOC_SUBVOL_CREATE: | 1292 | case BTRFS_IOC_SUBVOL_CREATE: |
| 1260 | return btrfs_ioctl_snap_create(file, argp, 1); | 1293 | return btrfs_ioctl_snap_create(file, argp, 1); |
| 1294 | case BTRFS_IOC_SNAP_DESTROY: | ||
| 1295 | return btrfs_ioctl_snap_destroy(file, argp); | ||
| 1261 | case BTRFS_IOC_DEFRAG: | 1296 | case BTRFS_IOC_DEFRAG: |
| 1262 | return btrfs_ioctl_defrag(file); | 1297 | return btrfs_ioctl_defrag(file); |
| 1263 | case BTRFS_IOC_RESIZE: | 1298 | case BTRFS_IOC_RESIZE: |
