diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-25 11:35:08 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-25 11:35:08 -0400 |
commit | 78fae27ebf5bd35fb9b2e4213e486635eacfc0ad (patch) | |
tree | ca706d468053f33744cc38764854c2866c044cb7 /fs/btrfs/extent-tree.c | |
parent | d561c025ee3a0aee53a225bedce0ee35fe12f335 (diff) |
Btrfs: leak fixes, pinning fixes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 30 |
1 files changed, 21 insertions, 9 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 | } |