653f18aab330adc8ae5f138f019d9db0ac884d79
[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;
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         return ret;
37 }
38
39 struct 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
59 struct 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
75 struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
76 {
77         loff_t offset = blocknr * CTREE_BLOCKSIZE;
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
103 int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
104 {
105         u64 blocknr = buf->blocknr;
106         loff_t offset = blocknr * CTREE_BLOCKSIZE;
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
119 struct ctree_super_block {
120         struct ctree_root_info root_info;
121         struct ctree_root_info extent_info;
122 } __attribute__ ((__packed__));
123
124 static 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
139 struct ctree_root *open_ctree(char *filename)
140 {
141         struct ctree_root *root = malloc(sizeof(struct ctree_root));
142         struct ctree_root *extent_root = malloc(sizeof(struct ctree_root));
143         struct ctree_super_block super;
144         int fp;
145         int ret;
146
147         fp = open(filename, O_CREAT | O_RDWR);
148         if (fp < 0) {
149                 free(root);
150                 return NULL;
151         }
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);
166         return root;
167 }
168
169 int 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
179 int 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
190 void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
191 {
192         return;
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