Btrfs: add mkfs.c
[linux-2.6-block.git] / fs / btrfs / disk-io.c
CommitLineData
eb60ceac
CM
1#define _XOPEN_SOURCE 500
2#include <stdio.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <unistd.h>
8#include "kerncompat.h"
9#include "radix-tree.h"
10#include "ctree.h"
11#include "disk-io.h"
12
13static int allocated_blocks = 0;
14
eb60ceac
CM
15static int get_free_block(struct ctree_root *root, u64 *block)
16{
17 struct stat st;
18 int ret;
19
d97e63b6
CM
20 if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks)
21 return -1;
22
23 *block = root->alloc_extent->blocknr + root->alloc_extent->num_used;
24 root->alloc_extent->num_used += 1;
25 if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) {
26 struct alloc_extent *ae = root->alloc_extent;
27 root->alloc_extent = root->reserve_extent;
28 root->reserve_extent = ae;
29 ae->num_blocks = 0;
30 }
eb60ceac
CM
31 st.st_size = 0;
32 ret = fstat(root->fp, &st);
d97e63b6
CM
33 if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE)
34 ret = ftruncate(root->fp,
35 (*block + 1) * CTREE_BLOCKSIZE);
eb60ceac
CM
36 return ret;
37}
38
39struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr)
40{
41 struct tree_buffer *buf;
42 int ret;
43 buf = malloc(sizeof(struct tree_buffer));
44 if (!buf)
45 return buf;
46 allocated_blocks++;
47 buf->blocknr = blocknr;
48 buf->count = 1;
49 radix_tree_preload(GFP_KERNEL);
50 ret = radix_tree_insert(&root->cache_radix, blocknr, buf);
51 radix_tree_preload_end();
52 if (ret) {
53 free(buf);
54 return NULL;
55 }
56 return buf;
57}
58
59struct tree_buffer *alloc_free_block(struct ctree_root *root)
60{
61 u64 free_block;
62 int ret;
63 struct tree_buffer * buf;
64 ret = get_free_block(root, &free_block);
65 if (ret) {
66 BUG();
67 return NULL;
68 }
69 buf = alloc_tree_block(root, free_block);
70 if (!buf)
71 BUG();
72 return buf;
73}
74
75struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
76{
d97e63b6 77 loff_t offset = blocknr * CTREE_BLOCKSIZE;
eb60ceac
CM
78 struct tree_buffer *buf;
79 int ret;
80
81 buf = radix_tree_lookup(&root->cache_radix, blocknr);
82 if (buf) {
83 buf->count++;
84 if (buf->blocknr != blocknr)
85 BUG();
86 if (buf->blocknr != buf->node.header.blocknr)
87 BUG();
88 return buf;
89 }
90 buf = alloc_tree_block(root, blocknr);
91 if (!buf)
92 return NULL;
93 ret = pread(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
94 if (ret != CTREE_BLOCKSIZE) {
95 free(buf);
96 return NULL;
97 }
98 if (buf->blocknr != buf->node.header.blocknr)
99 BUG();
100 return buf;
101}
102
103int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
104{
105 u64 blocknr = buf->blocknr;
d97e63b6 106 loff_t offset = blocknr * CTREE_BLOCKSIZE;
eb60ceac
CM
107 int ret;
108
109 if (buf->blocknr != buf->node.header.blocknr)
110 BUG();
111 ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
112 if (ret != CTREE_BLOCKSIZE)
113 return ret;
114 if (buf == root->node)
115 return update_root_block(root);
116 return 0;
117}
118
d97e63b6
CM
119struct ctree_super_block {
120 struct ctree_root_info root_info;
121 struct ctree_root_info extent_info;
122} __attribute__ ((__packed__));
123
124static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root,
125 struct ctree_root_info *info, int fp)
126{
127 root->fp = fp;
128 root->node = read_tree_block(root, info->tree_root);
129 root->extent_root = extent_root;
130 memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent));
131 memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent));
132 root->alloc_extent = &root->ai1;
133 root->reserve_extent = &root->ai2;
134 INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL);
135 printf("setup done reading root %p, used %lu\n", root, root->alloc_extent->num_used);
136 return 0;
137}
138
eb60ceac
CM
139struct ctree_root *open_ctree(char *filename)
140{
141 struct ctree_root *root = malloc(sizeof(struct ctree_root));
d97e63b6
CM
142 struct ctree_root *extent_root = malloc(sizeof(struct ctree_root));
143 struct ctree_super_block super;
eb60ceac 144 int fp;
eb60ceac
CM
145 int ret;
146
147 fp = open(filename, O_CREAT | O_RDWR);
148 if (fp < 0) {
149 free(root);
150 return NULL;
151 }
d97e63b6
CM
152 ret = pread(fp, &super, sizeof(struct ctree_super_block),
153 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
154 if (ret == 0) {
155 ret = mkfs(fp);
156 if (ret)
157 return NULL;
158 ret = pread(fp, &super, sizeof(struct ctree_super_block),
159 CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
160 if (ret != sizeof(struct ctree_super_block))
161 return NULL;
162 }
163 BUG_ON(ret < 0);
164 __setup_root(root, extent_root, &super.root_info, fp);
165 __setup_root(extent_root, extent_root, &super.extent_info, fp);
eb60ceac
CM
166 return root;
167}
168
169int close_ctree(struct ctree_root *root)
170{
171 close(root->fp);
172 if (root->node)
173 tree_block_release(root, root->node);
174 free(root);
175 printf("on close %d blocks are allocated\n", allocated_blocks);
176 return 0;
177}
178
179int update_root_block(struct ctree_root *root)
180{
181 int ret;
182 u64 root_block = root->node->blocknr;
183
184 ret = pwrite(root->fp, &root_block, sizeof(u64), 0);
185 if (ret != sizeof(u64))
186 return ret;
187 return 0;
188}
189
190void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
191{
d97e63b6 192 return;
eb60ceac
CM
193 buf->count--;
194 if (buf->count == 0) {
195 if (!radix_tree_lookup(&root->cache_radix, buf->blocknr))
196 BUG();
197 radix_tree_delete(&root->cache_radix, buf->blocknr);
198 memset(buf, 0, sizeof(*buf));
199 free(buf);
200 BUG_ON(allocated_blocks == 0);
201 allocated_blocks--;
202 }
203}
204