]>
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 | ||
7 | ||
8 | static void put_transaction(struct btrfs_transaction *transaction) | |
9 | { | |
10 | transaction->use_count--; | |
11 | if (transaction->use_count == 0) | |
12 | kfree(transaction); | |
13 | } | |
14 | ||
15 | static 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 | ||
35 | struct 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 | ||
53 | int 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 | ||
70 | int 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 | ||
77 | int 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 | ||
107 | static 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 | ||
125 | int 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 |