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; |
79154b1b CM |
8 | static void put_transaction(struct btrfs_transaction *transaction) |
9 | { | |
10 | transaction->use_count--; | |
78fae27e CM |
11 | if (transaction->use_count == 0) { |
12 | WARN_ON(total_trans == 0); | |
13 | total_trans--; | |
79154b1b | 14 | kfree(transaction); |
78fae27e | 15 | } |
79154b1b CM |
16 | } |
17 | ||
18 | static int join_transaction(struct btrfs_root *root) | |
19 | { | |
20 | struct btrfs_transaction *cur_trans; | |
21 | cur_trans = root->fs_info->running_transaction; | |
22 | if (!cur_trans) { | |
23 | cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS); | |
78fae27e | 24 | total_trans++; |
79154b1b CM |
25 | BUG_ON(!cur_trans); |
26 | root->fs_info->running_transaction = cur_trans; | |
27 | cur_trans->num_writers = 0; | |
28 | cur_trans->transid = root->root_key.offset + 1; | |
29 | init_waitqueue_head(&cur_trans->writer_wait); | |
30 | init_waitqueue_head(&cur_trans->commit_wait); | |
31 | cur_trans->in_commit = 0; | |
d5719762 | 32 | cur_trans->use_count = 1; |
79154b1b CM |
33 | cur_trans->commit_done = 0; |
34 | } | |
35 | cur_trans->num_writers++; | |
36 | return 0; | |
37 | } | |
38 | ||
39 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |
40 | int num_blocks) | |
41 | { | |
42 | struct btrfs_trans_handle *h = kmalloc(sizeof(*h), GFP_NOFS); | |
43 | int ret; | |
44 | ||
45 | mutex_lock(&root->fs_info->trans_mutex); | |
46 | ret = join_transaction(root); | |
47 | BUG_ON(ret); | |
48 | h->transid = root->fs_info->running_transaction->transid; | |
49 | h->transaction = root->fs_info->running_transaction; | |
50 | h->blocks_reserved = num_blocks; | |
51 | h->blocks_used = 0; | |
52 | root->fs_info->running_transaction->use_count++; | |
53 | mutex_unlock(&root->fs_info->trans_mutex); | |
54 | return h; | |
55 | } | |
56 | ||
57 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |
58 | struct btrfs_root *root) | |
59 | { | |
60 | struct btrfs_transaction *cur_trans; | |
61 | mutex_lock(&root->fs_info->trans_mutex); | |
62 | cur_trans = root->fs_info->running_transaction; | |
d5719762 | 63 | WARN_ON(cur_trans->num_writers < 1); |
79154b1b CM |
64 | if (waitqueue_active(&cur_trans->writer_wait)) |
65 | wake_up(&cur_trans->writer_wait); | |
66 | cur_trans->num_writers--; | |
67 | put_transaction(cur_trans); | |
68 | mutex_unlock(&root->fs_info->trans_mutex); | |
69 | kfree(trans); | |
70 | return 0; | |
71 | } | |
72 | ||
73 | ||
74 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | |
75 | struct btrfs_root *root) | |
76 | { | |
77 | filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping); | |
78 | return 0; | |
79 | } | |
80 | ||
81 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |
82 | struct btrfs_root *root) | |
83 | { | |
84 | int ret; | |
85 | u64 old_extent_block; | |
86 | struct btrfs_fs_info *fs_info = root->fs_info; | |
87 | struct btrfs_root *tree_root = fs_info->tree_root; | |
88 | struct btrfs_root *extent_root = fs_info->extent_root; | |
89 | struct btrfs_root *inode_root = fs_info->inode_root; | |
90 | ||
91 | btrfs_set_root_blocknr(&inode_root->root_item, | |
92 | inode_root->node->b_blocknr); | |
93 | ret = btrfs_update_root(trans, tree_root, | |
94 | &inode_root->root_key, | |
95 | &inode_root->root_item); | |
96 | BUG_ON(ret); | |
97 | while(1) { | |
98 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | |
99 | if (old_extent_block == extent_root->node->b_blocknr) | |
100 | break; | |
101 | btrfs_set_root_blocknr(&extent_root->root_item, | |
102 | extent_root->node->b_blocknr); | |
103 | ret = btrfs_update_root(trans, tree_root, | |
104 | &extent_root->root_key, | |
105 | &extent_root->root_item); | |
106 | BUG_ON(ret); | |
107 | } | |
108 | return 0; | |
109 | } | |
110 | ||
111 | static int wait_for_commit(struct btrfs_root *root, | |
112 | struct btrfs_transaction *commit) | |
113 | { | |
114 | DEFINE_WAIT(wait); | |
79154b1b CM |
115 | while(!commit->commit_done) { |
116 | prepare_to_wait(&commit->commit_wait, &wait, | |
117 | TASK_UNINTERRUPTIBLE); | |
118 | if (commit->commit_done) | |
119 | break; | |
120 | mutex_unlock(&root->fs_info->trans_mutex); | |
121 | schedule(); | |
122 | mutex_lock(&root->fs_info->trans_mutex); | |
123 | } | |
124 | finish_wait(&commit->commit_wait, &wait); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |
129 | struct btrfs_root *root) | |
130 | { | |
131 | int ret = 0; | |
78fae27e | 132 | struct buffer_head *snap; |
79154b1b CM |
133 | struct btrfs_key snap_key; |
134 | struct btrfs_transaction *cur_trans; | |
135 | DEFINE_WAIT(wait); | |
136 | ||
137 | mutex_lock(&root->fs_info->trans_mutex); | |
138 | if (trans->transaction->in_commit) { | |
139 | cur_trans = trans->transaction; | |
140 | trans->transaction->use_count++; | |
141 | btrfs_end_transaction(trans, root); | |
142 | ret = wait_for_commit(root, cur_trans); | |
143 | BUG_ON(ret); | |
144 | put_transaction(cur_trans); | |
145 | mutex_unlock(&root->fs_info->trans_mutex); | |
146 | return 0; | |
147 | } | |
148 | while (trans->transaction->num_writers > 1) { | |
149 | prepare_to_wait(&trans->transaction->writer_wait, &wait, | |
150 | TASK_UNINTERRUPTIBLE); | |
151 | if (trans->transaction->num_writers <= 1) | |
152 | break; | |
153 | mutex_unlock(&root->fs_info->trans_mutex); | |
154 | schedule(); | |
155 | mutex_lock(&root->fs_info->trans_mutex); | |
156 | } | |
157 | finish_wait(&trans->transaction->writer_wait, &wait); | |
158 | ||
d5719762 CM |
159 | if (root->node != root->commit_root) { |
160 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | |
161 | root->root_key.offset++; | |
162 | } | |
163 | ||
79154b1b CM |
164 | |
165 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { | |
166 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | |
167 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | |
168 | &root->root_key, &root->root_item); | |
169 | BUG_ON(ret); | |
170 | } | |
171 | ||
172 | ret = btrfs_commit_tree_roots(trans, root); | |
173 | BUG_ON(ret); | |
174 | ||
78fae27e CM |
175 | cur_trans = root->fs_info->running_transaction; |
176 | root->fs_info->running_transaction = NULL; | |
177 | mutex_unlock(&root->fs_info->trans_mutex); | |
178 | ||
79154b1b CM |
179 | ret = btrfs_write_and_wait_transaction(trans, root); |
180 | BUG_ON(ret); | |
181 | ||
182 | write_ctree_super(trans, root); | |
78fae27e CM |
183 | btrfs_finish_extent_commit(trans, root); |
184 | mutex_lock(&root->fs_info->trans_mutex); | |
185 | put_transaction(cur_trans); | |
79154b1b | 186 | put_transaction(cur_trans); |
78fae27e | 187 | mutex_unlock(&root->fs_info->trans_mutex); |
79154b1b CM |
188 | kfree(trans); |
189 | ||
190 | if (root->node != root->commit_root) { | |
191 | trans = btrfs_start_transaction(root, 1); | |
78fae27e | 192 | snap = root->commit_root; |
79154b1b CM |
193 | root->commit_root = root->node; |
194 | get_bh(root->node); | |
195 | ret = btrfs_drop_snapshot(trans, root, snap); | |
196 | BUG_ON(ret); | |
197 | ||
198 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | |
199 | &snap_key); | |
78fae27e CM |
200 | BUG_ON(ret); root->fs_info->generation = root->root_key.offset + 1; ret = btrfs_end_transaction(trans, root); BUG_ON(ret); |
201 | printk("at free, total trans %d\n", total_trans); | |
79154b1b CM |
202 | } |
203 | ||
204 | return ret; | |
205 | } | |
206 |