1 #define _XOPEN_SOURCE 500
8 #include "kerncompat.h"
9 #include "radix-tree.h"
13 static int allocated_blocks
= 0;
14 int cache_max
= 10000;
16 static int check_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
18 if (buf
->blocknr
!= btrfs_header_blocknr(&buf
->node
.header
))
20 if (root
->node
&& btrfs_header_parentid(&buf
->node
.header
) !=
21 btrfs_header_parentid(&root
->node
->node
.header
))
26 static int free_some_buffers(struct btrfs_root
*root
)
28 struct list_head
*node
, *next
;
29 struct btrfs_buffer
*b
;
30 if (root
->cache_size
< cache_max
)
32 list_for_each_safe(node
, next
, &root
->cache
) {
33 b
= list_entry(node
, struct btrfs_buffer
, cache
);
35 BUG_ON(!list_empty(&b
->dirty
));
36 list_del_init(&b
->cache
);
37 btrfs_block_release(root
, b
);
38 if (root
->cache_size
< cache_max
)
45 struct btrfs_buffer
*alloc_tree_block(struct btrfs_root
*root
, u64 blocknr
)
47 struct btrfs_buffer
*buf
;
50 buf
= malloc(sizeof(struct btrfs_buffer
) + root
->blocksize
);
54 buf
->blocknr
= blocknr
;
56 INIT_LIST_HEAD(&buf
->dirty
);
57 free_some_buffers(root
);
58 radix_tree_preload(GFP_KERNEL
);
59 ret
= radix_tree_insert(&root
->cache_radix
, blocknr
, buf
);
60 radix_tree_preload_end();
61 list_add_tail(&buf
->cache
, &root
->cache
);
70 struct btrfs_buffer
*find_tree_block(struct btrfs_root
*root
, u64 blocknr
)
72 struct btrfs_buffer
*buf
;
73 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
77 buf
= alloc_tree_block(root
, blocknr
);
86 struct btrfs_buffer
*read_tree_block(struct btrfs_root
*root
, u64 blocknr
)
88 loff_t offset
= blocknr
* root
->blocksize
;
89 struct btrfs_buffer
*buf
;
92 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
96 buf
= alloc_tree_block(root
, blocknr
);
99 ret
= pread(root
->fp
, &buf
->node
, root
->blocksize
, offset
);
100 if (ret
!= root
->blocksize
) {
105 if (check_tree_block(root
, buf
))
110 int dirty_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
112 if (!list_empty(&buf
->dirty
))
114 list_add_tail(&buf
->dirty
, &root
->trans
);
119 int clean_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
121 if (!list_empty(&buf
->dirty
)) {
122 list_del_init(&buf
->dirty
);
123 btrfs_block_release(root
, buf
);
128 int write_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
130 u64 blocknr
= buf
->blocknr
;
131 loff_t offset
= blocknr
* root
->blocksize
;
134 if (buf
->blocknr
!= btrfs_header_blocknr(&buf
->node
.header
))
136 ret
= pwrite(root
->fp
, &buf
->node
, root
->blocksize
, offset
);
137 if (ret
!= root
->blocksize
)
142 static int __commit_transaction(struct btrfs_root
*root
)
144 struct btrfs_buffer
*b
;
147 while(!list_empty(&root
->trans
)) {
148 b
= list_entry(root
->trans
.next
, struct btrfs_buffer
, dirty
);
149 list_del_init(&b
->dirty
);
150 wret
= write_tree_block(root
, b
);
153 btrfs_block_release(root
, b
);
158 static int commit_extent_and_tree_roots(struct btrfs_root
*tree_root
,
159 struct btrfs_root
*extent_root
)
162 u64 old_extent_block
;
165 old_extent_block
= btrfs_root_blocknr(&extent_root
->root_item
);
166 if (old_extent_block
== extent_root
->node
->blocknr
)
168 btrfs_set_root_blocknr(&extent_root
->root_item
,
169 extent_root
->node
->blocknr
);
170 ret
= btrfs_update_root(tree_root
,
171 &extent_root
->root_key
,
172 &extent_root
->root_item
);
175 __commit_transaction(extent_root
);
176 __commit_transaction(tree_root
);
180 int btrfs_commit_transaction(struct btrfs_root
*root
,
181 struct btrfs_super_block
*s
)
184 struct btrfs_buffer
*snap
= root
->commit_root
;
185 struct btrfs_key snap_key
;
187 ret
= __commit_transaction(root
);
190 if (root
->commit_root
== root
->node
)
193 memcpy(&snap_key
, &root
->root_key
, sizeof(snap_key
));
194 root
->root_key
.offset
++;
196 btrfs_set_root_blocknr(&root
->root_item
, root
->node
->blocknr
);
197 ret
= btrfs_insert_root(root
->tree_root
, &root
->root_key
,
201 ret
= commit_extent_and_tree_roots(root
->tree_root
, root
->extent_root
);
204 write_ctree_super(root
, s
);
205 btrfs_finish_extent_commit(root
->extent_root
);
206 btrfs_finish_extent_commit(root
->tree_root
);
208 root
->commit_root
= root
->node
;
210 ret
= btrfs_drop_snapshot(root
, snap
);
213 ret
= btrfs_del_root(root
->tree_root
, &snap_key
);
219 static int __setup_root(struct btrfs_super_block
*super
,
220 struct btrfs_root
*root
, u64 objectid
, int fp
)
222 INIT_LIST_HEAD(&root
->trans
);
223 INIT_LIST_HEAD(&root
->cache
);
224 root
->cache_size
= 0;
227 root
->commit_root
= NULL
;
228 root
->blocksize
= btrfs_super_blocksize(super
);
230 memset(&root
->current_insert
, 0, sizeof(root
->current_insert
));
231 memset(&root
->last_insert
, 0, sizeof(root
->last_insert
));
232 memset(&root
->root_key
, 0, sizeof(root
->root_key
));
233 memset(&root
->root_item
, 0, sizeof(root
->root_item
));
237 static int find_and_setup_root(struct btrfs_super_block
*super
,
238 struct btrfs_root
*tree_root
, u64 objectid
,
239 struct btrfs_root
*root
, int fp
)
243 __setup_root(super
, root
, objectid
, fp
);
244 ret
= btrfs_find_last_root(tree_root
, objectid
,
245 &root
->root_item
, &root
->root_key
);
248 root
->node
= read_tree_block(root
,
249 btrfs_root_blocknr(&root
->root_item
));
254 struct btrfs_root
*open_ctree(char *filename
, struct btrfs_super_block
*super
)
256 struct btrfs_root
*root
= malloc(sizeof(struct btrfs_root
));
257 struct btrfs_root
*extent_root
= malloc(sizeof(struct btrfs_root
));
258 struct btrfs_root
*tree_root
= malloc(sizeof(struct btrfs_root
));
262 root
->extent_root
= extent_root
;
263 root
->tree_root
= tree_root
;
265 extent_root
->extent_root
= extent_root
;
266 extent_root
->tree_root
= tree_root
;
268 tree_root
->extent_root
= extent_root
;
269 tree_root
->tree_root
= tree_root
;
271 fp
= open(filename
, O_CREAT
| O_RDWR
, 0600);
276 INIT_RADIX_TREE(&root
->cache_radix
, GFP_KERNEL
);
277 INIT_RADIX_TREE(&root
->pinned_radix
, GFP_KERNEL
);
278 INIT_RADIX_TREE(&extent_root
->pinned_radix
, GFP_KERNEL
);
279 INIT_RADIX_TREE(&extent_root
->cache_radix
, GFP_KERNEL
);
280 INIT_RADIX_TREE(&tree_root
->pinned_radix
, GFP_KERNEL
);
281 INIT_RADIX_TREE(&tree_root
->cache_radix
, GFP_KERNEL
);
283 ret
= pread(fp
, super
, sizeof(struct btrfs_super_block
),
284 BTRFS_SUPER_INFO_OFFSET
);
285 if (ret
== 0 || btrfs_super_root(super
) == 0) {
286 printf("making new FS!\n");
287 ret
= mkfs(fp
, 0, 1024);
290 ret
= pread(fp
, super
, sizeof(struct btrfs_super_block
),
291 BTRFS_SUPER_INFO_OFFSET
);
292 if (ret
!= sizeof(struct btrfs_super_block
))
297 __setup_root(super
, tree_root
, BTRFS_ROOT_TREE_OBJECTID
, fp
);
298 tree_root
->node
= read_tree_block(tree_root
, btrfs_super_root(super
));
299 BUG_ON(!tree_root
->node
);
301 ret
= find_and_setup_root(super
, tree_root
, BTRFS_EXTENT_TREE_OBJECTID
,
305 ret
= find_and_setup_root(super
, tree_root
, BTRFS_FS_TREE_OBJECTID
,
309 root
->commit_root
= root
->node
;
315 int write_ctree_super(struct btrfs_root
*root
, struct btrfs_super_block
*s
)
318 btrfs_set_super_root(s
, root
->tree_root
->node
->blocknr
);
319 ret
= pwrite(root
->fp
, s
, sizeof(*s
),
320 BTRFS_SUPER_INFO_OFFSET
);
321 if (ret
!= sizeof(*s
)) {
322 fprintf(stderr
, "failed to write new super block err %d\n", ret
);
328 static int drop_cache(struct btrfs_root
*root
)
330 while(!list_empty(&root
->cache
)) {
331 struct btrfs_buffer
*b
= list_entry(root
->cache
.next
,
332 struct btrfs_buffer
, cache
);
333 list_del_init(&b
->cache
);
334 btrfs_block_release(root
, b
);
338 int close_ctree(struct btrfs_root
*root
, struct btrfs_super_block
*s
)
341 btrfs_commit_transaction(root
, s
);
342 ret
= commit_extent_and_tree_roots(root
->tree_root
, root
->extent_root
);
344 write_ctree_super(root
, s
);
345 drop_cache(root
->extent_root
);
346 drop_cache(root
->tree_root
);
348 BUG_ON(!list_empty(&root
->trans
));
349 BUG_ON(!list_empty(&root
->extent_root
->trans
));
350 BUG_ON(!list_empty(&root
->tree_root
->trans
));
354 btrfs_block_release(root
, root
->node
);
355 if (root
->extent_root
->node
)
356 btrfs_block_release(root
->extent_root
, root
->extent_root
->node
);
357 if (root
->tree_root
->node
)
358 btrfs_block_release(root
->tree_root
, root
->tree_root
->node
);
359 btrfs_block_release(root
, root
->commit_root
);
361 printf("on close %d blocks are allocated\n", allocated_blocks
);
365 void btrfs_block_release(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
370 if (buf
->count
== 0) {
371 BUG_ON(!list_empty(&buf
->cache
));
372 BUG_ON(!list_empty(&buf
->dirty
));
373 if (!radix_tree_lookup(&root
->cache_radix
, buf
->blocknr
))
375 radix_tree_delete(&root
->cache_radix
, buf
->blocknr
);
376 memset(buf
, 0, sizeof(*buf
));
378 BUG_ON(allocated_blocks
== 0);
380 BUG_ON(root
->cache_size
== 0);