diff options
| -rw-r--r-- | fs/btrfs/transaction.c | 97 |
1 files changed, 31 insertions, 66 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 43054285f638..01cebd661997 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -755,10 +755,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 755 | struct btrfs_root_item *new_root_item; | 755 | struct btrfs_root_item *new_root_item; |
| 756 | struct btrfs_root *tree_root = fs_info->tree_root; | 756 | struct btrfs_root *tree_root = fs_info->tree_root; |
| 757 | struct btrfs_root *root = pending->root; | 757 | struct btrfs_root *root = pending->root; |
| 758 | struct btrfs_root *parent_root; | ||
| 759 | struct inode *parent_inode; | ||
| 758 | struct extent_buffer *tmp; | 760 | struct extent_buffer *tmp; |
| 759 | struct extent_buffer *old; | 761 | struct extent_buffer *old; |
| 760 | int ret; | 762 | int ret; |
| 761 | u64 objectid; | 763 | u64 objectid; |
| 764 | int namelen; | ||
| 765 | u64 index = 0; | ||
| 766 | |||
| 767 | parent_inode = pending->dentry->d_parent->d_inode; | ||
| 768 | parent_root = BTRFS_I(parent_inode)->root; | ||
| 762 | 769 | ||
| 763 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 770 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
| 764 | if (!new_root_item) { | 771 | if (!new_root_item) { |
| @@ -769,79 +776,59 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 769 | if (ret) | 776 | if (ret) |
| 770 | goto fail; | 777 | goto fail; |
| 771 | 778 | ||
| 772 | record_root_in_trans(trans, root); | ||
| 773 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
| 774 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
| 775 | |||
| 776 | key.objectid = objectid; | 779 | key.objectid = objectid; |
| 777 | /* record when the snapshot was created in key.offset */ | 780 | /* record when the snapshot was created in key.offset */ |
| 778 | key.offset = trans->transid; | 781 | key.offset = trans->transid; |
| 779 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 782 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
| 780 | 783 | ||
| 781 | old = btrfs_lock_root_node(root); | ||
| 782 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
| 783 | btrfs_set_lock_blocking(old); | ||
| 784 | |||
| 785 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
| 786 | btrfs_tree_unlock(old); | ||
| 787 | free_extent_buffer(old); | ||
| 788 | |||
| 789 | btrfs_set_root_node(new_root_item, tmp); | ||
| 790 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
| 791 | new_root_item); | ||
| 792 | btrfs_tree_unlock(tmp); | ||
| 793 | free_extent_buffer(tmp); | ||
| 794 | if (ret) | ||
| 795 | goto fail; | ||
| 796 | |||
| 797 | key.offset = (u64)-1; | ||
| 798 | memcpy(&pending->root_key, &key, sizeof(key)); | 784 | memcpy(&pending->root_key, &key, sizeof(key)); |
| 799 | fail: | 785 | pending->root_key.offset = (u64)-1; |
| 800 | kfree(new_root_item); | ||
| 801 | return ret; | ||
| 802 | } | ||
| 803 | |||
| 804 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
| 805 | struct btrfs_pending_snapshot *pending) | ||
| 806 | { | ||
| 807 | int ret; | ||
| 808 | int namelen; | ||
| 809 | u64 index = 0; | ||
| 810 | struct btrfs_trans_handle *trans; | ||
| 811 | struct inode *parent_inode; | ||
| 812 | struct btrfs_root *parent_root; | ||
| 813 | |||
| 814 | parent_inode = pending->dentry->d_parent->d_inode; | ||
| 815 | parent_root = BTRFS_I(parent_inode)->root; | ||
| 816 | trans = btrfs_join_transaction(parent_root, 1); | ||
| 817 | 786 | ||
| 787 | record_root_in_trans(trans, parent_root); | ||
| 818 | /* | 788 | /* |
| 819 | * insert the directory item | 789 | * insert the directory item |
| 820 | */ | 790 | */ |
| 821 | namelen = strlen(pending->name); | 791 | namelen = strlen(pending->name); |
| 822 | ret = btrfs_set_inode_index(parent_inode, &index); | 792 | ret = btrfs_set_inode_index(parent_inode, &index); |
| 793 | BUG_ON(ret); | ||
| 823 | ret = btrfs_insert_dir_item(trans, parent_root, | 794 | ret = btrfs_insert_dir_item(trans, parent_root, |
| 824 | pending->name, namelen, | 795 | pending->name, namelen, |
| 825 | parent_inode->i_ino, | 796 | parent_inode->i_ino, |
| 826 | &pending->root_key, BTRFS_FT_DIR, index); | 797 | &pending->root_key, BTRFS_FT_DIR, index); |
| 827 | 798 | BUG_ON(ret); | |
| 828 | if (ret) | ||
| 829 | goto fail; | ||
| 830 | 799 | ||
| 831 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 800 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); |
| 832 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 801 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
| 833 | BUG_ON(ret); | 802 | BUG_ON(ret); |
| 834 | 803 | ||
| 804 | record_root_in_trans(trans, root); | ||
| 805 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
| 806 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
| 807 | |||
| 808 | old = btrfs_lock_root_node(root); | ||
| 809 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
| 810 | btrfs_set_lock_blocking(old); | ||
| 811 | |||
| 812 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
| 813 | btrfs_tree_unlock(old); | ||
| 814 | free_extent_buffer(old); | ||
| 815 | |||
| 816 | btrfs_set_root_node(new_root_item, tmp); | ||
| 817 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
| 818 | new_root_item); | ||
| 819 | BUG_ON(ret); | ||
| 820 | btrfs_tree_unlock(tmp); | ||
| 821 | free_extent_buffer(tmp); | ||
| 822 | |||
| 835 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 823 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, |
| 836 | pending->root_key.objectid, | 824 | pending->root_key.objectid, |
| 837 | parent_root->root_key.objectid, | 825 | parent_root->root_key.objectid, |
| 838 | parent_inode->i_ino, index, pending->name, | 826 | parent_inode->i_ino, index, pending->name, |
| 839 | namelen); | 827 | namelen); |
| 840 | |||
| 841 | BUG_ON(ret); | 828 | BUG_ON(ret); |
| 842 | 829 | ||
| 843 | fail: | 830 | fail: |
| 844 | btrfs_end_transaction(trans, fs_info->fs_root); | 831 | kfree(new_root_item); |
| 845 | return ret; | 832 | return ret; |
| 846 | } | 833 | } |
| 847 | 834 | ||
| @@ -862,25 +849,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
| 862 | return 0; | 849 | return 0; |
| 863 | } | 850 | } |
| 864 | 851 | ||
| 865 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
| 866 | struct btrfs_fs_info *fs_info) | ||
| 867 | { | ||
| 868 | struct btrfs_pending_snapshot *pending; | ||
| 869 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
| 870 | int ret; | ||
| 871 | |||
| 872 | while (!list_empty(head)) { | ||
| 873 | pending = list_entry(head->next, | ||
| 874 | struct btrfs_pending_snapshot, list); | ||
| 875 | ret = finish_pending_snapshot(fs_info, pending); | ||
| 876 | BUG_ON(ret); | ||
| 877 | list_del(&pending->list); | ||
| 878 | kfree(pending->name); | ||
| 879 | kfree(pending); | ||
| 880 | } | ||
| 881 | return 0; | ||
| 882 | } | ||
| 883 | |||
| 884 | static void update_super_roots(struct btrfs_root *root) | 852 | static void update_super_roots(struct btrfs_root *root) |
| 885 | { | 853 | { |
| 886 | struct btrfs_root_item *root_item; | 854 | struct btrfs_root_item *root_item; |
| @@ -1092,9 +1060,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1092 | 1060 | ||
| 1093 | btrfs_finish_extent_commit(trans, root); | 1061 | btrfs_finish_extent_commit(trans, root); |
| 1094 | 1062 | ||
| 1095 | /* do the directory inserts of any pending snapshot creations */ | ||
| 1096 | finish_pending_snapshots(trans, root->fs_info); | ||
| 1097 | |||
| 1098 | mutex_lock(&root->fs_info->trans_mutex); | 1063 | mutex_lock(&root->fs_info->trans_mutex); |
| 1099 | 1064 | ||
| 1100 | cur_trans->commit_done = 1; | 1065 | cur_trans->commit_done = 1; |
