diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-16 08:56:18 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-16 08:56:18 -0400 |
commit | 88fd146c27da0f34c512f47e2b3776a0762ecd81 (patch) | |
tree | b9edfbb99674dcd8ad036f04664b96e92f62719a /fs/btrfs | |
parent | a8a2ee0c600a213d13170c2f4d7bd0b304bbec19 (diff) |
Btrfs: pin freed blocks from the FS tree too
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 14 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 28 |
3 files changed, 26 insertions, 19 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 68f66b320a88..13128b5ed65c 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -55,13 +55,13 @@ static int btrfs_cow_block(struct btrfs_root *root, | |||
55 | root->node = cow; | 55 | root->node = cow; |
56 | cow->count++; | 56 | cow->count++; |
57 | if (buf != root->commit_root) | 57 | if (buf != root->commit_root) |
58 | btrfs_free_extent(root, buf->blocknr, 1); | 58 | btrfs_free_extent(root, buf->blocknr, 1, 1); |
59 | btrfs_block_release(root, buf); | 59 | btrfs_block_release(root, buf); |
60 | } else { | 60 | } else { |
61 | btrfs_set_node_blockptr(&parent->node, parent_slot, | 61 | btrfs_set_node_blockptr(&parent->node, parent_slot, |
62 | cow->blocknr); | 62 | cow->blocknr); |
63 | BUG_ON(list_empty(&parent->dirty)); | 63 | BUG_ON(list_empty(&parent->dirty)); |
64 | btrfs_free_extent(root, buf->blocknr, 1); | 64 | btrfs_free_extent(root, buf->blocknr, 1, 1); |
65 | } | 65 | } |
66 | btrfs_block_release(root, buf); | 66 | btrfs_block_release(root, buf); |
67 | return 0; | 67 | return 0; |
@@ -311,7 +311,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, | |||
311 | /* once for the root ptr */ | 311 | /* once for the root ptr */ |
312 | btrfs_block_release(root, mid_buf); | 312 | btrfs_block_release(root, mid_buf); |
313 | clean_tree_block(root, mid_buf); | 313 | clean_tree_block(root, mid_buf); |
314 | return btrfs_free_extent(root, blocknr, 1); | 314 | return btrfs_free_extent(root, blocknr, 1, 1); |
315 | } | 315 | } |
316 | parent = &parent_buf->node; | 316 | parent = &parent_buf->node; |
317 | 317 | ||
@@ -352,7 +352,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, | |||
352 | wret = del_ptr(root, path, level + 1, pslot + 1); | 352 | wret = del_ptr(root, path, level + 1, pslot + 1); |
353 | if (wret) | 353 | if (wret) |
354 | ret = wret; | 354 | ret = wret; |
355 | wret = btrfs_free_extent(root, blocknr, 1); | 355 | wret = btrfs_free_extent(root, blocknr, 1, 1); |
356 | if (wret) | 356 | if (wret) |
357 | ret = wret; | 357 | ret = wret; |
358 | } else { | 358 | } else { |
@@ -388,7 +388,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, | |||
388 | wret = del_ptr(root, path, level + 1, pslot); | 388 | wret = del_ptr(root, path, level + 1, pslot); |
389 | if (wret) | 389 | if (wret) |
390 | ret = wret; | 390 | ret = wret; |
391 | wret = btrfs_free_extent(root, blocknr, 1); | 391 | wret = btrfs_free_extent(root, blocknr, 1, 1); |
392 | if (wret) | 392 | if (wret) |
393 | ret = wret; | 393 | ret = wret; |
394 | } else { | 394 | } else { |
@@ -1310,7 +1310,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path) | |||
1310 | wret = del_ptr(root, path, 1, path->slots[1]); | 1310 | wret = del_ptr(root, path, 1, path->slots[1]); |
1311 | if (wret) | 1311 | if (wret) |
1312 | ret = wret; | 1312 | ret = wret; |
1313 | wret = btrfs_free_extent(root, leaf_buf->blocknr, 1); | 1313 | wret = btrfs_free_extent(root, leaf_buf->blocknr, 1, 1); |
1314 | if (wret) | 1314 | if (wret) |
1315 | ret = wret; | 1315 | ret = wret; |
1316 | } | 1316 | } |
@@ -1348,7 +1348,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path) | |||
1348 | if (wret) | 1348 | if (wret) |
1349 | ret = wret; | 1349 | ret = wret; |
1350 | btrfs_block_release(root, leaf_buf); | 1350 | btrfs_block_release(root, leaf_buf); |
1351 | wret = btrfs_free_extent(root, blocknr, 1); | 1351 | wret = btrfs_free_extent(root, blocknr, 1, 1); |
1352 | if (wret) | 1352 | if (wret) |
1353 | ret = wret; | 1353 | ret = wret; |
1354 | } else { | 1354 | } else { |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7c66b647ea24..d15a2ed95076 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -658,7 +658,8 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) | |||
658 | 658 | ||
659 | struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root); | 659 | struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root); |
660 | int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf); | 660 | int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf); |
661 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks); | 661 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks, |
662 | int pin); | ||
662 | int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key, | 663 | int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key, |
663 | struct btrfs_path *p, int ins_len, int cow); | 664 | struct btrfs_path *p, int ins_len, int cow); |
664 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); | 665 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c81e14162ef1..4a40282b45f7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -95,6 +95,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf) | |||
95 | int btrfs_finish_extent_commit(struct btrfs_root *root) | 95 | int btrfs_finish_extent_commit(struct btrfs_root *root) |
96 | { | 96 | { |
97 | unsigned long gang[8]; | 97 | unsigned long gang[8]; |
98 | u64 first = 0; | ||
98 | int ret; | 99 | int ret; |
99 | int i; | 100 | int i; |
100 | 101 | ||
@@ -104,11 +105,13 @@ int btrfs_finish_extent_commit(struct btrfs_root *root) | |||
104 | ARRAY_SIZE(gang)); | 105 | ARRAY_SIZE(gang)); |
105 | if (!ret) | 106 | if (!ret) |
106 | break; | 107 | break; |
108 | if (!first) | ||
109 | first = gang[0]; | ||
107 | for (i = 0; i < ret; i++) { | 110 | for (i = 0; i < ret; i++) { |
108 | radix_tree_delete(&root->pinned_radix, gang[i]); | 111 | radix_tree_delete(&root->pinned_radix, gang[i]); |
109 | } | 112 | } |
110 | } | 113 | } |
111 | root->last_insert.objectid = 0; | 114 | root->last_insert.objectid = first; |
112 | root->last_insert.offset = 0; | 115 | root->last_insert.offset = 0; |
113 | return 0; | 116 | return 0; |
114 | } | 117 | } |
@@ -140,7 +143,8 @@ static int finish_current_insert(struct btrfs_root *extent_root) | |||
140 | /* | 143 | /* |
141 | * remove an extent from the root, returns 0 on success | 144 | * remove an extent from the root, returns 0 on success |
142 | */ | 145 | */ |
143 | static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | 146 | static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks, |
147 | int pin) | ||
144 | { | 148 | { |
145 | struct btrfs_path path; | 149 | struct btrfs_path path; |
146 | struct btrfs_key key; | 150 | struct btrfs_key key; |
@@ -150,6 +154,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
150 | struct btrfs_key ins; | 154 | struct btrfs_key ins; |
151 | u32 refs; | 155 | u32 refs; |
152 | 156 | ||
157 | BUG_ON(pin && num_blocks != 1); | ||
153 | key.objectid = blocknr; | 158 | key.objectid = blocknr; |
154 | key.flags = 0; | 159 | key.flags = 0; |
155 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 160 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
@@ -170,7 +175,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
170 | refs = btrfs_extent_refs(ei) - 1; | 175 | refs = btrfs_extent_refs(ei) - 1; |
171 | btrfs_set_extent_refs(ei, refs); | 176 | btrfs_set_extent_refs(ei, refs); |
172 | if (refs == 0) { | 177 | if (refs == 0) { |
173 | if (!root->ref_cows) { | 178 | if (pin) { |
174 | int err; | 179 | int err; |
175 | radix_tree_preload(GFP_KERNEL); | 180 | radix_tree_preload(GFP_KERNEL); |
176 | err = radix_tree_insert(&extent_root->pinned_radix, | 181 | err = radix_tree_insert(&extent_root->pinned_radix, |
@@ -179,8 +184,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
179 | radix_tree_preload_end(); | 184 | radix_tree_preload_end(); |
180 | } | 185 | } |
181 | ret = btrfs_del_item(extent_root, &path); | 186 | ret = btrfs_del_item(extent_root, &path); |
182 | if (root != extent_root && | 187 | if (!pin && extent_root->last_insert.objectid > blocknr) |
183 | extent_root->last_insert.objectid > blocknr) | ||
184 | extent_root->last_insert.objectid = blocknr; | 188 | extent_root->last_insert.objectid = blocknr; |
185 | if (ret) | 189 | if (ret) |
186 | BUG(); | 190 | BUG(); |
@@ -208,7 +212,8 @@ static int del_pending_extents(struct btrfs_root *extent_root) | |||
208 | if (!ret) | 212 | if (!ret) |
209 | break; | 213 | break; |
210 | for (i = 0; i < ret; i++) { | 214 | for (i = 0; i < ret; i++) { |
211 | ret = __free_extent(extent_root, gang[i]->blocknr, 1); | 215 | ret = __free_extent(extent_root, |
216 | gang[i]->blocknr, 1, 1); | ||
212 | radix_tree_tag_clear(&extent_root->cache_radix, | 217 | radix_tree_tag_clear(&extent_root->cache_radix, |
213 | gang[i]->blocknr, | 218 | gang[i]->blocknr, |
214 | CTREE_EXTENT_PENDING_DEL); | 219 | CTREE_EXTENT_PENDING_DEL); |
@@ -230,7 +235,8 @@ static int run_pending(struct btrfs_root *extent_root) | |||
230 | /* | 235 | /* |
231 | * remove an extent from the root, returns 0 on success | 236 | * remove an extent from the root, returns 0 on success |
232 | */ | 237 | */ |
233 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | 238 | int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks, |
239 | int pin) | ||
234 | { | 240 | { |
235 | struct btrfs_root *extent_root = root->extent_root; | 241 | struct btrfs_root *extent_root = root->extent_root; |
236 | struct btrfs_buffer *t; | 242 | struct btrfs_buffer *t; |
@@ -243,7 +249,7 @@ int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) | |||
243 | CTREE_EXTENT_PENDING_DEL); | 249 | CTREE_EXTENT_PENDING_DEL); |
244 | return 0; | 250 | return 0; |
245 | } | 251 | } |
246 | ret = __free_extent(root, blocknr, num_blocks); | 252 | ret = __free_extent(root, blocknr, num_blocks, pin); |
247 | pending_ret = run_pending(root->extent_root); | 253 | pending_ret = run_pending(root->extent_root); |
248 | return ret ? ret : pending_ret; | 254 | return ret ? ret : pending_ret; |
249 | } | 255 | } |
@@ -451,7 +457,7 @@ static int walk_down_tree(struct btrfs_root *root, | |||
451 | ret = lookup_block_ref(root, blocknr, &refs); | 457 | ret = lookup_block_ref(root, blocknr, &refs); |
452 | if (refs != 1 || *level == 1) { | 458 | if (refs != 1 || *level == 1) { |
453 | path->slots[*level]++; | 459 | path->slots[*level]++; |
454 | ret = btrfs_free_extent(root, blocknr, 1); | 460 | ret = btrfs_free_extent(root, blocknr, 1, 1); |
455 | BUG_ON(ret); | 461 | BUG_ON(ret); |
456 | continue; | 462 | continue; |
457 | } | 463 | } |
@@ -464,7 +470,7 @@ static int walk_down_tree(struct btrfs_root *root, | |||
464 | path->slots[*level] = 0; | 470 | path->slots[*level] = 0; |
465 | } | 471 | } |
466 | out: | 472 | out: |
467 | ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1); | 473 | ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1, 1); |
468 | btrfs_block_release(root, path->nodes[*level]); | 474 | btrfs_block_release(root, path->nodes[*level]); |
469 | path->nodes[*level] = NULL; | 475 | path->nodes[*level] = NULL; |
470 | *level += 1; | 476 | *level += 1; |
@@ -492,7 +498,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, | |||
492 | return 0; | 498 | return 0; |
493 | } else { | 499 | } else { |
494 | ret = btrfs_free_extent(root, | 500 | ret = btrfs_free_extent(root, |
495 | path->nodes[*level]->blocknr, 1); | 501 | path->nodes[*level]->blocknr, 1, 1); |
496 | btrfs_block_release(root, path->nodes[*level]); | 502 | btrfs_block_release(root, path->nodes[*level]); |
497 | path->nodes[*level] = NULL; | 503 | path->nodes[*level] = NULL; |
498 | *level = i + 1; | 504 | *level = i + 1; |