diff options
-rw-r--r-- | fs/btrfs/extent-tree.c | 30 | ||||
-rw-r--r-- | fs/btrfs/super.c | 1 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 32 |
3 files changed, 40 insertions, 23 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9583a9ae8b79..369b960fce45 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -165,13 +165,23 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) | |||
165 | { | 165 | { |
166 | int err; | 166 | int err; |
167 | struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr); | 167 | struct buffer_head *bh = sb_getblk(root->fs_info->sb, blocknr); |
168 | struct btrfs_header *header; | ||
168 | BUG_ON(!bh); | 169 | BUG_ON(!bh); |
170 | |||
171 | header = btrfs_buffer_header(bh); | ||
172 | if (btrfs_header_generation(header) == | ||
173 | root->fs_info->running_transaction->transid) { | ||
174 | return 0; | ||
175 | } | ||
176 | |||
169 | err = radix_tree_insert(&root->fs_info->pinned_radix, | 177 | err = radix_tree_insert(&root->fs_info->pinned_radix, |
170 | blocknr, bh); | 178 | blocknr, bh); |
171 | if (err && err != -EEXIST) { | 179 | if (err && err != -EEXIST) { |
172 | BUG(); | 180 | BUG(); |
173 | return err; | 181 | return err; |
174 | } | 182 | } |
183 | if (err == -EEXIST) | ||
184 | brelse(bh); | ||
175 | radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr, | 185 | radix_tree_tag_set(&root->fs_info->pinned_radix, blocknr, |
176 | tag); | 186 | tag); |
177 | return 0; | 187 | return 0; |
@@ -181,7 +191,7 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int tag) | |||
181 | * remove an extent from the root, returns 0 on success | 191 | * remove an extent from the root, returns 0 on success |
182 | */ | 192 | */ |
183 | static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 193 | static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
184 | *root, u64 blocknr, u64 num_blocks) | 194 | *root, u64 blocknr, u64 num_blocks, int pin) |
185 | { | 195 | { |
186 | struct btrfs_path path; | 196 | struct btrfs_path path; |
187 | struct btrfs_key key; | 197 | struct btrfs_key key; |
@@ -213,12 +223,18 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
213 | btrfs_set_extent_refs(ei, refs); | 223 | btrfs_set_extent_refs(ei, refs); |
214 | if (refs == 0) { | 224 | if (refs == 0) { |
215 | u64 super_blocks_used; | 225 | u64 super_blocks_used; |
226 | |||
227 | if (pin) { | ||
228 | ret = pin_down_block(root, blocknr, | ||
229 | CTREE_EXTENT_PINNED); | ||
230 | BUG_ON(ret); | ||
231 | } | ||
232 | |||
216 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); | 233 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); |
217 | btrfs_set_super_blocks_used(info->disk_super, | 234 | btrfs_set_super_blocks_used(info->disk_super, |
218 | super_blocks_used - num_blocks); | 235 | super_blocks_used - num_blocks); |
219 | ret = btrfs_del_item(trans, extent_root, &path); | 236 | ret = btrfs_del_item(trans, extent_root, &path); |
220 | if (extent_root->fs_info->last_insert.objectid > | 237 | if (extent_root->fs_info->last_insert.objectid > blocknr) |
221 | blocknr) | ||
222 | extent_root->fs_info->last_insert.objectid = blocknr; | 238 | extent_root->fs_info->last_insert.objectid = blocknr; |
223 | if (ret) | 239 | if (ret) |
224 | BUG(); | 240 | BUG(); |
@@ -257,7 +273,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct | |||
257 | radix_tree_tag_clear(radix, gang[i]->b_blocknr, | 273 | radix_tree_tag_clear(radix, gang[i]->b_blocknr, |
258 | CTREE_EXTENT_PENDING_DEL); | 274 | CTREE_EXTENT_PENDING_DEL); |
259 | wret = __free_extent(trans, extent_root, | 275 | wret = __free_extent(trans, extent_root, |
260 | gang[i]->b_blocknr, 1); | 276 | gang[i]->b_blocknr, 1, 0); |
261 | if (wret) | 277 | if (wret) |
262 | err = wret; | 278 | err = wret; |
263 | } | 279 | } |
@@ -281,11 +297,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
281 | pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL); | 297 | pin_down_block(root, blocknr, CTREE_EXTENT_PENDING_DEL); |
282 | return 0; | 298 | return 0; |
283 | } | 299 | } |
284 | if (pin) { | 300 | ret = __free_extent(trans, root, blocknr, num_blocks, pin); |
285 | ret = pin_down_block(root, blocknr, CTREE_EXTENT_PINNED); | ||
286 | BUG_ON(ret); | ||
287 | } | ||
288 | ret = __free_extent(trans, root, blocknr, num_blocks); | ||
289 | pending_ret = del_pending_extents(trans, root->fs_info->extent_root); | 301 | pending_ret = del_pending_extents(trans, root->fs_info->extent_root); |
290 | return ret ? ret : pending_ret; | 302 | return ret ? ret : pending_ret; |
291 | } | 303 | } |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 0ca1080e0198..094a66c267b4 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -146,6 +146,7 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
146 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); | 146 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); |
147 | if (ret) { | 147 | if (ret) { |
148 | make_bad_inode(inode); | 148 | make_bad_inode(inode); |
149 | btrfs_release_path(root, &path); | ||
149 | return; | 150 | return; |
150 | } | 151 | } |
151 | inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), | 152 | inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4903b47c9780..46a596e345f0 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -4,12 +4,15 @@ | |||
4 | #include "disk-io.h" | 4 | #include "disk-io.h" |
5 | #include "transaction.h" | 5 | #include "transaction.h" |
6 | 6 | ||
7 | 7 | static int total_trans = 0; | |
8 | static void put_transaction(struct btrfs_transaction *transaction) | 8 | static void put_transaction(struct btrfs_transaction *transaction) |
9 | { | 9 | { |
10 | transaction->use_count--; | 10 | transaction->use_count--; |
11 | if (transaction->use_count == 0) | 11 | if (transaction->use_count == 0) { |
12 | WARN_ON(total_trans == 0); | ||
13 | total_trans--; | ||
12 | kfree(transaction); | 14 | kfree(transaction); |
15 | } | ||
13 | } | 16 | } |
14 | 17 | ||
15 | static int join_transaction(struct btrfs_root *root) | 18 | static int join_transaction(struct btrfs_root *root) |
@@ -18,6 +21,7 @@ static int join_transaction(struct btrfs_root *root) | |||
18 | cur_trans = root->fs_info->running_transaction; | 21 | cur_trans = root->fs_info->running_transaction; |
19 | if (!cur_trans) { | 22 | if (!cur_trans) { |
20 | cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS); | 23 | cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS); |
24 | total_trans++; | ||
21 | BUG_ON(!cur_trans); | 25 | BUG_ON(!cur_trans); |
22 | root->fs_info->running_transaction = cur_trans; | 26 | root->fs_info->running_transaction = cur_trans; |
23 | cur_trans->num_writers = 0; | 27 | cur_trans->num_writers = 0; |
@@ -108,7 +112,6 @@ static int wait_for_commit(struct btrfs_root *root, | |||
108 | struct btrfs_transaction *commit) | 112 | struct btrfs_transaction *commit) |
109 | { | 113 | { |
110 | DEFINE_WAIT(wait); | 114 | DEFINE_WAIT(wait); |
111 | commit->use_count++; | ||
112 | while(!commit->commit_done) { | 115 | while(!commit->commit_done) { |
113 | prepare_to_wait(&commit->commit_wait, &wait, | 116 | prepare_to_wait(&commit->commit_wait, &wait, |
114 | TASK_UNINTERRUPTIBLE); | 117 | TASK_UNINTERRUPTIBLE); |
@@ -126,7 +129,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
126 | struct btrfs_root *root) | 129 | struct btrfs_root *root) |
127 | { | 130 | { |
128 | int ret = 0; | 131 | int ret = 0; |
129 | struct buffer_head *snap = root->commit_root; | 132 | struct buffer_head *snap; |
130 | struct btrfs_key snap_key; | 133 | struct btrfs_key snap_key; |
131 | struct btrfs_transaction *cur_trans; | 134 | struct btrfs_transaction *cur_trans; |
132 | DEFINE_WAIT(wait); | 135 | DEFINE_WAIT(wait); |
@@ -153,15 +156,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
153 | } | 156 | } |
154 | finish_wait(&trans->transaction->writer_wait, &wait); | 157 | finish_wait(&trans->transaction->writer_wait, &wait); |
155 | 158 | ||
156 | cur_trans = root->fs_info->running_transaction; | ||
157 | root->fs_info->running_transaction = NULL; | ||
158 | |||
159 | if (root->node != root->commit_root) { | 159 | if (root->node != root->commit_root) { |
160 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | 160 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); |
161 | root->root_key.offset++; | 161 | root->root_key.offset++; |
162 | } | 162 | } |
163 | 163 | ||
164 | mutex_unlock(&root->fs_info->trans_mutex); | ||
165 | 164 | ||
166 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { | 165 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { |
167 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | 166 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); |
@@ -173,17 +172,24 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
173 | ret = btrfs_commit_tree_roots(trans, root); | 172 | ret = btrfs_commit_tree_roots(trans, root); |
174 | BUG_ON(ret); | 173 | BUG_ON(ret); |
175 | 174 | ||
175 | cur_trans = root->fs_info->running_transaction; | ||
176 | root->fs_info->running_transaction = NULL; | ||
177 | mutex_unlock(&root->fs_info->trans_mutex); | ||
178 | |||
176 | ret = btrfs_write_and_wait_transaction(trans, root); | 179 | ret = btrfs_write_and_wait_transaction(trans, root); |
177 | BUG_ON(ret); | 180 | BUG_ON(ret); |
178 | 181 | ||
179 | write_ctree_super(trans, root); | 182 | write_ctree_super(trans, root); |
180 | btrfs_finish_extent_commit(trans, root->fs_info->extent_root); | 183 | btrfs_finish_extent_commit(trans, root); |
181 | btrfs_finish_extent_commit(trans, root->fs_info->tree_root); | 184 | mutex_lock(&root->fs_info->trans_mutex); |
185 | put_transaction(cur_trans); | ||
182 | put_transaction(cur_trans); | 186 | put_transaction(cur_trans); |
187 | mutex_unlock(&root->fs_info->trans_mutex); | ||
183 | kfree(trans); | 188 | kfree(trans); |
184 | 189 | ||
185 | if (root->node != root->commit_root) { | 190 | if (root->node != root->commit_root) { |
186 | trans = btrfs_start_transaction(root, 1); | 191 | trans = btrfs_start_transaction(root, 1); |
192 | snap = root->commit_root; | ||
187 | root->commit_root = root->node; | 193 | root->commit_root = root->node; |
188 | get_bh(root->node); | 194 | get_bh(root->node); |
189 | ret = btrfs_drop_snapshot(trans, root, snap); | 195 | ret = btrfs_drop_snapshot(trans, root, snap); |
@@ -191,10 +197,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
191 | 197 | ||
192 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | 198 | ret = btrfs_del_root(trans, root->fs_info->tree_root, |
193 | &snap_key); | 199 | &snap_key); |
194 | BUG_ON(ret); | 200 | BUG_ON(ret); root->fs_info->generation = root->root_key.offset + 1; ret = btrfs_end_transaction(trans, root); BUG_ON(ret); |
195 | root->fs_info->generation = root->root_key.offset + 1; | 201 | printk("at free, total trans %d\n", total_trans); |
196 | ret = btrfs_end_transaction(trans, root); | ||
197 | BUG_ON(ret); | ||
198 | } | 202 | } |
199 | 203 | ||
200 | return ret; | 204 | return ret; |