diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 118 | 
1 files changed, 38 insertions, 80 deletions
| diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2a36e236a492..2cb116099b90 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | */ | 17 | */ | 
| 18 | 18 | ||
| 19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> | 
| 20 | #include <linux/slab.h> | ||
| 20 | #include <linux/sched.h> | 21 | #include <linux/sched.h> | 
| 21 | #include <linux/writeback.h> | 22 | #include <linux/writeback.h> | 
| 22 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> | 
| @@ -147,18 +148,13 @@ static void wait_current_trans(struct btrfs_root *root) | |||
| 147 | while (1) { | 148 | while (1) { | 
| 148 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 149 | prepare_to_wait(&root->fs_info->transaction_wait, &wait, | 
| 149 | TASK_UNINTERRUPTIBLE); | 150 | TASK_UNINTERRUPTIBLE); | 
| 150 | if (cur_trans->blocked) { | 151 | if (!cur_trans->blocked) | 
| 151 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 152 | schedule(); | ||
| 153 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 154 | finish_wait(&root->fs_info->transaction_wait, | ||
| 155 | &wait); | ||
| 156 | } else { | ||
| 157 | finish_wait(&root->fs_info->transaction_wait, | ||
| 158 | &wait); | ||
| 159 | break; | 152 | break; | 
| 160 | } | 153 | mutex_unlock(&root->fs_info->trans_mutex); | 
| 154 | schedule(); | ||
| 155 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 161 | } | 156 | } | 
| 157 | finish_wait(&root->fs_info->transaction_wait, &wait); | ||
| 162 | put_transaction(cur_trans); | 158 | put_transaction(cur_trans); | 
| 163 | } | 159 | } | 
| 164 | } | 160 | } | 
| @@ -760,10 +756,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 760 | struct btrfs_root_item *new_root_item; | 756 | struct btrfs_root_item *new_root_item; | 
| 761 | struct btrfs_root *tree_root = fs_info->tree_root; | 757 | struct btrfs_root *tree_root = fs_info->tree_root; | 
| 762 | struct btrfs_root *root = pending->root; | 758 | struct btrfs_root *root = pending->root; | 
| 759 | struct btrfs_root *parent_root; | ||
| 760 | struct inode *parent_inode; | ||
| 763 | struct extent_buffer *tmp; | 761 | struct extent_buffer *tmp; | 
| 764 | struct extent_buffer *old; | 762 | struct extent_buffer *old; | 
| 765 | int ret; | 763 | int ret; | 
| 766 | u64 objectid; | 764 | u64 objectid; | 
| 765 | int namelen; | ||
| 766 | u64 index = 0; | ||
| 767 | |||
| 768 | parent_inode = pending->dentry->d_parent->d_inode; | ||
| 769 | parent_root = BTRFS_I(parent_inode)->root; | ||
| 767 | 770 | ||
| 768 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 771 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 
| 769 | if (!new_root_item) { | 772 | if (!new_root_item) { | 
| @@ -774,79 +777,59 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 774 | if (ret) | 777 | if (ret) | 
| 775 | goto fail; | 778 | goto fail; | 
| 776 | 779 | ||
| 777 | record_root_in_trans(trans, root); | ||
| 778 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
| 779 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
| 780 | |||
| 781 | key.objectid = objectid; | 780 | key.objectid = objectid; | 
| 782 | /* record when the snapshot was created in key.offset */ | 781 | /* record when the snapshot was created in key.offset */ | 
| 783 | key.offset = trans->transid; | 782 | key.offset = trans->transid; | 
| 784 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 783 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 
| 785 | 784 | ||
| 786 | old = btrfs_lock_root_node(root); | ||
| 787 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
| 788 | btrfs_set_lock_blocking(old); | ||
| 789 | |||
| 790 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
| 791 | btrfs_tree_unlock(old); | ||
| 792 | free_extent_buffer(old); | ||
| 793 | |||
| 794 | btrfs_set_root_node(new_root_item, tmp); | ||
| 795 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
| 796 | new_root_item); | ||
| 797 | btrfs_tree_unlock(tmp); | ||
| 798 | free_extent_buffer(tmp); | ||
| 799 | if (ret) | ||
| 800 | goto fail; | ||
| 801 | |||
| 802 | key.offset = (u64)-1; | ||
| 803 | memcpy(&pending->root_key, &key, sizeof(key)); | 785 | memcpy(&pending->root_key, &key, sizeof(key)); | 
| 804 | fail: | 786 | pending->root_key.offset = (u64)-1; | 
| 805 | kfree(new_root_item); | ||
| 806 | return ret; | ||
| 807 | } | ||
| 808 | |||
| 809 | static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, | ||
| 810 | struct btrfs_pending_snapshot *pending) | ||
| 811 | { | ||
| 812 | int ret; | ||
| 813 | int namelen; | ||
| 814 | u64 index = 0; | ||
| 815 | struct btrfs_trans_handle *trans; | ||
| 816 | struct inode *parent_inode; | ||
| 817 | struct btrfs_root *parent_root; | ||
| 818 | |||
| 819 | parent_inode = pending->dentry->d_parent->d_inode; | ||
| 820 | parent_root = BTRFS_I(parent_inode)->root; | ||
| 821 | trans = btrfs_join_transaction(parent_root, 1); | ||
| 822 | 787 | ||
| 788 | record_root_in_trans(trans, parent_root); | ||
| 823 | /* | 789 | /* | 
| 824 | * insert the directory item | 790 | * insert the directory item | 
| 825 | */ | 791 | */ | 
| 826 | namelen = strlen(pending->name); | 792 | namelen = strlen(pending->name); | 
| 827 | ret = btrfs_set_inode_index(parent_inode, &index); | 793 | ret = btrfs_set_inode_index(parent_inode, &index); | 
| 794 | BUG_ON(ret); | ||
| 828 | ret = btrfs_insert_dir_item(trans, parent_root, | 795 | ret = btrfs_insert_dir_item(trans, parent_root, | 
| 829 | pending->name, namelen, | 796 | pending->name, namelen, | 
| 830 | parent_inode->i_ino, | 797 | parent_inode->i_ino, | 
| 831 | &pending->root_key, BTRFS_FT_DIR, index); | 798 | &pending->root_key, BTRFS_FT_DIR, index); | 
| 832 | 799 | BUG_ON(ret); | |
| 833 | if (ret) | ||
| 834 | goto fail; | ||
| 835 | 800 | ||
| 836 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 801 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 
| 837 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 802 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 
| 838 | BUG_ON(ret); | 803 | BUG_ON(ret); | 
| 839 | 804 | ||
| 805 | record_root_in_trans(trans, root); | ||
| 806 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
| 807 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | ||
| 808 | |||
| 809 | old = btrfs_lock_root_node(root); | ||
| 810 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | ||
| 811 | btrfs_set_lock_blocking(old); | ||
| 812 | |||
| 813 | btrfs_copy_root(trans, root, old, &tmp, objectid); | ||
| 814 | btrfs_tree_unlock(old); | ||
| 815 | free_extent_buffer(old); | ||
| 816 | |||
| 817 | btrfs_set_root_node(new_root_item, tmp); | ||
| 818 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
| 819 | new_root_item); | ||
| 820 | BUG_ON(ret); | ||
| 821 | btrfs_tree_unlock(tmp); | ||
| 822 | free_extent_buffer(tmp); | ||
| 823 | |||
| 840 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 824 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 
| 841 | pending->root_key.objectid, | 825 | pending->root_key.objectid, | 
| 842 | parent_root->root_key.objectid, | 826 | parent_root->root_key.objectid, | 
| 843 | parent_inode->i_ino, index, pending->name, | 827 | parent_inode->i_ino, index, pending->name, | 
| 844 | namelen); | 828 | namelen); | 
| 845 | |||
| 846 | BUG_ON(ret); | 829 | BUG_ON(ret); | 
| 847 | 830 | ||
| 848 | fail: | 831 | fail: | 
| 849 | btrfs_end_transaction(trans, fs_info->fs_root); | 832 | kfree(new_root_item); | 
| 850 | return ret; | 833 | return ret; | 
| 851 | } | 834 | } | 
| 852 | 835 | ||
| @@ -867,25 +850,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | |||
| 867 | return 0; | 850 | return 0; | 
| 868 | } | 851 | } | 
| 869 | 852 | ||
| 870 | static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, | ||
| 871 | struct btrfs_fs_info *fs_info) | ||
| 872 | { | ||
| 873 | struct btrfs_pending_snapshot *pending; | ||
| 874 | struct list_head *head = &trans->transaction->pending_snapshots; | ||
| 875 | int ret; | ||
| 876 | |||
| 877 | while (!list_empty(head)) { | ||
| 878 | pending = list_entry(head->next, | ||
| 879 | struct btrfs_pending_snapshot, list); | ||
| 880 | ret = finish_pending_snapshot(fs_info, pending); | ||
| 881 | BUG_ON(ret); | ||
| 882 | list_del(&pending->list); | ||
| 883 | kfree(pending->name); | ||
| 884 | kfree(pending); | ||
| 885 | } | ||
| 886 | return 0; | ||
| 887 | } | ||
| 888 | |||
| 889 | static void update_super_roots(struct btrfs_root *root) | 853 | static void update_super_roots(struct btrfs_root *root) | 
| 890 | { | 854 | { | 
| 891 | struct btrfs_root_item *root_item; | 855 | struct btrfs_root_item *root_item; | 
| @@ -997,13 +961,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 997 | 961 | ||
| 998 | mutex_unlock(&root->fs_info->trans_mutex); | 962 | mutex_unlock(&root->fs_info->trans_mutex); | 
| 999 | 963 | ||
| 1000 | if (flush_on_commit) { | 964 | if (flush_on_commit || snap_pending) { | 
| 1001 | btrfs_start_delalloc_inodes(root, 1); | 965 | btrfs_start_delalloc_inodes(root, 1); | 
| 1002 | ret = btrfs_wait_ordered_extents(root, 0, 1); | 966 | ret = btrfs_wait_ordered_extents(root, 0, 1); | 
| 1003 | BUG_ON(ret); | 967 | BUG_ON(ret); | 
| 1004 | } else if (snap_pending) { | ||
| 1005 | ret = btrfs_wait_ordered_extents(root, 0, 1); | ||
| 1006 | BUG_ON(ret); | ||
| 1007 | } | 968 | } | 
| 1008 | 969 | ||
| 1009 | /* | 970 | /* | 
| @@ -1100,9 +1061,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1100 | 1061 | ||
| 1101 | btrfs_finish_extent_commit(trans, root); | 1062 | btrfs_finish_extent_commit(trans, root); | 
| 1102 | 1063 | ||
| 1103 | /* do the directory inserts of any pending snapshot creations */ | ||
| 1104 | finish_pending_snapshots(trans, root->fs_info); | ||
| 1105 | |||
| 1106 | mutex_lock(&root->fs_info->trans_mutex); | 1064 | mutex_lock(&root->fs_info->trans_mutex); | 
| 1107 | 1065 | ||
| 1108 | cur_trans->commit_done = 1; | 1066 | cur_trans->commit_done = 1; | 
