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
;
49 buf
= malloc(sizeof(struct btrfs_buffer
));
53 buf
->blocknr
= blocknr
;
55 INIT_LIST_HEAD(&buf
->dirty
);
56 free_some_buffers(root
);
57 radix_tree_preload(GFP_KERNEL
);
58 ret
= radix_tree_insert(&root
->cache_radix
, blocknr
, buf
);
59 radix_tree_preload_end();
60 list_add_tail(&buf
->cache
, &root
->cache
);
69 struct btrfs_buffer
*find_tree_block(struct btrfs_root
*root
, u64 blocknr
)
71 struct btrfs_buffer
*buf
;
72 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
76 buf
= alloc_tree_block(root
, blocknr
);
85 struct btrfs_buffer
*read_tree_block(struct btrfs_root
*root
, u64 blocknr
)
87 loff_t offset
= blocknr
* BTRFS_BLOCKSIZE
;
88 struct btrfs_buffer
*buf
;
91 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
95 buf
= alloc_tree_block(root
, blocknr
);
98 ret
= pread(root
->fp
, &buf
->node
, BTRFS_BLOCKSIZE
, offset
);
99 if (ret
!= BTRFS_BLOCKSIZE
) {
104 if (check_tree_block(root
, buf
))
109 int dirty_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
111 if (!list_empty(&buf
->dirty
))
113 list_add_tail(&buf
->dirty
, &root
->trans
);
118 int clean_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
120 if (!list_empty(&buf
->dirty
)) {
121 list_del_init(&buf
->dirty
);
122 btrfs_block_release(root
, buf
);
127 int write_tree_block(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
129 u64 blocknr
= buf
->blocknr
;
130 loff_t offset
= blocknr
* BTRFS_BLOCKSIZE
;
133 if (buf
->blocknr
!= btrfs_header_blocknr(&buf
->node
.header
))
135 ret
= pwrite(root
->fp
, &buf
->node
, BTRFS_BLOCKSIZE
, offset
);
136 if (ret
!= BTRFS_BLOCKSIZE
)
141 static int __commit_transaction(struct btrfs_root
*root
)
143 struct btrfs_buffer
*b
;
146 while(!list_empty(&root
->trans
)) {
147 b
= list_entry(root
->trans
.next
, struct btrfs_buffer
, dirty
);
148 list_del_init(&b
->dirty
);
149 wret
= write_tree_block(root
, b
);
152 btrfs_block_release(root
, b
);
157 int btrfs_commit_transaction(struct btrfs_root
*root
,
158 struct btrfs_super_block
*s
)
162 ret
= __commit_transaction(root
);
163 if (!ret
&& root
!= root
->extent_root
)
164 ret
= __commit_transaction(root
->extent_root
);
166 if (root
->commit_root
!= root
->node
) {
167 struct btrfs_buffer
*snap
= root
->commit_root
;
168 root
->commit_root
= root
->node
;
170 ret
= btrfs_drop_snapshot(root
, snap
);
172 // btrfs_block_release(root, snap);
174 write_ctree_super(root
, s
);
175 btrfs_finish_extent_commit(root
);
179 static int __setup_root(struct btrfs_root
*root
, struct btrfs_root
*extent_root
,
180 struct btrfs_root_info
*info
, int fp
)
182 INIT_LIST_HEAD(&root
->trans
);
183 INIT_LIST_HEAD(&root
->cache
);
184 root
->cache_size
= 0;
187 root
->extent_root
= extent_root
;
188 root
->commit_root
= NULL
;
189 root
->node
= read_tree_block(root
, info
->tree_root
);
190 memset(&root
->current_insert
, 0, sizeof(root
->current_insert
));
191 memset(&root
->last_insert
, 0, sizeof(root
->last_insert
));
195 struct btrfs_root
*open_ctree(char *filename
, struct btrfs_super_block
*super
)
197 struct btrfs_root
*root
= malloc(sizeof(struct btrfs_root
));
198 struct btrfs_root
*extent_root
= malloc(sizeof(struct btrfs_root
));
202 fp
= open(filename
, O_CREAT
| O_RDWR
, 0600);
207 INIT_RADIX_TREE(&root
->cache_radix
, GFP_KERNEL
);
208 INIT_RADIX_TREE(&root
->pinned_radix
, GFP_KERNEL
);
209 INIT_RADIX_TREE(&extent_root
->pinned_radix
, GFP_KERNEL
);
210 INIT_RADIX_TREE(&extent_root
->cache_radix
, GFP_KERNEL
);
211 ret
= pread(fp
, super
, sizeof(struct btrfs_super_block
),
212 BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE
));
213 if (ret
== 0 || super
->root_info
.tree_root
== 0) {
214 printf("making new FS!\n");
218 ret
= pread(fp
, super
, sizeof(struct btrfs_super_block
),
219 BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE
));
220 if (ret
!= sizeof(struct btrfs_super_block
))
224 __setup_root(root
, extent_root
, &super
->root_info
, fp
);
225 __setup_root(extent_root
, extent_root
, &super
->extent_info
, fp
);
226 root
->commit_root
= root
->node
;
231 static int __update_root(struct btrfs_root
*root
, struct btrfs_root_info
*info
)
233 info
->tree_root
= root
->node
->blocknr
;
237 int write_ctree_super(struct btrfs_root
*root
, struct btrfs_super_block
*s
)
240 __update_root(root
, &s
->root_info
);
241 __update_root(root
->extent_root
, &s
->extent_info
);
242 ret
= pwrite(root
->fp
, s
, sizeof(*s
),
243 BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE
));
244 if (ret
!= sizeof(*s
)) {
245 fprintf(stderr
, "failed to write new super block err %d\n", ret
);
251 static int drop_cache(struct btrfs_root
*root
)
253 while(!list_empty(&root
->cache
)) {
254 struct btrfs_buffer
*b
= list_entry(root
->cache
.next
,
255 struct btrfs_buffer
, cache
);
256 list_del_init(&b
->cache
);
257 btrfs_block_release(root
, b
);
261 int close_ctree(struct btrfs_root
*root
, struct btrfs_super_block
*s
)
263 btrfs_commit_transaction(root
, s
);
264 __commit_transaction(root
->extent_root
);
265 write_ctree_super(root
, s
);
266 drop_cache(root
->extent_root
);
268 BUG_ON(!list_empty(&root
->trans
));
269 BUG_ON(!list_empty(&root
->extent_root
->trans
));
273 btrfs_block_release(root
, root
->node
);
274 if (root
->extent_root
->node
)
275 btrfs_block_release(root
->extent_root
, root
->extent_root
->node
);
276 btrfs_block_release(root
, root
->commit_root
);
278 printf("on close %d blocks are allocated\n", allocated_blocks
);
282 void btrfs_block_release(struct btrfs_root
*root
, struct btrfs_buffer
*buf
)
287 if (buf
->count
== 0) {
288 BUG_ON(!list_empty(&buf
->cache
));
289 BUG_ON(!list_empty(&buf
->dirty
));
290 if (!radix_tree_lookup(&root
->cache_radix
, buf
->blocknr
))
292 radix_tree_delete(&root
->cache_radix
, buf
->blocknr
);
293 memset(buf
, 0, sizeof(*buf
));
295 BUG_ON(allocated_blocks
== 0);
297 BUG_ON(root
->cache_size
== 0);
This page took 0.038559 seconds and 6 git commands to generate.