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 | ||
55 | mutex_lock(&root->fs_info->trans_mutex); | |
56 | ret = join_transaction(root); | |
57 | BUG_ON(ret); | |
58 | h->transid = root->fs_info->running_transaction->transid; | |
59 | h->transaction = root->fs_info->running_transaction; | |
60 | h->blocks_reserved = num_blocks; | |
61 | h->blocks_used = 0; | |
62 | root->fs_info->running_transaction->use_count++; | |
63 | mutex_unlock(&root->fs_info->trans_mutex); | |
2c90e5d6 | 64 | h->magic = h->magic2 = TRANS_MAGIC; |
79154b1b CM |
65 | return h; |
66 | } | |
67 | ||
68 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |
69 | struct btrfs_root *root) | |
70 | { | |
71 | struct btrfs_transaction *cur_trans; | |
2c90e5d6 CM |
72 | WARN_ON(trans->magic != TRANS_MAGIC); |
73 | WARN_ON(trans->magic2 != TRANS_MAGIC); | |
79154b1b CM |
74 | mutex_lock(&root->fs_info->trans_mutex); |
75 | cur_trans = root->fs_info->running_transaction; | |
d5719762 | 76 | WARN_ON(cur_trans->num_writers < 1); |
79154b1b CM |
77 | if (waitqueue_active(&cur_trans->writer_wait)) |
78 | wake_up(&cur_trans->writer_wait); | |
79 | cur_trans->num_writers--; | |
80 | put_transaction(cur_trans); | |
81 | mutex_unlock(&root->fs_info->trans_mutex); | |
d6025579 | 82 | memset(trans, 0, sizeof(*trans)); |
2c90e5d6 | 83 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
79154b1b CM |
84 | return 0; |
85 | } | |
86 | ||
87 | ||
88 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | |
89 | struct btrfs_root *root) | |
90 | { | |
7cfcc17e | 91 | filemap_write_and_wait(root->fs_info->btree_inode->i_mapping); |
79154b1b CM |
92 | return 0; |
93 | } | |
94 | ||
95 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |
96 | struct btrfs_root *root) | |
97 | { | |
98 | int ret; | |
99 | u64 old_extent_block; | |
100 | struct btrfs_fs_info *fs_info = root->fs_info; | |
101 | struct btrfs_root *tree_root = fs_info->tree_root; | |
102 | struct btrfs_root *extent_root = fs_info->extent_root; | |
103 | struct btrfs_root *inode_root = fs_info->inode_root; | |
104 | ||
105 | btrfs_set_root_blocknr(&inode_root->root_item, | |
106 | inode_root->node->b_blocknr); | |
107 | ret = btrfs_update_root(trans, tree_root, | |
108 | &inode_root->root_key, | |
109 | &inode_root->root_item); | |
110 | BUG_ON(ret); | |
111 | while(1) { | |
112 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | |
113 | if (old_extent_block == extent_root->node->b_blocknr) | |
114 | break; | |
115 | btrfs_set_root_blocknr(&extent_root->root_item, | |
116 | extent_root->node->b_blocknr); | |
117 | ret = btrfs_update_root(trans, tree_root, | |
118 | &extent_root->root_key, | |
119 | &extent_root->root_item); | |
120 | BUG_ON(ret); | |
121 | } | |
122 | return 0; | |
123 | } | |
124 | ||
125 | static int wait_for_commit(struct btrfs_root *root, | |
126 | struct btrfs_transaction *commit) | |
127 | { | |
128 | DEFINE_WAIT(wait); | |
79154b1b CM |
129 | while(!commit->commit_done) { |
130 | prepare_to_wait(&commit->commit_wait, &wait, | |
131 | TASK_UNINTERRUPTIBLE); | |
132 | if (commit->commit_done) | |
133 | break; | |
134 | mutex_unlock(&root->fs_info->trans_mutex); | |
135 | schedule(); | |
136 | mutex_lock(&root->fs_info->trans_mutex); | |
137 | } | |
138 | finish_wait(&commit->commit_wait, &wait); | |
139 | return 0; | |
140 | } | |
141 | ||
142 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |
143 | struct btrfs_root *root) | |
144 | { | |
145 | int ret = 0; | |
78fae27e | 146 | struct buffer_head *snap; |
79154b1b CM |
147 | struct btrfs_key snap_key; |
148 | struct btrfs_transaction *cur_trans; | |
149 | DEFINE_WAIT(wait); | |
150 | ||
151 | mutex_lock(&root->fs_info->trans_mutex); | |
152 | if (trans->transaction->in_commit) { | |
2c90e5d6 | 153 | printk("already in commit!, waiting\n"); |
79154b1b CM |
154 | cur_trans = trans->transaction; |
155 | trans->transaction->use_count++; | |
156 | btrfs_end_transaction(trans, root); | |
157 | ret = wait_for_commit(root, cur_trans); | |
158 | BUG_ON(ret); | |
159 | put_transaction(cur_trans); | |
160 | mutex_unlock(&root->fs_info->trans_mutex); | |
161 | return 0; | |
162 | } | |
2c90e5d6 CM |
163 | cur_trans = trans->transaction; |
164 | trans->transaction->in_commit = 1; | |
79154b1b | 165 | while (trans->transaction->num_writers > 1) { |
2c90e5d6 | 166 | WARN_ON(cur_trans != trans->transaction); |
79154b1b CM |
167 | prepare_to_wait(&trans->transaction->writer_wait, &wait, |
168 | TASK_UNINTERRUPTIBLE); | |
169 | if (trans->transaction->num_writers <= 1) | |
170 | break; | |
171 | mutex_unlock(&root->fs_info->trans_mutex); | |
172 | schedule(); | |
173 | mutex_lock(&root->fs_info->trans_mutex); | |
2c90e5d6 | 174 | finish_wait(&trans->transaction->writer_wait, &wait); |
79154b1b CM |
175 | } |
176 | finish_wait(&trans->transaction->writer_wait, &wait); | |
2c90e5d6 | 177 | WARN_ON(cur_trans != trans->transaction); |
d5719762 CM |
178 | if (root->node != root->commit_root) { |
179 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | |
180 | root->root_key.offset++; | |
181 | } | |
182 | ||
79154b1b CM |
183 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { |
184 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | |
185 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | |
186 | &root->root_key, &root->root_item); | |
187 | BUG_ON(ret); | |
188 | } | |
189 | ||
190 | ret = btrfs_commit_tree_roots(trans, root); | |
191 | BUG_ON(ret); | |
78fae27e CM |
192 | cur_trans = root->fs_info->running_transaction; |
193 | root->fs_info->running_transaction = NULL; | |
194 | mutex_unlock(&root->fs_info->trans_mutex); | |
79154b1b CM |
195 | ret = btrfs_write_and_wait_transaction(trans, root); |
196 | BUG_ON(ret); | |
197 | ||
198 | write_ctree_super(trans, root); | |
78fae27e CM |
199 | btrfs_finish_extent_commit(trans, root); |
200 | mutex_lock(&root->fs_info->trans_mutex); | |
2c90e5d6 CM |
201 | cur_trans->commit_done = 1; |
202 | wake_up(&cur_trans->commit_wait); | |
78fae27e | 203 | put_transaction(cur_trans); |
79154b1b | 204 | put_transaction(cur_trans); |
78fae27e | 205 | mutex_unlock(&root->fs_info->trans_mutex); |
2c90e5d6 | 206 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
79154b1b CM |
207 | if (root->node != root->commit_root) { |
208 | trans = btrfs_start_transaction(root, 1); | |
78fae27e | 209 | snap = root->commit_root; |
79154b1b CM |
210 | root->commit_root = root->node; |
211 | get_bh(root->node); | |
212 | ret = btrfs_drop_snapshot(trans, root, snap); | |
213 | BUG_ON(ret); | |
214 | ||
215 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | |
216 | &snap_key); | |
22b0ebda CM |
217 | BUG_ON(ret); |
218 | root->fs_info->generation = root->root_key.offset + 1; | |
219 | ret = btrfs_end_transaction(trans, root); | |
220 | BUG_ON(ret); | |
79154b1b | 221 | } |
79154b1b CM |
222 | return ret; |
223 | } | |
224 |