aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-22 15:59:16 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-22 15:59:16 -0400
commit79154b1b5bcf87903db7ff16a30b360b78d6fe4f (patch)
tree7c752c350abd28060c5bd7aa364323051aecac90 /fs/btrfs/transaction.c
parente20d96d64f9cf9288ffecc9ad4714e91c3b97ca8 (diff)
Btrfs: transaction rework
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
new file mode 100644
index 000000000000..8dc1c170f10f
--- /dev/null
+++ b/fs/btrfs/transaction.c
@@ -0,0 +1,199 @@
1#include <linux/module.h>
2#include <linux/fs.h>
3#include "ctree.h"
4#include "disk-io.h"
5#include "transaction.h"
6
7
8static void put_transaction(struct btrfs_transaction *transaction)
9{
10 transaction->use_count--;
11 if (transaction->use_count == 0)
12 kfree(transaction);
13}
14
15static int join_transaction(struct btrfs_root *root)
16{
17 struct btrfs_transaction *cur_trans;
18 cur_trans = root->fs_info->running_transaction;
19 if (!cur_trans) {
20 cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS);
21 BUG_ON(!cur_trans);
22 root->fs_info->running_transaction = cur_trans;
23 cur_trans->num_writers = 0;
24 cur_trans->transid = root->root_key.offset + 1;
25 init_waitqueue_head(&cur_trans->writer_wait);
26 init_waitqueue_head(&cur_trans->commit_wait);
27 cur_trans->in_commit = 0;
28 cur_trans->use_count = 0;
29 cur_trans->commit_done = 0;
30 }
31 cur_trans->num_writers++;
32 return 0;
33}
34
35struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
36 int num_blocks)
37{
38 struct btrfs_trans_handle *h = kmalloc(sizeof(*h), GFP_NOFS);
39 int ret;
40
41 mutex_lock(&root->fs_info->trans_mutex);
42 ret = join_transaction(root);
43 BUG_ON(ret);
44 h->transid = root->fs_info->running_transaction->transid;
45 h->transaction = root->fs_info->running_transaction;
46 h->blocks_reserved = num_blocks;
47 h->blocks_used = 0;
48 root->fs_info->running_transaction->use_count++;
49 mutex_unlock(&root->fs_info->trans_mutex);
50 return h;
51}
52
53int btrfs_end_transaction(struct btrfs_trans_handle *trans,
54 struct btrfs_root *root)
55{
56 struct btrfs_transaction *cur_trans;
57 mutex_lock(&root->fs_info->trans_mutex);
58 cur_trans = root->fs_info->running_transaction;
59 WARN_ON(cur_trans->num_writers <= 1);
60 if (waitqueue_active(&cur_trans->writer_wait))
61 wake_up(&cur_trans->writer_wait);
62 cur_trans->num_writers--;
63 put_transaction(cur_trans);
64 mutex_unlock(&root->fs_info->trans_mutex);
65 kfree(trans);
66 return 0;
67}
68
69
70int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
71 struct btrfs_root *root)
72{
73 filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping);
74 return 0;
75}
76
77int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
78 struct btrfs_root *root)
79{
80 int ret;
81 u64 old_extent_block;
82 struct btrfs_fs_info *fs_info = root->fs_info;
83 struct btrfs_root *tree_root = fs_info->tree_root;
84 struct btrfs_root *extent_root = fs_info->extent_root;
85 struct btrfs_root *inode_root = fs_info->inode_root;
86
87 btrfs_set_root_blocknr(&inode_root->root_item,
88 inode_root->node->b_blocknr);
89 ret = btrfs_update_root(trans, tree_root,
90 &inode_root->root_key,
91 &inode_root->root_item);
92 BUG_ON(ret);
93 while(1) {
94 old_extent_block = btrfs_root_blocknr(&extent_root->root_item);
95 if (old_extent_block == extent_root->node->b_blocknr)
96 break;
97 btrfs_set_root_blocknr(&extent_root->root_item,
98 extent_root->node->b_blocknr);
99 ret = btrfs_update_root(trans, tree_root,
100 &extent_root->root_key,
101 &extent_root->root_item);
102 BUG_ON(ret);
103 }
104 return 0;
105}
106
107static int wait_for_commit(struct btrfs_root *root,
108 struct btrfs_transaction *commit)
109{
110 DEFINE_WAIT(wait);
111 commit->use_count++;
112 while(!commit->commit_done) {
113 prepare_to_wait(&commit->commit_wait, &wait,
114 TASK_UNINTERRUPTIBLE);
115 if (commit->commit_done)
116 break;
117 mutex_unlock(&root->fs_info->trans_mutex);
118 schedule();
119 mutex_lock(&root->fs_info->trans_mutex);
120 }
121 finish_wait(&commit->commit_wait, &wait);
122 return 0;
123}
124
125int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
126 struct btrfs_root *root)
127{
128 int ret = 0;
129 struct buffer_head *snap = root->commit_root;
130 struct btrfs_key snap_key;
131 struct btrfs_transaction *cur_trans;
132 DEFINE_WAIT(wait);
133
134 mutex_lock(&root->fs_info->trans_mutex);
135 if (trans->transaction->in_commit) {
136 cur_trans = trans->transaction;
137 trans->transaction->use_count++;
138 btrfs_end_transaction(trans, root);
139 ret = wait_for_commit(root, cur_trans);
140 BUG_ON(ret);
141 put_transaction(cur_trans);
142 mutex_unlock(&root->fs_info->trans_mutex);
143 return 0;
144 }
145 while (trans->transaction->num_writers > 1) {
146 prepare_to_wait(&trans->transaction->writer_wait, &wait,
147 TASK_UNINTERRUPTIBLE);
148 if (trans->transaction->num_writers <= 1)
149 break;
150 mutex_unlock(&root->fs_info->trans_mutex);
151 schedule();
152 mutex_lock(&root->fs_info->trans_mutex);
153 }
154 finish_wait(&trans->transaction->writer_wait, &wait);
155
156 cur_trans = root->fs_info->running_transaction;
157 root->fs_info->running_transaction = NULL;
158 mutex_unlock(&root->fs_info->trans_mutex);
159
160 memcpy(&snap_key, &root->root_key, sizeof(snap_key));
161 root->root_key.offset++;
162
163 if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) {
164 btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr);
165 ret = btrfs_insert_root(trans, root->fs_info->tree_root,
166 &root->root_key, &root->root_item);
167 BUG_ON(ret);
168 }
169
170 ret = btrfs_commit_tree_roots(trans, root);
171 BUG_ON(ret);
172
173 ret = btrfs_write_and_wait_transaction(trans, root);
174 BUG_ON(ret);
175
176 write_ctree_super(trans, root);
177 btrfs_finish_extent_commit(trans, root->fs_info->extent_root);
178 btrfs_finish_extent_commit(trans, root->fs_info->tree_root);
179 put_transaction(cur_trans);
180 kfree(trans);
181
182 if (root->node != root->commit_root) {
183 trans = btrfs_start_transaction(root, 1);
184 root->commit_root = root->node;
185 get_bh(root->node);
186 ret = btrfs_drop_snapshot(trans, root, snap);
187 BUG_ON(ret);
188
189 ret = btrfs_del_root(trans, root->fs_info->tree_root,
190 &snap_key);
191 BUG_ON(ret);
192 root->fs_info->generation = root->root_key.offset + 1;
193 ret = btrfs_end_transaction(trans, root);
194 BUG_ON(ret);
195 }
196
197 return ret;
198}
199