extent fixes
[platform/upstream/btrfs-progs.git] / disk-io.c
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
13 static int allocated_blocks = 0;
14
15 static int get_free_block(struct ctree_root *root, u64 *block)
16 {
17         struct stat st;
18         int ret = 0;
19
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         }
31         st.st_size = 0;
32         ret = fstat(root->fp, &st);
33         if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) {
34                 ret = ftruncate(root->fp,
35                                 (*block + 1) * CTREE_BLOCKSIZE);
36                 if (ret) {
37                         perror("ftruncate");
38                         exit(1);
39                 }
40         }
41         return ret;
42 }
43
44 struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr)
45 {
46         struct tree_buffer *buf;
47         int ret;
48         buf = malloc(sizeof(struct tree_buffer));
49         if (!buf)
50                 return buf;
51         allocated_blocks++;
52         buf->blocknr = blocknr;
53         buf->count = 1;
54         radix_tree_preload(GFP_KERNEL);
55         ret = radix_tree_insert(&root->cache_radix, blocknr, buf);
56         radix_tree_preload_end();
57         if (ret) {
58                 free(buf);
59                 return NULL;
60         }
61         return buf;
62 }
63
64 struct tree_buffer *alloc_free_block(struct ctree_root *root)
65 {
66         u64 free_block;
67         int ret;
68         struct tree_buffer * buf;
69         ret = get_free_block(root, &free_block);
70         if (ret) {
71                 BUG();
72                 return NULL;
73         }
74         buf = alloc_tree_block(root, free_block);
75         if (!buf)
76                 BUG();
77         return buf;
78 }
79
80 struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
81 {
82         loff_t offset = blocknr * CTREE_BLOCKSIZE;
83         struct tree_buffer *buf;
84         int ret;
85
86         buf = radix_tree_lookup(&root->cache_radix, blocknr);
87         if (buf) {
88                 buf->count++;
89                 goto test;
90         }
91         buf = alloc_tree_block(root, blocknr);
92         if (!buf)
93                 return NULL;
94         ret = pread(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
95         if (ret != CTREE_BLOCKSIZE) {
96                 free(buf);
97                 return NULL;
98         }
99 test:
100         if (buf->blocknr != buf->node.header.blocknr)
101                 BUG();
102         if (root->node && buf->node.header.parentid != root->node->node.header.parentid)
103                 BUG();
104         return buf;
105 }
106
107 int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
108 {
109         u64 blocknr = buf->blocknr;
110         loff_t offset = blocknr * CTREE_BLOCKSIZE;
111         int ret;
112
113         if (buf->blocknr != buf->node.header.blocknr)
114                 BUG();
115         ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
116         if (ret != CTREE_BLOCKSIZE)
117                 return ret;
118         return 0;
119 }
120
121 static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root,
122                         struct ctree_root_info *info, int fp)
123 {
124         INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL);
125         root->fp = fp;
126         root->node = NULL;
127         root->node = read_tree_block(root, info->tree_root);
128         root->extent_root = extent_root;
129         memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent));
130         memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent));
131         root->alloc_extent = &root->ai1;
132         root->reserve_extent = &root->ai2;
133         printf("setup done reading root %p, used %lu available %lu\n", root, root->alloc_extent->num_used, root->alloc_extent->num_blocks);
134         printf("setup done reading root %p, reserve used %lu available %lu\n", root, root->reserve_extent->num_used, root->reserve_extent->num_blocks);
135         return 0;
136 }
137
138 struct ctree_root *open_ctree(char *filename, struct ctree_super_block *super)
139 {
140         struct ctree_root *root = malloc(sizeof(struct ctree_root));
141         struct ctree_root *extent_root = malloc(sizeof(struct ctree_root));
142         int fp;
143         int ret;
144
145         fp = open(filename, O_CREAT | O_RDWR);
146         if (fp < 0) {
147                 free(root);
148                 return NULL;
149         }
150         ret = pread(fp, super, sizeof(struct ctree_super_block),
151                      CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
152         if (ret == 0) {
153                 ret = mkfs(fp);
154                 if (ret)
155                         return NULL;
156                 ret = pread(fp, super, sizeof(struct ctree_super_block),
157                              CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
158                 if (ret != sizeof(struct ctree_super_block))
159                         return NULL;
160         }
161         BUG_ON(ret < 0);
162         __setup_root(root, extent_root, &super->root_info, fp);
163         __setup_root(extent_root, extent_root, &super->extent_info, fp);
164         return root;
165 }
166
167 static int __update_root(struct ctree_root *root, struct ctree_root_info *info)
168 {
169         info->tree_root = root->node->blocknr;
170         memcpy(&info->alloc_extent, root->alloc_extent, sizeof(struct alloc_extent));
171         memcpy(&info->reserve_extent, root->reserve_extent, sizeof(struct alloc_extent));
172         return 0;
173 }
174
175 int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s)
176 {
177         int ret;
178         __update_root(root, &s->root_info);
179         __update_root(root->extent_root, &s->extent_info);
180         ret = pwrite(root->fp, s, sizeof(*s), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE));
181         if (ret != sizeof(*s)) {
182                 fprintf(stderr, "failed to write new super block err %d\n", ret);
183                 return ret;
184         }
185         return 0;
186 }
187
188 int close_ctree(struct ctree_root *root)
189 {
190         close(root->fp);
191         if (root->node)
192                 tree_block_release(root, root->node);
193         if (root->extent_root->node)
194                 tree_block_release(root->extent_root, root->extent_root->node);
195         free(root);
196         printf("on close %d blocks are allocated\n", allocated_blocks);
197         return 0;
198 }
199
200 void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
201 {
202         buf->count--;
203         if (buf->count < 0)
204                 BUG();
205         if (buf->count == 0) {
206                 if (!radix_tree_lookup(&root->cache_radix, buf->blocknr))
207                         BUG();
208                 radix_tree_delete(&root->cache_radix, buf->blocknr);
209                 memset(buf, 0, sizeof(*buf));
210                 free(buf);
211                 BUG_ON(allocated_blocks == 0);
212                 allocated_blocks--;
213         }
214 }
215