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 ctree_root
*root
, struct tree_buffer
*buf
)
18 if (buf
->blocknr
!= buf
->node
.header
.blocknr
)
20 if (root
->node
&& buf
->node
.header
.parentid
!= root
->node
->node
.header
.parentid
)
25 static int free_some_buffers(struct ctree_root
*root
)
27 struct list_head
*node
, *next
;
28 struct tree_buffer
*b
;
29 if (root
->cache_size
< cache_max
)
31 list_for_each_safe(node
, next
, &root
->cache
) {
32 b
= list_entry(node
, struct tree_buffer
, cache
);
34 BUG_ON(!list_empty(&b
->dirty
));
35 list_del_init(&b
->cache
);
36 tree_block_release(root
, b
);
37 if (root
->cache_size
< cache_max
)
44 struct tree_buffer
*alloc_tree_block(struct ctree_root
*root
, u64 blocknr
)
46 struct tree_buffer
*buf
;
48 buf
= malloc(sizeof(struct tree_buffer
));
52 buf
->blocknr
= blocknr
;
54 INIT_LIST_HEAD(&buf
->dirty
);
55 free_some_buffers(root
);
56 radix_tree_preload(GFP_KERNEL
);
57 ret
= radix_tree_insert(&root
->cache_radix
, blocknr
, buf
);
58 radix_tree_preload_end();
59 list_add_tail(&buf
->cache
, &root
->cache
);
68 struct tree_buffer
*find_tree_block(struct ctree_root
*root
, u64 blocknr
)
70 struct tree_buffer
*buf
;
71 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
75 buf
= alloc_tree_block(root
, blocknr
);
84 struct tree_buffer
*read_tree_block(struct ctree_root
*root
, u64 blocknr
)
86 loff_t offset
= blocknr
* CTREE_BLOCKSIZE
;
87 struct tree_buffer
*buf
;
90 buf
= radix_tree_lookup(&root
->cache_radix
, blocknr
);
94 buf
= alloc_tree_block(root
, blocknr
);
97 ret
= pread(root
->fp
, &buf
->node
, CTREE_BLOCKSIZE
, offset
);
98 if (ret
!= CTREE_BLOCKSIZE
) {
103 if (check_tree_block(root
, buf
))
108 int dirty_tree_block(struct ctree_root
*root
, struct tree_buffer
*buf
)
110 if (!list_empty(&buf
->dirty
))
112 list_add_tail(&buf
->dirty
, &root
->trans
);
117 int clean_tree_block(struct ctree_root
*root
, struct tree_buffer
*buf
)
119 if (!list_empty(&buf
->dirty
)) {
120 list_del_init(&buf
->dirty
);
121 tree_block_release(root
, buf
);
126 int write_tree_block(struct ctree_root
*root
, struct tree_buffer
*buf
)
128 u64 blocknr
= buf
->blocknr
;
129 loff_t offset
= blocknr
* CTREE_BLOCKSIZE
;
132 if (buf
->blocknr
!= buf
->node
.header
.blocknr
)
134 ret
= pwrite(root
->fp
, &buf
->node
, CTREE_BLOCKSIZE
, offset
);
135 if (ret
!= CTREE_BLOCKSIZE
)
140 static int __commit_transaction(struct ctree_root
*root
)
142 struct tree_buffer
*b
;
145 while(!list_empty(&root
->trans
)) {
146 b
= list_entry(root
->trans
.next
, struct tree_buffer
, dirty
);
147 list_del_init(&b
->dirty
);
148 wret
= write_tree_block(root
, b
);
151 tree_block_release(root
, b
);
156 int commit_transaction(struct ctree_root
*root
, struct ctree_super_block
*s
)
160 ret
= __commit_transaction(root
);
161 if (!ret
&& root
!= root
->extent_root
)
162 ret
= __commit_transaction(root
->extent_root
);
164 if (root
->commit_root
!= root
->node
) {
165 struct tree_buffer
*snap
= root
->commit_root
;
166 root
->commit_root
= root
->node
;
168 ret
= btrfs_drop_snapshot(root
, snap
);
170 tree_block_release(root
, snap
);
172 write_ctree_super(root
, s
);
173 btrfs_finish_extent_commit(root
);
177 static int __setup_root(struct ctree_root
*root
, struct ctree_root
*extent_root
,
178 struct ctree_root_info
*info
, int fp
)
180 INIT_LIST_HEAD(&root
->trans
);
181 INIT_LIST_HEAD(&root
->cache
);
182 root
->cache_size
= 0;
185 root
->extent_root
= extent_root
;
186 root
->commit_root
= NULL
;
187 root
->node
= read_tree_block(root
, info
->tree_root
);
188 memset(&root
->current_insert
, 0, sizeof(root
->current_insert
));
192 struct ctree_root
*open_ctree(char *filename
, struct ctree_super_block
*super
)
194 struct ctree_root
*root
= malloc(sizeof(struct ctree_root
));
195 struct ctree_root
*extent_root
= malloc(sizeof(struct ctree_root
));
199 fp
= open(filename
, O_CREAT
| O_RDWR
, 0600);
204 INIT_RADIX_TREE(&root
->cache_radix
, GFP_KERNEL
);
205 INIT_RADIX_TREE(&root
->pinned_radix
, GFP_KERNEL
);
206 INIT_RADIX_TREE(&extent_root
->pinned_radix
, GFP_KERNEL
);
207 INIT_RADIX_TREE(&extent_root
->cache_radix
, GFP_KERNEL
);
208 ret
= pread(fp
, super
, sizeof(struct ctree_super_block
),
209 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE
));
210 if (ret
== 0 || super
->root_info
.tree_root
== 0) {
211 printf("making new FS!\n");
215 ret
= pread(fp
, super
, sizeof(struct ctree_super_block
),
216 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE
));
217 if (ret
!= sizeof(struct ctree_super_block
))
221 __setup_root(root
, extent_root
, &super
->root_info
, fp
);
222 __setup_root(extent_root
, extent_root
, &super
->extent_info
, fp
);
223 root
->commit_root
= root
->node
;
228 static int __update_root(struct ctree_root
*root
, struct ctree_root_info
*info
)
230 info
->tree_root
= root
->node
->blocknr
;
234 int write_ctree_super(struct ctree_root
*root
, struct ctree_super_block
*s
)
237 __update_root(root
, &s
->root_info
);
238 __update_root(root
->extent_root
, &s
->extent_info
);
239 ret
= pwrite(root
->fp
, s
, sizeof(*s
), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE
));
240 if (ret
!= sizeof(*s
)) {
241 fprintf(stderr
, "failed to write new super block err %d\n", ret
);
247 static int drop_cache(struct ctree_root
*root
)
249 while(!list_empty(&root
->cache
)) {
250 struct tree_buffer
*b
= list_entry(root
->cache
.next
,
251 struct tree_buffer
, cache
);
252 list_del_init(&b
->cache
);
253 tree_block_release(root
, b
);
257 int close_ctree(struct ctree_root
*root
, struct ctree_super_block
*s
)
259 commit_transaction(root
, s
);
260 __commit_transaction(root
->extent_root
);
261 write_ctree_super(root
, s
);
262 drop_cache(root
->extent_root
);
264 BUG_ON(!list_empty(&root
->trans
));
265 BUG_ON(!list_empty(&root
->extent_root
->trans
));
269 tree_block_release(root
, root
->node
);
270 if (root
->extent_root
->node
)
271 tree_block_release(root
->extent_root
, root
->extent_root
->node
);
272 tree_block_release(root
, root
->commit_root
);
274 printf("on close %d blocks are allocated\n", allocated_blocks
);
278 void tree_block_release(struct ctree_root
*root
, struct tree_buffer
*buf
)
283 if (buf
->count
== 0) {
284 BUG_ON(!list_empty(&buf
->cache
));
285 BUG_ON(!list_empty(&buf
->dirty
));
286 if (!radix_tree_lookup(&root
->cache_radix
, buf
->blocknr
))
288 radix_tree_delete(&root
->cache_radix
, buf
->blocknr
);
289 memset(buf
, 0, sizeof(*buf
));
291 BUG_ON(allocated_blocks
== 0);
293 BUG_ON(root
->cache_size
== 0);
This page took 0.055809 seconds and 6 git commands to generate.