aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-06 20:08:01 -0500
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-06 20:08:01 -0500
commita28ec19775d62d673b034082128aca95780d3737 (patch)
tree105694ca29ed0ad6563c45a86df9a7df1abf94ff /fs/btrfs/extent-tree.c
parent02217ed299c6340a35696e0610047eb96826de2d (diff)
Btrfs: Fixup reference counting on cows
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c291
1 files changed, 204 insertions, 87 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 25d9cd169209..0723b7f3f0c3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -13,7 +13,8 @@
13 * other allocations are done. The pending tag is also used in the same 13 * other allocations are done. The pending tag is also used in the same
14 * manner for deletes. 14 * manner for deletes.
15 */ 15 */
16#define CTREE_EXTENT_PENDING 0 16#define CTREE_EXTENT_PENDING_ADD 0
17#define CTREE_EXTENT_PENDING_DEL 1
17 18
18static int inc_block_ref(struct ctree_root *root, u64 blocknr) 19static int inc_block_ref(struct ctree_root *root, u64 blocknr)
19{ 20{
@@ -27,20 +28,51 @@ static int inc_block_ref(struct ctree_root *root, u64 blocknr)
27 key.flags = 0; 28 key.flags = 0;
28 key.offset = 1; 29 key.offset = 1;
29 ret = search_slot(root->extent_root, &key, &path, 0, 1); 30 ret = search_slot(root->extent_root, &key, &path, 0, 1);
31 if (ret != 0)
32 BUG();
30 BUG_ON(ret != 0); 33 BUG_ON(ret != 0);
31 l = &path.nodes[0]->leaf; 34 l = &path.nodes[0]->leaf;
32 item = (struct extent_item *)(l->data + 35 item = (struct extent_item *)(l->data +
33 l->items[path.slots[0]].offset); 36 l->items[path.slots[0]].offset);
34 item->refs++; 37 item->refs++;
38
35 BUG_ON(list_empty(&path.nodes[0]->dirty)); 39 BUG_ON(list_empty(&path.nodes[0]->dirty));
36 release_path(root->extent_root, &path); 40 release_path(root->extent_root, &path);
37 return 0; 41 return 0;
38} 42}
39 43
44static int lookup_block_ref(struct ctree_root *root, u64 blocknr, int *refs)
45{
46 struct ctree_path path;
47 int ret;
48 struct key key;
49 struct leaf *l;
50 struct extent_item *item;
51 init_path(&path);
52 key.objectid = blocknr;
53 key.flags = 0;
54 key.offset = 1;
55 ret = search_slot(root->extent_root, &key, &path, 0, 0);
56 if (ret != 0)
57 BUG();
58 l = &path.nodes[0]->leaf;
59 item = (struct extent_item *)(l->data +
60 l->items[path.slots[0]].offset);
61 *refs = item->refs;
62 release_path(root->extent_root, &path);
63 return 0;
64}
65
40int btrfs_inc_ref(struct ctree_root *root, struct tree_buffer *buf) 66int btrfs_inc_ref(struct ctree_root *root, struct tree_buffer *buf)
41{ 67{
42 u64 blocknr; 68 u64 blocknr;
43 int i; 69 int i;
70
71 if (root == root->extent_root)
72 return 0;
73 if (is_leaf(buf->node.header.flags))
74 return 0;
75
44 for (i = 0; i < buf->node.header.nritems; i++) { 76 for (i = 0; i < buf->node.header.nritems; i++) {
45 blocknr = buf->node.blockptrs[i]; 77 blocknr = buf->node.blockptrs[i];
46 inc_block_ref(root, blocknr); 78 inc_block_ref(root, blocknr);
@@ -48,85 +80,187 @@ int btrfs_inc_ref(struct ctree_root *root, struct tree_buffer *buf)
48 return 0; 80 return 0;
49} 81}
50 82
83int btrfs_finish_extent_commit(struct ctree_root *root)
84{
85 struct ctree_root *extent_root = root->extent_root;
86 unsigned long gang[8];
87 int ret;
88 int i;
89
90 while(1) {
91 ret = radix_tree_gang_lookup(&extent_root->pinned_radix,
92 (void **)gang, 0,
93 ARRAY_SIZE(gang));
94 if (!ret)
95 break;
96 for (i = 0; i < ret; i++)
97 radix_tree_delete(&extent_root->pinned_radix, gang[i]);
98 }
99 return 0;
100}
101
51/* 102/*
52 * find all the blocks marked as pending in the radix tree and remove 103 * remove an extent from the root, returns 0 on success
53 * them from the extent map
54 */ 104 */
55static int del_pending_extents(struct ctree_root *extent_root) 105int __free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
106{
107 struct ctree_path path;
108 struct key key;
109 struct ctree_root *extent_root = root->extent_root;
110 int ret;
111 struct item *item;
112 struct extent_item *ei;
113 key.objectid = blocknr;
114 key.flags = 0;
115 key.offset = num_blocks;
116
117 init_path(&path);
118 ret = search_slot(extent_root, &key, &path, -1, 1);
119 if (ret) {
120 printf("failed to find %Lu\n", key.objectid);
121 print_tree(extent_root, extent_root->node);
122 printf("failed to find %Lu\n", key.objectid);
123 BUG();
124 }
125 item = path.nodes[0]->leaf.items + path.slots[0];
126 ei = (struct extent_item *)(path.nodes[0]->leaf.data + item->offset);
127 BUG_ON(ei->refs == 0);
128 ei->refs--;
129 if (ei->refs == 0) {
130 if (root == extent_root) {
131 int err;
132 radix_tree_preload(GFP_KERNEL);
133 err = radix_tree_insert(&extent_root->pinned_radix,
134 blocknr, (void *)blocknr);
135 BUG_ON(err);
136 radix_tree_preload_end();
137 }
138 ret = del_item(extent_root, &path);
139 if (ret)
140 BUG();
141 }
142 release_path(extent_root, &path);
143 return ret;
144}
145
146/*
147 * insert all of the pending extents reserved during the original
148 * allocation. (CTREE_EXTENT_PENDING). Returns zero if it all worked out
149 */
150static int insert_pending_extents(struct ctree_root *extent_root)
56{ 151{
57 int ret; 152 int ret;
58 struct key key; 153 struct key key;
154 struct extent_item item;
59 struct tree_buffer *gang[4]; 155 struct tree_buffer *gang[4];
60 int i; 156 int i;
61 struct ctree_path path;
62 157
158 // FIXME -ENOSPC
159 item.owner = extent_root->node->node.header.parentid;
160 item.refs = 1;
63 while(1) { 161 while(1) {
64 ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix, 162 ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix,
65 (void **)gang, 0, 163 (void **)gang, 0,
66 ARRAY_SIZE(gang), 164 ARRAY_SIZE(gang),
67 CTREE_EXTENT_PENDING); 165 CTREE_EXTENT_PENDING_ADD);
68 if (!ret) 166 if (!ret)
69 break; 167 break;
70 for (i = 0; i < ret; i++) { 168 for (i = 0; i < ret; i++) {
71 key.objectid = gang[i]->blocknr; 169 key.objectid = gang[i]->blocknr;
72 key.flags = 0; 170 key.flags = 0;
73 key.offset = 1; 171 key.offset = 1;
74 init_path(&path); 172 ret = insert_item(extent_root, &key, &item,
75 ret = search_slot(extent_root, &key, &path, -1, 1); 173 sizeof(item));
76 if (ret) { 174 if (ret) {
175 printf("%Lu already in tree\n", key.objectid);
77 print_tree(extent_root, extent_root->node); 176 print_tree(extent_root, extent_root->node);
78 printf("unable to find %Lu\n", key.objectid);
79 BUG(); 177 BUG();
80 // FIXME undo it and return sane 178 // FIXME undo it and return sane
81 return ret; 179 return ret;
82 } 180 }
83 ret = del_item(extent_root, &path); 181 radix_tree_tag_clear(&extent_root->cache_radix,
84 if (ret) { 182 gang[i]->blocknr,
85 BUG(); 183 CTREE_EXTENT_PENDING_ADD);
86 return ret; 184 tree_block_release(extent_root, gang[i]);
87 } 185 }
88 release_path(extent_root, &path); 186 }
187 return 0;
188}
189
190/*
191 * find all the blocks marked as pending in the radix tree and remove
192 * them from the extent map
193 */
194static int del_pending_extents(struct ctree_root *extent_root)
195{
196 int ret;
197 struct tree_buffer *gang[4];
198 int i;
199
200 while(1) {
201 ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix,
202 (void **)gang, 0,
203 ARRAY_SIZE(gang),
204 CTREE_EXTENT_PENDING_DEL);
205 if (!ret)
206 break;
207 for (i = 0; i < ret; i++) {
208 ret = __free_extent(extent_root, gang[i]->blocknr, 1);
89 radix_tree_tag_clear(&extent_root->cache_radix, 209 radix_tree_tag_clear(&extent_root->cache_radix,
90 gang[i]->blocknr, 210 gang[i]->blocknr,
91 CTREE_EXTENT_PENDING); 211 CTREE_EXTENT_PENDING_DEL);
92 tree_block_release(extent_root, gang[i]); 212 tree_block_release(extent_root, gang[i]);
93 } 213 }
94 } 214 }
95 return 0; 215 return 0;
96} 216}
97 217
218static int run_pending(struct ctree_root *extent_root)
219{
220 while(radix_tree_tagged(&extent_root->cache_radix,
221 CTREE_EXTENT_PENDING_DEL) ||
222 radix_tree_tagged(&extent_root->cache_radix,
223 CTREE_EXTENT_PENDING_ADD)) {
224 insert_pending_extents(extent_root);
225 del_pending_extents(extent_root);
226 }
227 return 0;
228}
229
230
98/* 231/*
99 * remove an extent from the root, returns 0 on success 232 * remove an extent from the root, returns 0 on success
100 */ 233 */
101int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks) 234int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
102{ 235{
103 struct ctree_path path;
104 struct key key; 236 struct key key;
105 struct ctree_root *extent_root = root->extent_root; 237 struct ctree_root *extent_root = root->extent_root;
106 struct tree_buffer *t; 238 struct tree_buffer *t;
107 int pending_ret; 239 int pending_ret;
108 int ret; 240 int ret;
109 key.objectid = blocknr; 241
110 key.flags = 0;
111 key.offset = num_blocks;
112 if (root == extent_root) { 242 if (root == extent_root) {
113 t = read_tree_block(root, key.objectid); 243 t = find_tree_block(root, blocknr);
114 radix_tree_tag_set(&root->cache_radix, key.objectid, 244 if (radix_tree_tag_get(&root->cache_radix, blocknr,
115 CTREE_EXTENT_PENDING); 245 CTREE_EXTENT_PENDING_ADD)) {
246 radix_tree_tag_clear(&root->cache_radix,
247 blocknr,
248 CTREE_EXTENT_PENDING_ADD);
249 /* once for us */
250 tree_block_release(root, t);
251 /* once for the pending add */
252 tree_block_release(root, t);
253 } else {
254 radix_tree_tag_set(&root->cache_radix, blocknr,
255 CTREE_EXTENT_PENDING_DEL);
256 }
116 return 0; 257 return 0;
117 } 258 }
118 init_path(&path); 259 key.objectid = blocknr;
119 ret = search_slot(extent_root, &key, &path, -1, 1); 260 key.flags = 0;
120 if (ret) { 261 key.offset = num_blocks;
121 print_tree(extent_root, extent_root->node); 262 ret = __free_extent(root, blocknr, num_blocks);
122 printf("failed to find %Lu\n", key.objectid); 263 pending_ret = run_pending(root->extent_root);
123 BUG();
124 }
125 ret = del_item(extent_root, &path);
126 if (ret)
127 BUG();
128 release_path(extent_root, &path);
129 pending_ret = del_pending_extents(root->extent_root);
130 return ret ? ret : pending_ret; 264 return ret ? ret : pending_ret;
131} 265}
132 266
@@ -203,7 +337,7 @@ check_pending:
203 */ 337 */
204 release_path(root, &path); 338 release_path(root, &path);
205 BUG_ON(ins->objectid < search_start); 339 BUG_ON(ins->objectid < search_start);
206 if (orig_root->extent_root == orig_root) { 340 if (1 || orig_root->extent_root == orig_root) {
207 BUG_ON(num_blocks != 1); 341 BUG_ON(num_blocks != 1);
208 if ((root->current_insert.objectid <= ins->objectid && 342 if ((root->current_insert.objectid <= ins->objectid &&
209 root->current_insert.objectid + 343 root->current_insert.objectid +
@@ -211,8 +345,9 @@ check_pending:
211 (root->current_insert.objectid > ins->objectid && 345 (root->current_insert.objectid > ins->objectid &&
212 root->current_insert.objectid <= ins->objectid + 346 root->current_insert.objectid <= ins->objectid +
213 ins->offset) || 347 ins->offset) ||
348 radix_tree_lookup(&root->pinned_radix, ins->objectid) ||
214 radix_tree_tag_get(&root->cache_radix, ins->objectid, 349 radix_tree_tag_get(&root->cache_radix, ins->objectid,
215 CTREE_EXTENT_PENDING)) { 350 CTREE_EXTENT_PENDING_ADD)) {
216 search_start = ins->objectid + 1; 351 search_start = ins->objectid + 1;
217 goto check_failed; 352 goto check_failed;
218 } 353 }
@@ -226,51 +361,6 @@ error:
226} 361}
227 362
228/* 363/*
229 * insert all of the pending extents reserved during the original
230 * allocation. (CTREE_EXTENT_PENDING). Returns zero if it all worked out
231 */
232static int insert_pending_extents(struct ctree_root *extent_root)
233{
234 int ret;
235 struct key key;
236 struct extent_item item;
237 struct tree_buffer *gang[4];
238 int i;
239
240 // FIXME -ENOSPC
241 item.refs = 1;
242 item.owner = extent_root->node->node.header.parentid;
243 while(1) {
244 ret = radix_tree_gang_lookup_tag(&extent_root->cache_radix,
245 (void **)gang, 0,
246 ARRAY_SIZE(gang),
247 CTREE_EXTENT_PENDING);
248 if (!ret)
249 break;
250 for (i = 0; i < ret; i++) {
251 key.objectid = gang[i]->blocknr;
252 key.flags = 0;
253 key.offset = 1;
254 ret = insert_item(extent_root, &key, &item,
255 sizeof(item));
256 if (ret) {
257 printf("%Lu already in tree\n", key.objectid);
258 print_tree(extent_root, extent_root->node);
259 BUG();
260 // FIXME undo it and return sane
261 return ret;
262 }
263 radix_tree_tag_clear(&extent_root->cache_radix,
264 gang[i]->blocknr,
265 CTREE_EXTENT_PENDING);
266 printf("%Lu is not pending\n", gang[i]->blocknr);
267 tree_block_release(extent_root, gang[i]);
268 }
269 }
270 return 0;
271}
272
273/*
274 * finds a free extent and does all the dirty work required for allocation 364 * finds a free extent and does all the dirty work required for allocation
275 * returns the key for the extent through ins, and a tree buffer for 365 * returns the key for the extent through ins, and a tree buffer for
276 * the first block of the extent through buf. 366 * the first block of the extent through buf.
@@ -296,7 +386,7 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start,
296 sizeof(extent_item)); 386 sizeof(extent_item));
297 memset(&root->extent_root->current_insert, 0, 387 memset(&root->extent_root->current_insert, 0,
298 sizeof(struct key)); 388 sizeof(struct key));
299 pending_ret = insert_pending_extents(root->extent_root); 389 pending_ret = run_pending(root->extent_root);
300 if (ret) 390 if (ret)
301 return ret; 391 return ret;
302 if (pending_ret) 392 if (pending_ret)
@@ -309,9 +399,8 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start,
309 BUG_ON(ins->offset != 1); 399 BUG_ON(ins->offset != 1);
310 *buf = find_tree_block(root, ins->objectid); 400 *buf = find_tree_block(root, ins->objectid);
311 BUG_ON(!*buf); 401 BUG_ON(!*buf);
312 printf("%Lu is pending\n", ins->objectid);
313 radix_tree_tag_set(&root->cache_radix, ins->objectid, 402 radix_tree_tag_set(&root->cache_radix, ins->objectid,
314 CTREE_EXTENT_PENDING); 403 CTREE_EXTENT_PENDING_ADD);
315 (*buf)->count++; 404 (*buf)->count++;
316 dirty_tree_block(root, *buf); 405 dirty_tree_block(root, *buf);
317 return 0; 406 return 0;
@@ -331,13 +420,41 @@ struct tree_buffer *alloc_free_block(struct ctree_root *root)
331 ret = alloc_extent(root, 1, 0, (unsigned long)-1, 420 ret = alloc_extent(root, 1, 0, (unsigned long)-1,
332 root->node->node.header.parentid, 421 root->node->node.header.parentid,
333 &ins, &buf); 422 &ins, &buf);
334
335 if (ret) { 423 if (ret) {
336 BUG(); 424 BUG();
337 return NULL; 425 return NULL;
338 } 426 }
339 if (root != root->extent_root) 427 if (root != root->extent_root)
340 BUG_ON(radix_tree_tag_get(&root->extent_root->cache_radix, 428 BUG_ON(radix_tree_tag_get(&root->extent_root->cache_radix,
341 buf->blocknr, CTREE_EXTENT_PENDING)); 429 buf->blocknr,
430 CTREE_EXTENT_PENDING_ADD));
342 return buf; 431 return buf;
343} 432}
433
434int btrfs_drop_snapshot(struct ctree_root *root, struct tree_buffer *snap)
435{
436 int ret;
437 int level;
438 int refs;
439 u64 blocknr = snap->blocknr;
440
441 level = node_level(snap->node.header.flags);
442 ret = lookup_block_ref(root, snap->blocknr, &refs);
443 BUG_ON(ret);
444 if (refs == 1 && level != 0) {
445 struct node *n = &snap->node;
446 struct tree_buffer *b;
447 int i;
448 for (i = 0; i < n->header.nritems; i++) {
449 b = read_tree_block(root, n->blockptrs[i]);
450 /* FIXME, don't recurse here */
451 ret = btrfs_drop_snapshot(root, b);
452 BUG_ON(ret);
453 tree_block_release(root, b);
454 }
455 }
456 ret = free_extent(root, blocknr, 1);
457 BUG_ON(ret);
458 return 0;
459}
460