remove device tree
[btrfs-progs-unstable.git] / disk-io.c
blobcb10c2d3e84838500dbfd48462ab6ede45f1f97c
1 #define _XOPEN_SOURCE 600
2 #define __USE_XOPEN2K
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include "kerncompat.h"
10 #include "radix-tree.h"
11 #include "ctree.h"
12 #include "disk-io.h"
13 #include "transaction.h"
15 static int allocated_blocks = 0;
16 int cache_max = 10000;
18 int btrfs_map_bh_to_logical(struct btrfs_root *root, struct btrfs_buffer *bh,
19 u64 logical)
21 bh->fd = root->fs_info->fp;
22 bh->dev_blocknr = logical;
23 return 0;
26 static int check_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
28 if (buf->blocknr != btrfs_header_blocknr(&buf->node.header))
29 BUG();
30 if (memcmp(root->fs_info->disk_super->fsid, buf->node.header.fsid,
31 sizeof(buf->node.header.fsid)))
32 BUG();
33 return 0;
36 static int free_some_buffers(struct btrfs_root *root)
38 struct list_head *node, *next;
39 struct btrfs_buffer *b;
40 if (root->fs_info->cache_size < cache_max)
41 return 0;
42 list_for_each_safe(node, next, &root->fs_info->cache) {
43 b = list_entry(node, struct btrfs_buffer, cache);
44 if (b->count == 1) {
45 BUG_ON(!list_empty(&b->dirty));
46 list_del_init(&b->cache);
47 btrfs_block_release(root, b);
48 if (root->fs_info->cache_size < cache_max)
49 break;
52 return 0;
55 struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr)
57 struct btrfs_buffer *buf;
58 int ret;
60 buf = malloc(sizeof(struct btrfs_buffer) + root->blocksize);
61 if (!buf)
62 return buf;
63 allocated_blocks++;
64 buf->blocknr = blocknr;
65 buf->count = 2;
66 INIT_LIST_HEAD(&buf->dirty);
67 free_some_buffers(root);
68 radix_tree_preload(GFP_KERNEL);
69 ret = radix_tree_insert(&root->fs_info->cache_radix, blocknr, buf);
70 radix_tree_preload_end();
71 list_add_tail(&buf->cache, &root->fs_info->cache);
72 root->fs_info->cache_size++;
73 if (ret) {
74 free(buf);
75 return NULL;
77 return buf;
80 struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr)
82 struct btrfs_buffer *buf;
83 buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr);
84 if (buf) {
85 buf->count++;
86 } else {
87 buf = alloc_tree_block(root, blocknr);
88 if (!buf) {
89 BUG();
90 return NULL;
93 return buf;
96 struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr)
98 struct btrfs_buffer *buf;
99 int ret;
100 buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr);
101 if (buf) {
102 buf->count++;
103 if (check_tree_block(root, buf))
104 BUG();
105 } else {
106 buf = alloc_tree_block(root, blocknr);
107 if (!buf)
108 return NULL;
109 btrfs_map_bh_to_logical(root, buf, blocknr);
110 ret = pread(buf->fd, &buf->node, root->blocksize,
111 buf->dev_blocknr * root->blocksize);
112 if (ret != root->blocksize) {
113 free(buf);
114 return NULL;
116 if (check_tree_block(root, buf))
117 BUG();
119 return buf;
122 int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
123 struct btrfs_buffer *buf)
125 if (!list_empty(&buf->dirty))
126 return 0;
127 list_add_tail(&buf->dirty, &root->fs_info->trans);
128 buf->count++;
129 if (check_tree_block(root, buf))
130 BUG();
131 return 0;
134 int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
135 struct btrfs_buffer *buf)
137 if (!list_empty(&buf->dirty)) {
138 list_del_init(&buf->dirty);
139 btrfs_block_release(root, buf);
141 return 0;
144 int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
145 struct btrfs_buffer *buf)
147 int ret;
149 if (buf->blocknr != btrfs_header_blocknr(&buf->node.header))
150 BUG();
151 btrfs_map_bh_to_logical(root, buf, buf->blocknr);
152 if (check_tree_block(root, buf))
153 BUG();
154 ret = pwrite(buf->fd, &buf->node, root->blocksize,
155 buf->dev_blocknr * root->blocksize);
156 if (ret != root->blocksize)
157 return ret;
158 return 0;
161 static int __commit_transaction(struct btrfs_trans_handle *trans, struct
162 btrfs_root *root)
164 struct btrfs_buffer *b;
165 int ret = 0;
166 int wret;
167 while(!list_empty(&root->fs_info->trans)) {
168 b = list_entry(root->fs_info->trans.next, struct btrfs_buffer,
169 dirty);
170 list_del_init(&b->dirty);
171 wret = write_tree_block(trans, root, b);
172 if (wret)
173 ret = wret;
174 btrfs_block_release(root, b);
176 return ret;
179 static int commit_tree_roots(struct btrfs_trans_handle *trans,
180 struct btrfs_fs_info *fs_info)
182 int ret;
183 u64 old_extent_block;
184 struct btrfs_root *tree_root = fs_info->tree_root;
185 struct btrfs_root *extent_root = fs_info->extent_root;
187 btrfs_write_dirty_block_groups(trans, fs_info->extent_root);
188 while(1) {
189 old_extent_block = btrfs_root_blocknr(&extent_root->root_item);
190 if (old_extent_block == extent_root->node->blocknr)
191 break;
192 btrfs_set_root_blocknr(&extent_root->root_item,
193 extent_root->node->blocknr);
194 ret = btrfs_update_root(trans, tree_root,
195 &extent_root->root_key,
196 &extent_root->root_item);
197 BUG_ON(ret);
198 btrfs_write_dirty_block_groups(trans, fs_info->extent_root);
200 return 0;
203 int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
204 btrfs_root *root, struct btrfs_super_block *s)
206 int ret = 0;
207 struct btrfs_buffer *snap = root->commit_root;
208 struct btrfs_key snap_key;
210 if (root->commit_root == root->node)
211 return 0;
213 memcpy(&snap_key, &root->root_key, sizeof(snap_key));
214 root->root_key.offset++;
216 btrfs_set_root_blocknr(&root->root_item, root->node->blocknr);
217 ret = btrfs_insert_root(trans, root->fs_info->tree_root,
218 &root->root_key, &root->root_item);
219 BUG_ON(ret);
221 ret = commit_tree_roots(trans, root->fs_info);
222 BUG_ON(ret);
224 ret = __commit_transaction(trans, root);
225 BUG_ON(ret);
227 write_ctree_super(trans, root, s);
228 btrfs_finish_extent_commit(trans, root->fs_info->extent_root);
229 btrfs_finish_extent_commit(trans, root->fs_info->tree_root);
231 root->commit_root = root->node;
232 root->node->count++;
233 ret = btrfs_drop_snapshot(trans, root, snap);
234 BUG_ON(ret);
236 ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key);
237 BUG_ON(ret);
238 root->fs_info->generation = root->root_key.offset + 1;
240 return ret;
243 static int __setup_root(struct btrfs_super_block *super,
244 struct btrfs_root *root,
245 struct btrfs_fs_info *fs_info,
246 u64 objectid, int fp)
248 root->node = NULL;
249 root->commit_root = NULL;
250 root->blocksize = btrfs_super_blocksize(super);
251 root->ref_cows = 0;
252 root->fs_info = fs_info;
253 memset(&root->root_key, 0, sizeof(root->root_key));
254 memset(&root->root_item, 0, sizeof(root->root_item));
255 root->root_key.objectid = objectid;
256 return 0;
259 static int find_and_setup_root(struct btrfs_super_block *super,
260 struct btrfs_root *tree_root,
261 struct btrfs_fs_info *fs_info,
262 u64 objectid,
263 struct btrfs_root *root, int fp)
265 int ret;
267 __setup_root(super, root, fs_info, objectid, fp);
268 ret = btrfs_find_last_root(tree_root, objectid,
269 &root->root_item, &root->root_key);
270 BUG_ON(ret);
272 root->node = read_tree_block(root,
273 btrfs_root_blocknr(&root->root_item));
274 BUG_ON(!root->node);
275 return 0;
278 struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super)
280 int fp;
282 fp = open(filename, O_CREAT | O_RDWR, 0600);
283 if (fp < 0) {
284 return NULL;
286 return open_ctree_fd(fp, super);
289 struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
291 struct btrfs_root *root = malloc(sizeof(struct btrfs_root));
292 struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
293 struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root));
294 struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
295 int ret;
297 INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL);
298 INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL);
299 INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL);
300 INIT_LIST_HEAD(&fs_info->trans);
301 INIT_LIST_HEAD(&fs_info->cache);
302 fs_info->cache_size = 0;
303 fs_info->fp = fp;
304 fs_info->running_transaction = NULL;
305 fs_info->fs_root = root;
306 fs_info->tree_root = tree_root;
307 fs_info->extent_root = extent_root;
308 fs_info->last_inode_alloc = 0;
309 fs_info->last_inode_alloc_dirid = 0;
310 fs_info->disk_super = super;
311 memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert));
312 memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
314 ret = pread(fp, super, sizeof(struct btrfs_super_block),
315 BTRFS_SUPER_INFO_OFFSET);
316 if (ret == 0 || btrfs_super_root(super) == 0) {
317 BUG();
318 return NULL;
320 BUG_ON(ret < 0);
322 __setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp);
323 tree_root->node = read_tree_block(tree_root, btrfs_super_root(super));
324 BUG_ON(!tree_root->node);
326 ret = find_and_setup_root(super, tree_root, fs_info,
327 BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp);
328 BUG_ON(ret);
330 ret = find_and_setup_root(super, tree_root, fs_info,
331 BTRFS_FS_TREE_OBJECTID, root, fp);
332 BUG_ON(ret);
334 root->commit_root = root->node;
335 root->node->count++;
336 root->ref_cows = 1;
337 root->fs_info->generation = root->root_key.offset + 1;
338 btrfs_read_block_groups(root);
339 return root;
342 int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
343 *root, struct btrfs_super_block *s)
345 int ret;
346 btrfs_set_super_root(s, root->fs_info->tree_root->node->blocknr);
347 ret = pwrite(root->fs_info->fp, s, sizeof(*s),
348 BTRFS_SUPER_INFO_OFFSET);
349 if (ret != sizeof(*s)) {
350 fprintf(stderr, "failed to write new super block err %d\n", ret);
351 return ret;
353 return 0;
356 static int drop_cache(struct btrfs_root *root)
358 while(!list_empty(&root->fs_info->cache)) {
359 struct btrfs_buffer *b = list_entry(root->fs_info->cache.next,
360 struct btrfs_buffer,
361 cache);
362 list_del_init(&b->cache);
363 btrfs_block_release(root, b);
365 return 0;
368 int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
370 int ret;
371 struct btrfs_trans_handle *trans;
373 trans = root->fs_info->running_transaction;
374 btrfs_commit_transaction(trans, root, s);
375 ret = commit_tree_roots(trans, root->fs_info);
376 BUG_ON(ret);
377 ret = __commit_transaction(trans, root);
378 BUG_ON(ret);
379 write_ctree_super(trans, root, s);
380 drop_cache(root);
381 BUG_ON(!list_empty(&root->fs_info->trans));
383 btrfs_free_block_groups(root->fs_info);
384 close(root->fs_info->fp);
385 if (root->node)
386 btrfs_block_release(root, root->node);
387 if (root->fs_info->extent_root->node)
388 btrfs_block_release(root->fs_info->extent_root,
389 root->fs_info->extent_root->node);
390 if (root->fs_info->tree_root->node)
391 btrfs_block_release(root->fs_info->tree_root,
392 root->fs_info->tree_root->node);
393 btrfs_block_release(root, root->commit_root);
394 free(root);
395 printf("on close %d blocks are allocated\n", allocated_blocks);
396 return 0;
399 void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf)
401 buf->count--;
402 if (buf->count < 0)
403 BUG();
404 if (buf->count == 0) {
405 BUG_ON(!list_empty(&buf->cache));
406 BUG_ON(!list_empty(&buf->dirty));
407 if (!radix_tree_lookup(&root->fs_info->cache_radix,
408 buf->blocknr))
409 BUG();
410 radix_tree_delete(&root->fs_info->cache_radix, buf->blocknr);
411 memset(buf, 0, sizeof(*buf));
412 free(buf);
413 BUG_ON(allocated_blocks == 0);
414 allocated_blocks--;
415 BUG_ON(root->fs_info->cache_size == 0);
416 root->fs_info->cache_size--;