Commit | Line | Data |
---|---|---|
79154b1b CM |
1 | #include <linux/module.h> |
2 | #include <linux/fs.h> | |
3 | #include "ctree.h" | |
4 | #include "disk-io.h" | |
5 | #include "transaction.h" | |
6 | ||
78fae27e | 7 | static int total_trans = 0; |
2c90e5d6 CM |
8 | extern struct kmem_cache *btrfs_trans_handle_cachep; |
9 | extern struct kmem_cache *btrfs_transaction_cachep; | |
10 | ||
11 | #define TRANS_MAGIC 0xE1E10E | |
79154b1b CM |
12 | static void put_transaction(struct btrfs_transaction *transaction) |
13 | { | |
2c90e5d6 | 14 | WARN_ON(transaction->use_count == 0); |
79154b1b | 15 | transaction->use_count--; |
2c90e5d6 | 16 | WARN_ON(transaction->magic != TRANS_MAGIC); |
78fae27e CM |
17 | if (transaction->use_count == 0) { |
18 | WARN_ON(total_trans == 0); | |
19 | total_trans--; | |
2c90e5d6 CM |
20 | memset(transaction, 0, sizeof(*transaction)); |
21 | kmem_cache_free(btrfs_transaction_cachep, transaction); | |
78fae27e | 22 | } |
79154b1b CM |
23 | } |
24 | ||
25 | static int join_transaction(struct btrfs_root *root) | |
26 | { | |
27 | struct btrfs_transaction *cur_trans; | |
28 | cur_trans = root->fs_info->running_transaction; | |
29 | if (!cur_trans) { | |
2c90e5d6 CM |
30 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, |
31 | GFP_NOFS); | |
78fae27e | 32 | total_trans++; |
79154b1b CM |
33 | BUG_ON(!cur_trans); |
34 | root->fs_info->running_transaction = cur_trans; | |
35 | cur_trans->num_writers = 0; | |
36 | cur_trans->transid = root->root_key.offset + 1; | |
37 | init_waitqueue_head(&cur_trans->writer_wait); | |
38 | init_waitqueue_head(&cur_trans->commit_wait); | |
2c90e5d6 | 39 | cur_trans->magic = TRANS_MAGIC; |
79154b1b | 40 | cur_trans->in_commit = 0; |
d5719762 | 41 | cur_trans->use_count = 1; |
79154b1b CM |
42 | cur_trans->commit_done = 0; |
43 | } | |
44 | cur_trans->num_writers++; | |
45 | return 0; | |
46 | } | |
47 | ||
48 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |
49 | int num_blocks) | |
50 | { | |
2c90e5d6 CM |
51 | struct btrfs_trans_handle *h = |
52 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | |
79154b1b CM |
53 | int ret; |
54 | ||
d6e4a428 CM |
55 | /* FIXME, use the right root */ |
56 | root = root->fs_info->fs_root; | |
79154b1b CM |
57 | mutex_lock(&root->fs_info->trans_mutex); |
58 | ret = join_transaction(root); | |
59 | BUG_ON(ret); | |
60 | h->transid = root->fs_info->running_transaction->transid; | |
61 | h->transaction = root->fs_info->running_transaction; | |
62 | h->blocks_reserved = num_blocks; | |
63 | h->blocks_used = 0; | |
64 | root->fs_info->running_transaction->use_count++; | |
65 | mutex_unlock(&root->fs_info->trans_mutex); | |
2c90e5d6 | 66 | h->magic = h->magic2 = TRANS_MAGIC; |
79154b1b CM |
67 | return h; |
68 | } | |
69 | ||
70 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |
71 | struct btrfs_root *root) | |
72 | { | |
73 | struct btrfs_transaction *cur_trans; | |
d6e4a428 CM |
74 | |
75 | /* FIXME, use the right root */ | |
76 | root = root->fs_info->fs_root; | |
77 | ||
2c90e5d6 CM |
78 | WARN_ON(trans->magic != TRANS_MAGIC); |
79 | WARN_ON(trans->magic2 != TRANS_MAGIC); | |
79154b1b CM |
80 | mutex_lock(&root->fs_info->trans_mutex); |
81 | cur_trans = root->fs_info->running_transaction; | |
d5719762 | 82 | WARN_ON(cur_trans->num_writers < 1); |
79154b1b CM |
83 | if (waitqueue_active(&cur_trans->writer_wait)) |
84 | wake_up(&cur_trans->writer_wait); | |
85 | cur_trans->num_writers--; | |
86 | put_transaction(cur_trans); | |
87 | mutex_unlock(&root->fs_info->trans_mutex); | |
d6025579 | 88 | memset(trans, 0, sizeof(*trans)); |
2c90e5d6 | 89 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
79154b1b CM |
90 | return 0; |
91 | } | |
92 | ||
93 | ||
94 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | |
95 | struct btrfs_root *root) | |
96 | { | |
7cfcc17e | 97 | filemap_write_and_wait(root->fs_info->btree_inode->i_mapping); |
79154b1b CM |
98 | return 0; |
99 | } | |
100 | ||
101 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |
102 | struct btrfs_root *root) | |
103 | { | |
104 | int ret; | |
105 | u64 old_extent_block; | |
106 | struct btrfs_fs_info *fs_info = root->fs_info; | |
107 | struct btrfs_root *tree_root = fs_info->tree_root; | |
108 | struct btrfs_root *extent_root = fs_info->extent_root; | |
109 | struct btrfs_root *inode_root = fs_info->inode_root; | |
110 | ||
111 | btrfs_set_root_blocknr(&inode_root->root_item, | |
112 | inode_root->node->b_blocknr); | |
113 | ret = btrfs_update_root(trans, tree_root, | |
114 | &inode_root->root_key, | |
115 | &inode_root->root_item); | |
116 | BUG_ON(ret); | |
117 | while(1) { | |
118 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | |
119 | if (old_extent_block == extent_root->node->b_blocknr) | |
120 | break; | |
121 | btrfs_set_root_blocknr(&extent_root->root_item, | |
122 | extent_root->node->b_blocknr); | |
123 | ret = btrfs_update_root(trans, tree_root, | |
124 | &extent_root->root_key, | |
125 | &extent_root->root_item); | |
126 | BUG_ON(ret); | |
127 | } | |
128 | return 0; | |
129 | } | |
130 | ||
131 | static int wait_for_commit(struct btrfs_root *root, | |
132 | struct btrfs_transaction *commit) | |
133 | { | |
134 | DEFINE_WAIT(wait); | |
79154b1b CM |
135 | while(!commit->commit_done) { |
136 | prepare_to_wait(&commit->commit_wait, &wait, | |
137 | TASK_UNINTERRUPTIBLE); | |
138 | if (commit->commit_done) | |
139 | break; | |
140 | mutex_unlock(&root->fs_info->trans_mutex); | |
141 | schedule(); | |
142 | mutex_lock(&root->fs_info->trans_mutex); | |
143 | } | |
144 | finish_wait(&commit->commit_wait, &wait); | |
145 | return 0; | |
146 | } | |
147 | ||
148 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |
149 | struct btrfs_root *root) | |
150 | { | |
151 | int ret = 0; | |
78fae27e | 152 | struct buffer_head *snap; |
79154b1b CM |
153 | struct btrfs_key snap_key; |
154 | struct btrfs_transaction *cur_trans; | |
155 | DEFINE_WAIT(wait); | |
156 | ||
d6e4a428 CM |
157 | /* FIXME, use the right root */ |
158 | root = root->fs_info->fs_root; | |
159 | ||
79154b1b CM |
160 | mutex_lock(&root->fs_info->trans_mutex); |
161 | if (trans->transaction->in_commit) { | |
2c90e5d6 | 162 | printk("already in commit!, waiting\n"); |
79154b1b CM |
163 | cur_trans = trans->transaction; |
164 | trans->transaction->use_count++; | |
165 | btrfs_end_transaction(trans, root); | |
166 | ret = wait_for_commit(root, cur_trans); | |
167 | BUG_ON(ret); | |
168 | put_transaction(cur_trans); | |
169 | mutex_unlock(&root->fs_info->trans_mutex); | |
170 | return 0; | |
171 | } | |
2c90e5d6 CM |
172 | cur_trans = trans->transaction; |
173 | trans->transaction->in_commit = 1; | |
79154b1b | 174 | while (trans->transaction->num_writers > 1) { |
2c90e5d6 | 175 | WARN_ON(cur_trans != trans->transaction); |
79154b1b CM |
176 | prepare_to_wait(&trans->transaction->writer_wait, &wait, |
177 | TASK_UNINTERRUPTIBLE); | |
178 | if (trans->transaction->num_writers <= 1) | |
179 | break; | |
180 | mutex_unlock(&root->fs_info->trans_mutex); | |
181 | schedule(); | |
182 | mutex_lock(&root->fs_info->trans_mutex); | |
2c90e5d6 | 183 | finish_wait(&trans->transaction->writer_wait, &wait); |
79154b1b CM |
184 | } |
185 | finish_wait(&trans->transaction->writer_wait, &wait); | |
2c90e5d6 | 186 | WARN_ON(cur_trans != trans->transaction); |
d5719762 CM |
187 | if (root->node != root->commit_root) { |
188 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | |
189 | root->root_key.offset++; | |
190 | } | |
191 | ||
79154b1b CM |
192 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { |
193 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | |
194 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | |
195 | &root->root_key, &root->root_item); | |
196 | BUG_ON(ret); | |
197 | } | |
198 | ||
199 | ret = btrfs_commit_tree_roots(trans, root); | |
200 | BUG_ON(ret); | |
78fae27e CM |
201 | cur_trans = root->fs_info->running_transaction; |
202 | root->fs_info->running_transaction = NULL; | |
203 | mutex_unlock(&root->fs_info->trans_mutex); | |
79154b1b CM |
204 | ret = btrfs_write_and_wait_transaction(trans, root); |
205 | BUG_ON(ret); | |
206 | ||
207 | write_ctree_super(trans, root); | |
78fae27e CM |
208 | btrfs_finish_extent_commit(trans, root); |
209 | mutex_lock(&root->fs_info->trans_mutex); | |
2c90e5d6 CM |
210 | cur_trans->commit_done = 1; |
211 | wake_up(&cur_trans->commit_wait); | |
78fae27e | 212 | put_transaction(cur_trans); |
79154b1b | 213 | put_transaction(cur_trans); |
78fae27e | 214 | mutex_unlock(&root->fs_info->trans_mutex); |
2c90e5d6 | 215 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
79154b1b CM |
216 | if (root->node != root->commit_root) { |
217 | trans = btrfs_start_transaction(root, 1); | |
78fae27e | 218 | snap = root->commit_root; |
79154b1b CM |
219 | root->commit_root = root->node; |
220 | get_bh(root->node); | |
221 | ret = btrfs_drop_snapshot(trans, root, snap); | |
222 | BUG_ON(ret); | |
223 | ||
224 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | |
225 | &snap_key); | |
22b0ebda CM |
226 | BUG_ON(ret); |
227 | root->fs_info->generation = root->root_key.offset + 1; | |
228 | ret = btrfs_end_transaction(trans, root); | |
229 | BUG_ON(ret); | |
79154b1b | 230 | } |
79154b1b CM |
231 | return ret; |
232 | } | |
233 |