diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-08-04 23:23:47 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:06 -0400 |
commit | ae01a0abf343aefe923ace5c1a8c634adfbe29c5 (patch) | |
tree | b6d1fc42223b3588c8187dcd946176257872499d /fs/btrfs/ioctl.c | |
parent | b48652c101cce7a54379a49cc0cf854cec2c94e2 (diff) |
Btrfs: Update clone file ioctl
This patch updates the file clone ioctl for the tree locking and new
data ordered code.
---
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 150 |
1 files changed, 70 insertions, 80 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e1046a54b1c5..3932c7cd0fae 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -517,32 +517,6 @@ out: | |||
517 | return ret; | 517 | return ret; |
518 | } | 518 | } |
519 | 519 | ||
520 | int dup_item_to_inode(struct btrfs_trans_handle *trans, | ||
521 | struct btrfs_root *root, | ||
522 | struct btrfs_path *path, | ||
523 | struct extent_buffer *leaf, | ||
524 | int slot, | ||
525 | struct btrfs_key *key, | ||
526 | u64 destino) | ||
527 | { | ||
528 | char *dup; | ||
529 | int len = btrfs_item_size_nr(leaf, slot); | ||
530 | struct btrfs_key ckey = *key; | ||
531 | int ret = 0; | ||
532 | |||
533 | dup = kmalloc(len, GFP_NOFS); | ||
534 | if (!dup) | ||
535 | return -ENOMEM; | ||
536 | |||
537 | read_extent_buffer(leaf, dup, btrfs_item_ptr_offset(leaf, slot), len); | ||
538 | btrfs_release_path(root, path); | ||
539 | |||
540 | ckey.objectid = destino; | ||
541 | ret = btrfs_insert_item(trans, root, &ckey, dup, len); | ||
542 | kfree(dup); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | 520 | long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) |
547 | { | 521 | { |
548 | struct inode *inode = fdentry(file)->d_inode; | 522 | struct inode *inode = fdentry(file)->d_inode; |
@@ -550,22 +524,41 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
550 | struct file *src_file; | 524 | struct file *src_file; |
551 | struct inode *src; | 525 | struct inode *src; |
552 | struct btrfs_trans_handle *trans; | 526 | struct btrfs_trans_handle *trans; |
553 | int ret; | 527 | struct btrfs_ordered_extent *ordered; |
554 | u64 pos; | ||
555 | struct btrfs_path *path; | 528 | struct btrfs_path *path; |
556 | struct btrfs_key key; | ||
557 | struct extent_buffer *leaf; | 529 | struct extent_buffer *leaf; |
530 | char *buf; | ||
531 | struct btrfs_key key; | ||
532 | struct btrfs_key new_key; | ||
533 | u32 size; | ||
558 | u32 nritems; | 534 | u32 nritems; |
559 | int slot; | 535 | int slot; |
536 | int ret; | ||
560 | 537 | ||
561 | src_file = fget(src_fd); | 538 | src_file = fget(src_fd); |
562 | if (!src_file) | 539 | if (!src_file) |
563 | return -EBADF; | 540 | return -EBADF; |
564 | src = src_file->f_dentry->d_inode; | 541 | src = src_file->f_dentry->d_inode; |
565 | 542 | ||
543 | ret = -EISDIR; | ||
544 | if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) | ||
545 | goto out_fput; | ||
546 | |||
566 | ret = -EXDEV; | 547 | ret = -EXDEV; |
567 | if (src->i_sb != inode->i_sb) | 548 | if (src->i_sb != inode->i_sb || BTRFS_I(src)->root != root) |
549 | goto out_fput; | ||
550 | |||
551 | ret = -ENOMEM; | ||
552 | buf = vmalloc(btrfs_level_size(root, 0)); | ||
553 | if (!buf) | ||
554 | goto out_fput; | ||
555 | |||
556 | path = btrfs_alloc_path(); | ||
557 | if (!path) { | ||
558 | vfree(buf); | ||
568 | goto out_fput; | 559 | goto out_fput; |
560 | } | ||
561 | path->reada = 2; | ||
569 | 562 | ||
570 | if (inode < src) { | 563 | if (inode < src) { |
571 | mutex_lock(&inode->i_mutex); | 564 | mutex_lock(&inode->i_mutex); |
@@ -582,24 +575,22 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
582 | /* do any pending delalloc/csum calc on src, one way or | 575 | /* do any pending delalloc/csum calc on src, one way or |
583 | another, and lock file content */ | 576 | another, and lock file content */ |
584 | while (1) { | 577 | while (1) { |
585 | filemap_write_and_wait(src->i_mapping); | ||
586 | lock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); | 578 | lock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); |
587 | if (BTRFS_I(src)->delalloc_bytes == 0) | 579 | ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); |
580 | if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered) | ||
588 | break; | 581 | break; |
589 | unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); | 582 | unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); |
583 | if (ordered) | ||
584 | btrfs_put_ordered_extent(ordered); | ||
585 | btrfs_wait_ordered_range(src, 0, (u64)-1); | ||
590 | } | 586 | } |
591 | 587 | ||
592 | trans = btrfs_start_transaction(root, 0); | 588 | trans = btrfs_start_transaction(root, 1); |
593 | path = btrfs_alloc_path(); | 589 | BUG_ON(!trans); |
594 | if (!path) { | 590 | |
595 | ret = -ENOMEM; | ||
596 | goto out; | ||
597 | } | ||
598 | key.offset = 0; | ||
599 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
600 | key.objectid = src->i_ino; | 591 | key.objectid = src->i_ino; |
601 | pos = 0; | 592 | key.type = BTRFS_EXTENT_DATA_KEY; |
602 | path->reada = 2; | 593 | key.offset = 0; |
603 | 594 | ||
604 | while (1) { | 595 | while (1) { |
605 | /* | 596 | /* |
@@ -610,18 +601,19 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
610 | if (ret < 0) | 601 | if (ret < 0) |
611 | goto out; | 602 | goto out; |
612 | 603 | ||
613 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | 604 | nritems = btrfs_header_nritems(path->nodes[0]); |
605 | if (path->slots[0] >= nritems) { | ||
614 | ret = btrfs_next_leaf(root, path); | 606 | ret = btrfs_next_leaf(root, path); |
615 | if (ret < 0) | 607 | if (ret < 0) |
616 | goto out; | 608 | goto out; |
617 | if (ret > 0) | 609 | if (ret > 0) |
618 | break; | 610 | break; |
611 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
619 | } | 612 | } |
620 | leaf = path->nodes[0]; | 613 | leaf = path->nodes[0]; |
621 | slot = path->slots[0]; | 614 | slot = path->slots[0]; |
622 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
623 | nritems = btrfs_header_nritems(leaf); | ||
624 | 615 | ||
616 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
625 | if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY || | 617 | if (btrfs_key_type(&key) > BTRFS_CSUM_ITEM_KEY || |
626 | key.objectid != src->i_ino) | 618 | key.objectid != src->i_ino) |
627 | break; | 619 | break; |
@@ -629,66 +621,64 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd) | |||
629 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { | 621 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { |
630 | struct btrfs_file_extent_item *extent; | 622 | struct btrfs_file_extent_item *extent; |
631 | int found_type; | 623 | int found_type; |
632 | pos = key.offset; | 624 | |
633 | extent = btrfs_item_ptr(leaf, slot, | 625 | extent = btrfs_item_ptr(leaf, slot, |
634 | struct btrfs_file_extent_item); | 626 | struct btrfs_file_extent_item); |
635 | found_type = btrfs_file_extent_type(leaf, extent); | 627 | found_type = btrfs_file_extent_type(leaf, extent); |
636 | if (found_type == BTRFS_FILE_EXTENT_REG) { | 628 | if (found_type == BTRFS_FILE_EXTENT_REG) { |
637 | u64 len = btrfs_file_extent_num_bytes(leaf, | ||
638 | extent); | ||
639 | u64 ds = btrfs_file_extent_disk_bytenr(leaf, | 629 | u64 ds = btrfs_file_extent_disk_bytenr(leaf, |
640 | extent); | 630 | extent); |
641 | u64 dl = btrfs_file_extent_disk_num_bytes(leaf, | 631 | u64 dl = btrfs_file_extent_disk_num_bytes(leaf, |
642 | extent); | 632 | extent); |
643 | u64 off = btrfs_file_extent_offset(leaf, | ||
644 | extent); | ||
645 | btrfs_insert_file_extent(trans, root, | ||
646 | inode->i_ino, pos, | ||
647 | ds, dl, len, off); | ||
648 | /* ds == 0 means there's a hole */ | 633 | /* ds == 0 means there's a hole */ |
649 | if (ds != 0) { | 634 | if (ds != 0) { |
650 | btrfs_inc_extent_ref(trans, root, | 635 | ret = btrfs_inc_extent_ref(trans, root, |
651 | ds, dl, | 636 | ds, dl, |
652 | root->root_key.objectid, | 637 | root->root_key.objectid, |
653 | trans->transid, | 638 | trans->transid, |
654 | inode->i_ino, pos); | 639 | inode->i_ino, key.offset); |
640 | if (ret) | ||
641 | goto out; | ||
655 | } | 642 | } |
656 | pos = key.offset + len; | ||
657 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
658 | ret = dup_item_to_inode(trans, root, path, | ||
659 | leaf, slot, &key, | ||
660 | inode->i_ino); | ||
661 | if (ret) | ||
662 | goto out; | ||
663 | pos = key.offset + btrfs_item_size_nr(leaf, | ||
664 | slot); | ||
665 | } | 643 | } |
666 | } else if (btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) { | 644 | } |
667 | ret = dup_item_to_inode(trans, root, path, leaf, | ||
668 | slot, &key, inode->i_ino); | ||
669 | 645 | ||
670 | if (ret) | 646 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY || |
671 | goto out; | 647 | btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) { |
648 | size = btrfs_item_size_nr(leaf, slot); | ||
649 | read_extent_buffer(leaf, buf, | ||
650 | btrfs_item_ptr_offset(leaf, slot), | ||
651 | size); | ||
652 | btrfs_release_path(root, path); | ||
653 | memcpy(&new_key, &key, sizeof(new_key)); | ||
654 | new_key.objectid = inode->i_ino; | ||
655 | ret = btrfs_insert_item(trans, root, &new_key, | ||
656 | buf, size); | ||
657 | BUG_ON(ret); | ||
658 | } else { | ||
659 | btrfs_release_path(root, path); | ||
672 | } | 660 | } |
673 | key.offset++; | 661 | key.offset++; |
674 | btrfs_release_path(root, path); | ||
675 | } | 662 | } |
676 | |||
677 | ret = 0; | 663 | ret = 0; |
678 | out: | 664 | out: |
679 | btrfs_free_path(path); | 665 | btrfs_release_path(root, path); |
680 | 666 | if (ret == 0) { | |
681 | inode->i_blocks = src->i_blocks; | 667 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
682 | i_size_write(inode, src->i_size); | 668 | inode->i_blocks = src->i_blocks; |
683 | btrfs_update_inode(trans, root, inode); | 669 | btrfs_i_size_write(inode, src->i_size); |
684 | 670 | BTRFS_I(inode)->flags = BTRFS_I(src)->flags; | |
685 | unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); | 671 | ret = btrfs_update_inode(trans, root, inode); |
686 | 672 | } | |
687 | btrfs_end_transaction(trans, root); | 673 | btrfs_end_transaction(trans, root); |
688 | 674 | unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); | |
675 | if (ret) | ||
676 | vmtruncate(inode, 0); | ||
689 | out_unlock: | 677 | out_unlock: |
690 | mutex_unlock(&src->i_mutex); | 678 | mutex_unlock(&src->i_mutex); |
691 | mutex_unlock(&inode->i_mutex); | 679 | mutex_unlock(&inode->i_mutex); |
680 | vfree(buf); | ||
681 | btrfs_free_path(path); | ||
692 | out_fput: | 682 | out_fput: |
693 | fput(src_file); | 683 | fput(src_file); |
694 | return ret; | 684 | return ret; |