diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 404 |
1 files changed, 231 insertions, 173 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index bd88f25889f7..cdbb054102b9 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; |
@@ -239,9 +239,15 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
239 | u64 index = 0; | 239 | u64 index = 0; |
240 | unsigned long nr = 1; | 240 | unsigned long nr = 1; |
241 | 241 | ||
242 | ret = btrfs_check_metadata_free_space(root); | 242 | /* |
243 | * 1 - inode item | ||
244 | * 2 - refs | ||
245 | * 1 - root item | ||
246 | * 2 - dir items | ||
247 | */ | ||
248 | ret = btrfs_reserve_metadata_space(root, 6); | ||
243 | if (ret) | 249 | if (ret) |
244 | goto fail_commit; | 250 | return ret; |
245 | 251 | ||
246 | trans = btrfs_start_transaction(root, 1); | 252 | trans = btrfs_start_transaction(root, 1); |
247 | BUG_ON(!trans); | 253 | BUG_ON(!trans); |
@@ -304,11 +310,17 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
304 | if (ret) | 310 | if (ret) |
305 | goto fail; | 311 | goto fail; |
306 | 312 | ||
313 | key.offset = (u64)-1; | ||
314 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); | ||
315 | BUG_ON(IS_ERR(new_root)); | ||
316 | |||
317 | btrfs_record_root_in_trans(trans, new_root); | ||
318 | |||
319 | ret = btrfs_create_subvol_root(trans, new_root, new_dirid, | ||
320 | BTRFS_I(dir)->block_group); | ||
307 | /* | 321 | /* |
308 | * insert the directory item | 322 | * insert the directory item |
309 | */ | 323 | */ |
310 | key.offset = (u64)-1; | ||
311 | dir = dentry->d_parent->d_inode; | ||
312 | ret = btrfs_set_inode_index(dir, &index); | 324 | ret = btrfs_set_inode_index(dir, &index); |
313 | BUG_ON(ret); | 325 | BUG_ON(ret); |
314 | 326 | ||
@@ -322,43 +334,20 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
322 | ret = btrfs_update_inode(trans, root, dir); | 334 | ret = btrfs_update_inode(trans, root, dir); |
323 | BUG_ON(ret); | 335 | BUG_ON(ret); |
324 | 336 | ||
325 | /* add the backref first */ | ||
326 | ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, | 337 | ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, |
327 | objectid, BTRFS_ROOT_BACKREF_KEY, | 338 | objectid, root->root_key.objectid, |
328 | root->root_key.objectid, | ||
329 | dir->i_ino, index, name, namelen); | 339 | dir->i_ino, index, name, namelen); |
330 | 340 | ||
331 | BUG_ON(ret); | 341 | BUG_ON(ret); |
332 | 342 | ||
333 | /* now add the forward ref */ | 343 | 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: | 344 | fail: |
357 | nr = trans->blocks_used; | 345 | nr = trans->blocks_used; |
358 | err = btrfs_commit_transaction(trans, new_root); | 346 | err = btrfs_commit_transaction(trans, root); |
359 | if (err && !ret) | 347 | if (err && !ret) |
360 | ret = err; | 348 | ret = err; |
361 | fail_commit: | 349 | |
350 | btrfs_unreserve_metadata_space(root, 6); | ||
362 | btrfs_btree_balance_dirty(root, nr); | 351 | btrfs_btree_balance_dirty(root, nr); |
363 | return ret; | 352 | return ret; |
364 | } | 353 | } |
@@ -375,19 +364,27 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
375 | if (!root->ref_cows) | 364 | if (!root->ref_cows) |
376 | return -EINVAL; | 365 | return -EINVAL; |
377 | 366 | ||
378 | ret = btrfs_check_metadata_free_space(root); | 367 | /* |
368 | * 1 - inode item | ||
369 | * 2 - refs | ||
370 | * 1 - root item | ||
371 | * 2 - dir items | ||
372 | */ | ||
373 | ret = btrfs_reserve_metadata_space(root, 6); | ||
379 | if (ret) | 374 | if (ret) |
380 | goto fail_unlock; | 375 | goto fail_unlock; |
381 | 376 | ||
382 | pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); | 377 | pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); |
383 | if (!pending_snapshot) { | 378 | if (!pending_snapshot) { |
384 | ret = -ENOMEM; | 379 | ret = -ENOMEM; |
380 | btrfs_unreserve_metadata_space(root, 6); | ||
385 | goto fail_unlock; | 381 | goto fail_unlock; |
386 | } | 382 | } |
387 | pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS); | 383 | pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS); |
388 | if (!pending_snapshot->name) { | 384 | if (!pending_snapshot->name) { |
389 | ret = -ENOMEM; | 385 | ret = -ENOMEM; |
390 | kfree(pending_snapshot); | 386 | kfree(pending_snapshot); |
387 | btrfs_unreserve_metadata_space(root, 6); | ||
391 | goto fail_unlock; | 388 | goto fail_unlock; |
392 | } | 389 | } |
393 | memcpy(pending_snapshot->name, name, namelen); | 390 | memcpy(pending_snapshot->name, name, namelen); |
@@ -420,14 +417,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 | 417 | * sys_mkdirat and vfs_mkdir, but we only do a single component lookup |
421 | * inside this filesystem so it's quite a bit simpler. | 418 | * inside this filesystem so it's quite a bit simpler. |
422 | */ | 419 | */ |
423 | static noinline int btrfs_mksubvol(struct path *parent, char *name, | 420 | static noinline int btrfs_mksubvol(struct path *parent, |
424 | int mode, int namelen, | 421 | char *name, int namelen, |
425 | struct btrfs_root *snap_src) | 422 | struct btrfs_root *snap_src) |
426 | { | 423 | { |
424 | struct inode *dir = parent->dentry->d_inode; | ||
427 | struct dentry *dentry; | 425 | struct dentry *dentry; |
428 | int error; | 426 | int error; |
429 | 427 | ||
430 | mutex_lock_nested(&parent->dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 428 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
431 | 429 | ||
432 | dentry = lookup_one_len(name, parent->dentry, namelen); | 430 | dentry = lookup_one_len(name, parent->dentry, namelen); |
433 | error = PTR_ERR(dentry); | 431 | error = PTR_ERR(dentry); |
@@ -438,99 +436,39 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name, | |||
438 | if (dentry->d_inode) | 436 | if (dentry->d_inode) |
439 | goto out_dput; | 437 | goto out_dput; |
440 | 438 | ||
441 | if (!IS_POSIXACL(parent->dentry->d_inode)) | ||
442 | mode &= ~current_umask(); | ||
443 | |||
444 | error = mnt_want_write(parent->mnt); | 439 | error = mnt_want_write(parent->mnt); |
445 | if (error) | 440 | if (error) |
446 | goto out_dput; | 441 | goto out_dput; |
447 | 442 | ||
448 | error = btrfs_may_create(parent->dentry->d_inode, dentry); | 443 | error = btrfs_may_create(dir, dentry); |
449 | if (error) | 444 | if (error) |
450 | goto out_drop_write; | 445 | goto out_drop_write; |
451 | 446 | ||
452 | /* | 447 | down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
453 | * Actually perform the low-level subvolume creation after all | 448 | |
454 | * this VFS fuzz. | 449 | if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) |
455 | * | 450 | goto out_up_read; |
456 | * Eventually we want to pass in an inode under which we create this | 451 | |
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) { | 452 | if (snap_src) { |
463 | struct dentry *dir = dentry->d_parent; | 453 | error = create_snapshot(snap_src, dentry, |
464 | struct dentry *test = dir->d_parent; | 454 | 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 { | 455 | } else { |
517 | error = create_subvol(BTRFS_I(parent->dentry->d_inode)->root, | 456 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
518 | dentry, name, namelen); | 457 | name, namelen); |
519 | } | 458 | } |
520 | if (error) | 459 | if (!error) |
521 | goto out_drop_write; | 460 | fsnotify_mkdir(dir, dentry); |
522 | 461 | out_up_read: | |
523 | fsnotify_mkdir(parent->dentry->d_inode, dentry); | 462 | up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
524 | out_drop_write: | 463 | out_drop_write: |
525 | mnt_drop_write(parent->mnt); | 464 | mnt_drop_write(parent->mnt); |
526 | out_dput: | 465 | out_dput: |
527 | dput(dentry); | 466 | dput(dentry); |
528 | out_unlock: | 467 | out_unlock: |
529 | mutex_unlock(&parent->dentry->d_inode->i_mutex); | 468 | mutex_unlock(&dir->i_mutex); |
530 | return error; | 469 | return error; |
531 | } | 470 | } |
532 | 471 | ||
533 | |||
534 | static int btrfs_defrag_file(struct file *file) | 472 | static int btrfs_defrag_file(struct file *file) |
535 | { | 473 | { |
536 | struct inode *inode = fdentry(file)->d_inode; | 474 | struct inode *inode = fdentry(file)->d_inode; |
@@ -596,9 +534,8 @@ again: | |||
596 | clear_page_dirty_for_io(page); | 534 | clear_page_dirty_for_io(page); |
597 | 535 | ||
598 | btrfs_set_extent_delalloc(inode, page_start, page_end); | 536 | 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); | 537 | set_page_dirty(page); |
538 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||
602 | unlock_page(page); | 539 | unlock_page(page); |
603 | page_cache_release(page); | 540 | page_cache_release(page); |
604 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); | 541 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); |
@@ -609,7 +546,8 @@ out_unlock: | |||
609 | return 0; | 546 | return 0; |
610 | } | 547 | } |
611 | 548 | ||
612 | static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) | 549 | static noinline int btrfs_ioctl_resize(struct btrfs_root *root, |
550 | void __user *arg) | ||
613 | { | 551 | { |
614 | u64 new_size; | 552 | u64 new_size; |
615 | u64 old_size; | 553 | u64 old_size; |
@@ -718,10 +656,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
718 | { | 656 | { |
719 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 657 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
720 | struct btrfs_ioctl_vol_args *vol_args; | 658 | struct btrfs_ioctl_vol_args *vol_args; |
721 | struct btrfs_dir_item *di; | ||
722 | struct btrfs_path *path; | ||
723 | struct file *src_file; | 659 | struct file *src_file; |
724 | u64 root_dirid; | ||
725 | int namelen; | 660 | int namelen; |
726 | int ret = 0; | 661 | int ret = 0; |
727 | 662 | ||
@@ -739,32 +674,9 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
739 | goto out; | 674 | goto out; |
740 | } | 675 | } |
741 | 676 | ||
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) { | 677 | if (subvol) { |
765 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | 678 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, |
766 | file->f_path.dentry->d_inode->i_mode, | 679 | NULL); |
767 | namelen, NULL); | ||
768 | } else { | 680 | } else { |
769 | struct inode *src_inode; | 681 | struct inode *src_inode; |
770 | src_file = fget(vol_args->fd); | 682 | src_file = fget(vol_args->fd); |
@@ -781,17 +693,157 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
781 | fput(src_file); | 693 | fput(src_file); |
782 | goto out; | 694 | goto out; |
783 | } | 695 | } |
784 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, | 696 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, |
785 | file->f_path.dentry->d_inode->i_mode, | 697 | BTRFS_I(src_inode)->root); |
786 | namelen, BTRFS_I(src_inode)->root); | ||
787 | fput(src_file); | 698 | fput(src_file); |
788 | } | 699 | } |
789 | |||
790 | out: | 700 | out: |
791 | kfree(vol_args); | 701 | kfree(vol_args); |
792 | return ret; | 702 | return ret; |
793 | } | 703 | } |
794 | 704 | ||
705 | /* | ||
706 | * helper to check if the subvolume references other subvolumes | ||
707 | */ | ||
708 | static noinline int may_destroy_subvol(struct btrfs_root *root) | ||
709 | { | ||
710 | struct btrfs_path *path; | ||
711 | struct btrfs_key key; | ||
712 | int ret; | ||
713 | |||
714 | path = btrfs_alloc_path(); | ||
715 | if (!path) | ||
716 | return -ENOMEM; | ||
717 | |||
718 | key.objectid = root->root_key.objectid; | ||
719 | key.type = BTRFS_ROOT_REF_KEY; | ||
720 | key.offset = (u64)-1; | ||
721 | |||
722 | ret = btrfs_search_slot(NULL, root->fs_info->tree_root, | ||
723 | &key, path, 0, 0); | ||
724 | if (ret < 0) | ||
725 | goto out; | ||
726 | BUG_ON(ret == 0); | ||
727 | |||
728 | ret = 0; | ||
729 | if (path->slots[0] > 0) { | ||
730 | path->slots[0]--; | ||
731 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
732 | if (key.objectid == root->root_key.objectid && | ||
733 | key.type == BTRFS_ROOT_REF_KEY) | ||
734 | ret = -ENOTEMPTY; | ||
735 | } | ||
736 | out: | ||
737 | btrfs_free_path(path); | ||
738 | return ret; | ||
739 | } | ||
740 | |||
741 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, | ||
742 | void __user *arg) | ||
743 | { | ||
744 | struct dentry *parent = fdentry(file); | ||
745 | struct dentry *dentry; | ||
746 | struct inode *dir = parent->d_inode; | ||
747 | struct inode *inode; | ||
748 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
749 | struct btrfs_root *dest = NULL; | ||
750 | struct btrfs_ioctl_vol_args *vol_args; | ||
751 | struct btrfs_trans_handle *trans; | ||
752 | int namelen; | ||
753 | int ret; | ||
754 | int err = 0; | ||
755 | |||
756 | if (!capable(CAP_SYS_ADMIN)) | ||
757 | return -EPERM; | ||
758 | |||
759 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
760 | if (IS_ERR(vol_args)) | ||
761 | return PTR_ERR(vol_args); | ||
762 | |||
763 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
764 | namelen = strlen(vol_args->name); | ||
765 | if (strchr(vol_args->name, '/') || | ||
766 | strncmp(vol_args->name, "..", namelen) == 0) { | ||
767 | err = -EINVAL; | ||
768 | goto out; | ||
769 | } | ||
770 | |||
771 | err = mnt_want_write(file->f_path.mnt); | ||
772 | if (err) | ||
773 | goto out; | ||
774 | |||
775 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | ||
776 | dentry = lookup_one_len(vol_args->name, parent, namelen); | ||
777 | if (IS_ERR(dentry)) { | ||
778 | err = PTR_ERR(dentry); | ||
779 | goto out_unlock_dir; | ||
780 | } | ||
781 | |||
782 | if (!dentry->d_inode) { | ||
783 | err = -ENOENT; | ||
784 | goto out_dput; | ||
785 | } | ||
786 | |||
787 | inode = dentry->d_inode; | ||
788 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { | ||
789 | err = -EINVAL; | ||
790 | goto out_dput; | ||
791 | } | ||
792 | |||
793 | dest = BTRFS_I(inode)->root; | ||
794 | |||
795 | mutex_lock(&inode->i_mutex); | ||
796 | err = d_invalidate(dentry); | ||
797 | if (err) | ||
798 | goto out_unlock; | ||
799 | |||
800 | down_write(&root->fs_info->subvol_sem); | ||
801 | |||
802 | err = may_destroy_subvol(dest); | ||
803 | if (err) | ||
804 | goto out_up_write; | ||
805 | |||
806 | trans = btrfs_start_transaction(root, 1); | ||
807 | ret = btrfs_unlink_subvol(trans, root, dir, | ||
808 | dest->root_key.objectid, | ||
809 | dentry->d_name.name, | ||
810 | dentry->d_name.len); | ||
811 | BUG_ON(ret); | ||
812 | |||
813 | btrfs_record_root_in_trans(trans, dest); | ||
814 | |||
815 | memset(&dest->root_item.drop_progress, 0, | ||
816 | sizeof(dest->root_item.drop_progress)); | ||
817 | dest->root_item.drop_level = 0; | ||
818 | btrfs_set_root_refs(&dest->root_item, 0); | ||
819 | |||
820 | ret = btrfs_insert_orphan_item(trans, | ||
821 | root->fs_info->tree_root, | ||
822 | dest->root_key.objectid); | ||
823 | BUG_ON(ret); | ||
824 | |||
825 | ret = btrfs_commit_transaction(trans, root); | ||
826 | BUG_ON(ret); | ||
827 | inode->i_flags |= S_DEAD; | ||
828 | out_up_write: | ||
829 | up_write(&root->fs_info->subvol_sem); | ||
830 | out_unlock: | ||
831 | mutex_unlock(&inode->i_mutex); | ||
832 | if (!err) { | ||
833 | shrink_dcache_sb(root->fs_info->sb); | ||
834 | btrfs_invalidate_inodes(dest); | ||
835 | d_delete(dentry); | ||
836 | } | ||
837 | out_dput: | ||
838 | dput(dentry); | ||
839 | out_unlock_dir: | ||
840 | mutex_unlock(&dir->i_mutex); | ||
841 | mnt_drop_write(file->f_path.mnt); | ||
842 | out: | ||
843 | kfree(vol_args); | ||
844 | return err; | ||
845 | } | ||
846 | |||
795 | static int btrfs_ioctl_defrag(struct file *file) | 847 | static int btrfs_ioctl_defrag(struct file *file) |
796 | { | 848 | { |
797 | struct inode *inode = fdentry(file)->d_inode; | 849 | struct inode *inode = fdentry(file)->d_inode; |
@@ -865,8 +917,8 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | |||
865 | return ret; | 917 | return ret; |
866 | } | 918 | } |
867 | 919 | ||
868 | static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | 920 | static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, |
869 | u64 off, u64 olen, u64 destoff) | 921 | u64 off, u64 olen, u64 destoff) |
870 | { | 922 | { |
871 | struct inode *inode = fdentry(file)->d_inode; | 923 | struct inode *inode = fdentry(file)->d_inode; |
872 | struct btrfs_root *root = BTRFS_I(inode)->root; | 924 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -976,7 +1028,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
976 | 1028 | ||
977 | /* punch hole in destination first */ | 1029 | /* punch hole in destination first */ |
978 | btrfs_drop_extents(trans, root, inode, off, off + len, | 1030 | btrfs_drop_extents(trans, root, inode, off, off + len, |
979 | off + len, 0, &hint_byte); | 1031 | off + len, 0, &hint_byte, 1); |
980 | 1032 | ||
981 | /* clone data */ | 1033 | /* clone data */ |
982 | key.objectid = src->i_ino; | 1034 | key.objectid = src->i_ino; |
@@ -1071,9 +1123,10 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1071 | datao += off - key.offset; | 1123 | datao += off - key.offset; |
1072 | datal -= off - key.offset; | 1124 | datal -= off - key.offset; |
1073 | } | 1125 | } |
1074 | if (key.offset + datao + datal + key.offset > | 1126 | |
1075 | off + len) | 1127 | if (key.offset + datal > off + len) |
1076 | datal = off + len - key.offset - datao; | 1128 | datal = off + len - key.offset; |
1129 | |||
1077 | /* disko == 0 means it's a hole */ | 1130 | /* disko == 0 means it's a hole */ |
1078 | if (!disko) | 1131 | if (!disko) |
1079 | datao = 0; | 1132 | datao = 0; |
@@ -1182,15 +1235,15 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1182 | struct inode *inode = fdentry(file)->d_inode; | 1235 | struct inode *inode = fdentry(file)->d_inode; |
1183 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1236 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1184 | struct btrfs_trans_handle *trans; | 1237 | struct btrfs_trans_handle *trans; |
1185 | int ret = 0; | 1238 | int ret; |
1186 | 1239 | ||
1240 | ret = -EPERM; | ||
1187 | if (!capable(CAP_SYS_ADMIN)) | 1241 | if (!capable(CAP_SYS_ADMIN)) |
1188 | return -EPERM; | 1242 | goto out; |
1189 | 1243 | ||
1190 | if (file->private_data) { | 1244 | ret = -EINPROGRESS; |
1191 | ret = -EINPROGRESS; | 1245 | if (file->private_data) |
1192 | goto out; | 1246 | goto out; |
1193 | } | ||
1194 | 1247 | ||
1195 | ret = mnt_want_write(file->f_path.mnt); | 1248 | ret = mnt_want_write(file->f_path.mnt); |
1196 | if (ret) | 1249 | if (ret) |
@@ -1200,12 +1253,19 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1200 | root->fs_info->open_ioctl_trans++; | 1253 | root->fs_info->open_ioctl_trans++; |
1201 | mutex_unlock(&root->fs_info->trans_mutex); | 1254 | mutex_unlock(&root->fs_info->trans_mutex); |
1202 | 1255 | ||
1256 | ret = -ENOMEM; | ||
1203 | trans = btrfs_start_ioctl_transaction(root, 0); | 1257 | trans = btrfs_start_ioctl_transaction(root, 0); |
1204 | if (trans) | 1258 | if (!trans) |
1205 | file->private_data = trans; | 1259 | goto out_drop; |
1206 | else | 1260 | |
1207 | ret = -ENOMEM; | 1261 | file->private_data = trans; |
1208 | /*printk(KERN_INFO "btrfs_ioctl_trans_start on %p\n", file);*/ | 1262 | return 0; |
1263 | |||
1264 | out_drop: | ||
1265 | mutex_lock(&root->fs_info->trans_mutex); | ||
1266 | root->fs_info->open_ioctl_trans--; | ||
1267 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1268 | mnt_drop_write(file->f_path.mnt); | ||
1209 | out: | 1269 | out: |
1210 | return ret; | 1270 | return ret; |
1211 | } | 1271 | } |
@@ -1221,24 +1281,20 @@ long btrfs_ioctl_trans_end(struct file *file) | |||
1221 | struct inode *inode = fdentry(file)->d_inode; | 1281 | struct inode *inode = fdentry(file)->d_inode; |
1222 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1282 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1223 | struct btrfs_trans_handle *trans; | 1283 | struct btrfs_trans_handle *trans; |
1224 | int ret = 0; | ||
1225 | 1284 | ||
1226 | trans = file->private_data; | 1285 | trans = file->private_data; |
1227 | if (!trans) { | 1286 | if (!trans) |
1228 | ret = -EINVAL; | 1287 | return -EINVAL; |
1229 | goto out; | ||
1230 | } | ||
1231 | btrfs_end_transaction(trans, root); | ||
1232 | file->private_data = NULL; | 1288 | file->private_data = NULL; |
1233 | 1289 | ||
1290 | btrfs_end_transaction(trans, root); | ||
1291 | |||
1234 | mutex_lock(&root->fs_info->trans_mutex); | 1292 | mutex_lock(&root->fs_info->trans_mutex); |
1235 | root->fs_info->open_ioctl_trans--; | 1293 | root->fs_info->open_ioctl_trans--; |
1236 | mutex_unlock(&root->fs_info->trans_mutex); | 1294 | mutex_unlock(&root->fs_info->trans_mutex); |
1237 | 1295 | ||
1238 | mnt_drop_write(file->f_path.mnt); | 1296 | mnt_drop_write(file->f_path.mnt); |
1239 | 1297 | return 0; | |
1240 | out: | ||
1241 | return ret; | ||
1242 | } | 1298 | } |
1243 | 1299 | ||
1244 | long btrfs_ioctl(struct file *file, unsigned int | 1300 | long btrfs_ioctl(struct file *file, unsigned int |
@@ -1258,6 +1314,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
1258 | return btrfs_ioctl_snap_create(file, argp, 0); | 1314 | return btrfs_ioctl_snap_create(file, argp, 0); |
1259 | case BTRFS_IOC_SUBVOL_CREATE: | 1315 | case BTRFS_IOC_SUBVOL_CREATE: |
1260 | return btrfs_ioctl_snap_create(file, argp, 1); | 1316 | return btrfs_ioctl_snap_create(file, argp, 1); |
1317 | case BTRFS_IOC_SNAP_DESTROY: | ||
1318 | return btrfs_ioctl_snap_destroy(file, argp); | ||
1261 | case BTRFS_IOC_DEFRAG: | 1319 | case BTRFS_IOC_DEFRAG: |
1262 | return btrfs_ioctl_defrag(file); | 1320 | return btrfs_ioctl_defrag(file); |
1263 | case BTRFS_IOC_RESIZE: | 1321 | case BTRFS_IOC_RESIZE: |