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: |