80aa7bc48e02a45f3e518aac2d98188a29630c05
[platform/upstream/btrfs-progs.git] / transaction.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public
4  * License v2 as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9  * General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the
13  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14  * Boston, MA 021110-1307, USA.
15  */
16
17 #include "kerncompat.h"
18 #include "disk-io.h"
19 #include "transaction.h"
20
21 #include "messages.h"
22
23 struct btrfs_trans_handle* btrfs_start_transaction(struct btrfs_root *root,
24                 int num_blocks)
25 {
26         struct btrfs_fs_info *fs_info = root->fs_info;
27         struct btrfs_trans_handle *h = kzalloc(sizeof(*h), GFP_NOFS);
28
29         if (!h)
30                 return ERR_PTR(-ENOMEM);
31         if (root->commit_root) {
32                 error("commit_root aleady set when starting transaction");
33                 kfree(h);
34                 return ERR_PTR(-EINVAL);
35         }
36         if (fs_info->running_transaction) {
37                 error("attempt to start transaction over already running one");
38                 kfree(h);
39                 return ERR_PTR(-EINVAL);
40         }
41         fs_info->running_transaction = h;
42         fs_info->generation++;
43         h->transid = fs_info->generation;
44         h->blocks_reserved = num_blocks;
45         root->last_trans = h->transid;
46         root->commit_root = root->node;
47         extent_buffer_get(root->node);
48
49         return h;
50 }
51
52 static int update_cowonly_root(struct btrfs_trans_handle *trans,
53                                struct btrfs_root *root)
54 {
55         int ret;
56         u64 old_root_bytenr;
57         struct btrfs_root *tree_root = root->fs_info->tree_root;
58
59         btrfs_write_dirty_block_groups(trans, root);
60         while(1) {
61                 old_root_bytenr = btrfs_root_bytenr(&root->root_item);
62                 if (old_root_bytenr == root->node->start)
63                         break;
64                 btrfs_set_root_bytenr(&root->root_item,
65                                        root->node->start);
66                 btrfs_set_root_generation(&root->root_item,
67                                           trans->transid);
68                 root->root_item.level = btrfs_header_level(root->node);
69                 ret = btrfs_update_root(trans, tree_root,
70                                         &root->root_key,
71                                         &root->root_item);
72                 BUG_ON(ret);
73                 btrfs_write_dirty_block_groups(trans, root);
74         }
75         return 0;
76 }
77
78 int commit_tree_roots(struct btrfs_trans_handle *trans,
79                              struct btrfs_fs_info *fs_info)
80 {
81         struct btrfs_root *root;
82         struct list_head *next;
83         struct extent_buffer *eb;
84         int ret;
85
86         if (fs_info->readonly)
87                 return 0;
88
89         eb = fs_info->tree_root->node;
90         extent_buffer_get(eb);
91         ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
92         free_extent_buffer(eb);
93         if (ret)
94                 return ret;
95
96         while(!list_empty(&fs_info->dirty_cowonly_roots)) {
97                 next = fs_info->dirty_cowonly_roots.next;
98                 list_del_init(next);
99                 root = list_entry(next, struct btrfs_root, dirty_list);
100                 update_cowonly_root(trans, root);
101                 free_extent_buffer(root->commit_root);
102                 root->commit_root = NULL;
103         }
104
105         return 0;
106 }
107
108 int __commit_transaction(struct btrfs_trans_handle *trans,
109                                 struct btrfs_root *root)
110 {
111         u64 start;
112         u64 end;
113         struct btrfs_fs_info *fs_info = root->fs_info;
114         struct extent_buffer *eb;
115         struct extent_io_tree *tree = &fs_info->extent_cache;
116         int ret;
117
118         while(1) {
119                 ret = find_first_extent_bit(tree, 0, &start, &end,
120                                             EXTENT_DIRTY);
121                 if (ret)
122                         break;
123                 while(start <= end) {
124                         eb = find_first_extent_buffer(tree, start);
125                         BUG_ON(!eb || eb->start != start);
126                         ret = write_tree_block(trans, fs_info, eb);
127                         BUG_ON(ret);
128                         start += eb->len;
129                         clear_extent_buffer_dirty(eb);
130                         free_extent_buffer(eb);
131                 }
132         }
133         return 0;
134 }
135
136 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
137                              struct btrfs_root *root)
138 {
139         u64 transid = trans->transid;
140         int ret = 0;
141         struct btrfs_fs_info *fs_info = root->fs_info;
142
143         if (root->commit_root == root->node)
144                 goto commit_tree;
145         if (root == root->fs_info->tree_root)
146                 goto commit_tree;
147         if (root == root->fs_info->chunk_root)
148                 goto commit_tree;
149
150         free_extent_buffer(root->commit_root);
151         root->commit_root = NULL;
152
153         btrfs_set_root_bytenr(&root->root_item, root->node->start);
154         btrfs_set_root_generation(&root->root_item, trans->transid);
155         root->root_item.level = btrfs_header_level(root->node);
156         ret = btrfs_update_root(trans, root->fs_info->tree_root,
157                                 &root->root_key, &root->root_item);
158         BUG_ON(ret);
159 commit_tree:
160         ret = commit_tree_roots(trans, fs_info);
161         BUG_ON(ret);
162         ret = __commit_transaction(trans, root);
163         BUG_ON(ret);
164         write_ctree_super(trans, fs_info);
165         btrfs_finish_extent_commit(trans, fs_info->extent_root,
166                                    &fs_info->pinned_extents);
167         kfree(trans);
168         free_extent_buffer(root->commit_root);
169         root->commit_root = NULL;
170         fs_info->running_transaction = NULL;
171         fs_info->last_trans_committed = transid;
172         return 0;
173 }
174