feca06b43f19a9396a4f4b2d312db372cc7c08cc
[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         h->fs_info = fs_info;
42         fs_info->running_transaction = h;
43         fs_info->generation++;
44         h->transid = fs_info->generation;
45         h->blocks_reserved = num_blocks;
46         root->last_trans = h->transid;
47         root->commit_root = root->node;
48         extent_buffer_get(root->node);
49
50         return h;
51 }
52
53 static int update_cowonly_root(struct btrfs_trans_handle *trans,
54                                struct btrfs_root *root)
55 {
56         int ret;
57         u64 old_root_bytenr;
58         struct btrfs_root *tree_root = root->fs_info->tree_root;
59
60         btrfs_write_dirty_block_groups(trans, root);
61         while(1) {
62                 old_root_bytenr = btrfs_root_bytenr(&root->root_item);
63                 if (old_root_bytenr == root->node->start)
64                         break;
65                 btrfs_set_root_bytenr(&root->root_item,
66                                        root->node->start);
67                 btrfs_set_root_generation(&root->root_item,
68                                           trans->transid);
69                 root->root_item.level = btrfs_header_level(root->node);
70                 ret = btrfs_update_root(trans, tree_root,
71                                         &root->root_key,
72                                         &root->root_item);
73                 BUG_ON(ret);
74                 btrfs_write_dirty_block_groups(trans, root);
75         }
76         return 0;
77 }
78
79 int commit_tree_roots(struct btrfs_trans_handle *trans,
80                              struct btrfs_fs_info *fs_info)
81 {
82         struct btrfs_root *root;
83         struct list_head *next;
84         struct extent_buffer *eb;
85         int ret;
86
87         if (fs_info->readonly)
88                 return 0;
89
90         eb = fs_info->tree_root->node;
91         extent_buffer_get(eb);
92         ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb);
93         free_extent_buffer(eb);
94         if (ret)
95                 return ret;
96
97         while(!list_empty(&fs_info->dirty_cowonly_roots)) {
98                 next = fs_info->dirty_cowonly_roots.next;
99                 list_del_init(next);
100                 root = list_entry(next, struct btrfs_root, dirty_list);
101                 update_cowonly_root(trans, root);
102                 free_extent_buffer(root->commit_root);
103                 root->commit_root = NULL;
104         }
105
106         return 0;
107 }
108
109 int __commit_transaction(struct btrfs_trans_handle *trans,
110                                 struct btrfs_root *root)
111 {
112         u64 start;
113         u64 end;
114         struct btrfs_fs_info *fs_info = root->fs_info;
115         struct extent_buffer *eb;
116         struct extent_io_tree *tree = &fs_info->extent_cache;
117         int ret;
118
119         while(1) {
120                 ret = find_first_extent_bit(tree, 0, &start, &end,
121                                             EXTENT_DIRTY);
122                 if (ret)
123                         break;
124                 while(start <= end) {
125                         eb = find_first_extent_buffer(tree, start);
126                         BUG_ON(!eb || eb->start != start);
127                         ret = write_tree_block(trans, fs_info, eb);
128                         BUG_ON(ret);
129                         start += eb->len;
130                         clear_extent_buffer_dirty(eb);
131                         free_extent_buffer(eb);
132                 }
133         }
134         return 0;
135 }
136
137 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
138                              struct btrfs_root *root)
139 {
140         u64 transid = trans->transid;
141         int ret = 0;
142         struct btrfs_fs_info *fs_info = root->fs_info;
143
144         if (root->commit_root == root->node)
145                 goto commit_tree;
146         if (root == root->fs_info->tree_root)
147                 goto commit_tree;
148         if (root == root->fs_info->chunk_root)
149                 goto commit_tree;
150
151         free_extent_buffer(root->commit_root);
152         root->commit_root = NULL;
153
154         btrfs_set_root_bytenr(&root->root_item, root->node->start);
155         btrfs_set_root_generation(&root->root_item, trans->transid);
156         root->root_item.level = btrfs_header_level(root->node);
157         ret = btrfs_update_root(trans, root->fs_info->tree_root,
158                                 &root->root_key, &root->root_item);
159         BUG_ON(ret);
160 commit_tree:
161         ret = commit_tree_roots(trans, fs_info);
162         BUG_ON(ret);
163         ret = __commit_transaction(trans, root);
164         BUG_ON(ret);
165         write_ctree_super(trans, fs_info);
166         btrfs_finish_extent_commit(trans, fs_info->extent_root,
167                                    &fs_info->pinned_extents);
168         kfree(trans);
169         free_extent_buffer(root->commit_root);
170         root->commit_root = NULL;
171         fs_info->running_transaction = NULL;
172         fs_info->last_trans_committed = transid;
173         return 0;
174 }
175
176 void btrfs_abort_transaction(struct btrfs_trans_handle *trans, int error)
177 {
178         trans->fs_info->transaction_aborted = error;
179 }