diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 79 |
1 files changed, 45 insertions, 34 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 653f18aab330..2f71ccf1c3cb 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -15,7 +15,7 @@ static int allocated_blocks = 0; | |||
15 | static int get_free_block(struct ctree_root *root, u64 *block) | 15 | static int get_free_block(struct ctree_root *root, u64 *block) |
16 | { | 16 | { |
17 | struct stat st; | 17 | struct stat st; |
18 | int ret; | 18 | int ret = 0; |
19 | 19 | ||
20 | if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) | 20 | if (root->alloc_extent->num_used >= root->alloc_extent->num_blocks) |
21 | return -1; | 21 | return -1; |
@@ -30,9 +30,14 @@ static int get_free_block(struct ctree_root *root, u64 *block) | |||
30 | } | 30 | } |
31 | st.st_size = 0; | 31 | st.st_size = 0; |
32 | ret = fstat(root->fp, &st); | 32 | ret = fstat(root->fp, &st); |
33 | if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) | 33 | if (st.st_size < (*block + 1) * CTREE_BLOCKSIZE) { |
34 | ret = ftruncate(root->fp, | 34 | ret = ftruncate(root->fp, |
35 | (*block + 1) * CTREE_BLOCKSIZE); | 35 | (*block + 1) * CTREE_BLOCKSIZE); |
36 | if (ret) { | ||
37 | perror("ftruncate"); | ||
38 | exit(1); | ||
39 | } | ||
40 | } | ||
36 | return ret; | 41 | return ret; |
37 | } | 42 | } |
38 | 43 | ||
@@ -81,11 +86,7 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) | |||
81 | buf = radix_tree_lookup(&root->cache_radix, blocknr); | 86 | buf = radix_tree_lookup(&root->cache_radix, blocknr); |
82 | if (buf) { | 87 | if (buf) { |
83 | buf->count++; | 88 | buf->count++; |
84 | if (buf->blocknr != blocknr) | 89 | goto test; |
85 | BUG(); | ||
86 | if (buf->blocknr != buf->node.header.blocknr) | ||
87 | BUG(); | ||
88 | return buf; | ||
89 | } | 90 | } |
90 | buf = alloc_tree_block(root, blocknr); | 91 | buf = alloc_tree_block(root, blocknr); |
91 | if (!buf) | 92 | if (!buf) |
@@ -95,8 +96,11 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) | |||
95 | free(buf); | 96 | free(buf); |
96 | return NULL; | 97 | return NULL; |
97 | } | 98 | } |
99 | test: | ||
98 | if (buf->blocknr != buf->node.header.blocknr) | 100 | if (buf->blocknr != buf->node.header.blocknr) |
99 | BUG(); | 101 | BUG(); |
102 | if (root->node && buf->node.header.parentid != root->node->node.header.parentid) | ||
103 | BUG(); | ||
100 | return buf; | 104 | return buf; |
101 | } | 105 | } |
102 | 106 | ||
@@ -111,36 +115,30 @@ int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) | |||
111 | ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); | 115 | ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset); |
112 | if (ret != CTREE_BLOCKSIZE) | 116 | if (ret != CTREE_BLOCKSIZE) |
113 | return ret; | 117 | return ret; |
114 | if (buf == root->node) | ||
115 | return update_root_block(root); | ||
116 | return 0; | 118 | return 0; |
117 | } | 119 | } |
118 | 120 | ||
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, | 121 | static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, |
125 | struct ctree_root_info *info, int fp) | 122 | struct ctree_root_info *info, int fp) |
126 | { | 123 | { |
124 | INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); | ||
127 | root->fp = fp; | 125 | root->fp = fp; |
126 | root->node = NULL; | ||
128 | root->node = read_tree_block(root, info->tree_root); | 127 | root->node = read_tree_block(root, info->tree_root); |
129 | root->extent_root = extent_root; | 128 | root->extent_root = extent_root; |
130 | memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); | 129 | memcpy(&root->ai1, &info->alloc_extent, sizeof(info->alloc_extent)); |
131 | memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); | 130 | memcpy(&root->ai2, &info->reserve_extent, sizeof(info->reserve_extent)); |
132 | root->alloc_extent = &root->ai1; | 131 | root->alloc_extent = &root->ai1; |
133 | root->reserve_extent = &root->ai2; | 132 | root->reserve_extent = &root->ai2; |
134 | INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); | 133 | printf("setup done reading root %p, used %lu available %lu\n", root, root->alloc_extent->num_used, root->alloc_extent->num_blocks); |
135 | printf("setup done reading root %p, used %lu\n", root, root->alloc_extent->num_used); | 134 | printf("setup done reading root %p, reserve used %lu available %lu\n", root, root->reserve_extent->num_used, root->reserve_extent->num_blocks); |
136 | return 0; | 135 | return 0; |
137 | } | 136 | } |
138 | 137 | ||
139 | struct ctree_root *open_ctree(char *filename) | 138 | struct ctree_root *open_ctree(char *filename, struct ctree_super_block *super) |
140 | { | 139 | { |
141 | struct ctree_root *root = malloc(sizeof(struct ctree_root)); | 140 | struct ctree_root *root = malloc(sizeof(struct ctree_root)); |
142 | struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); | 141 | struct ctree_root *extent_root = malloc(sizeof(struct ctree_root)); |
143 | struct ctree_super_block super; | ||
144 | int fp; | 142 | int fp; |
145 | int ret; | 143 | int ret; |
146 | 144 | ||
@@ -149,48 +147,61 @@ struct ctree_root *open_ctree(char *filename) | |||
149 | free(root); | 147 | free(root); |
150 | return NULL; | 148 | return NULL; |
151 | } | 149 | } |
152 | ret = pread(fp, &super, sizeof(struct ctree_super_block), | 150 | ret = pread(fp, super, sizeof(struct ctree_super_block), |
153 | CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); | 151 | CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); |
154 | if (ret == 0) { | 152 | if (ret == 0) { |
155 | ret = mkfs(fp); | 153 | ret = mkfs(fp); |
156 | if (ret) | 154 | if (ret) |
157 | return NULL; | 155 | return NULL; |
158 | ret = pread(fp, &super, sizeof(struct ctree_super_block), | 156 | ret = pread(fp, super, sizeof(struct ctree_super_block), |
159 | CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); | 157 | CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); |
160 | if (ret != sizeof(struct ctree_super_block)) | 158 | if (ret != sizeof(struct ctree_super_block)) |
161 | return NULL; | 159 | return NULL; |
162 | } | 160 | } |
163 | BUG_ON(ret < 0); | 161 | BUG_ON(ret < 0); |
164 | __setup_root(root, extent_root, &super.root_info, fp); | 162 | __setup_root(root, extent_root, &super->root_info, fp); |
165 | __setup_root(extent_root, extent_root, &super.extent_info, fp); | 163 | __setup_root(extent_root, extent_root, &super->extent_info, fp); |
166 | return root; | 164 | return root; |
167 | } | 165 | } |
168 | 166 | ||
169 | int close_ctree(struct ctree_root *root) | 167 | static int __update_root(struct ctree_root *root, struct ctree_root_info *info) |
170 | { | 168 | { |
171 | close(root->fp); | 169 | info->tree_root = root->node->blocknr; |
172 | if (root->node) | 170 | memcpy(&info->alloc_extent, root->alloc_extent, sizeof(struct alloc_extent)); |
173 | tree_block_release(root, root->node); | 171 | memcpy(&info->reserve_extent, root->reserve_extent, sizeof(struct alloc_extent)); |
174 | free(root); | ||
175 | printf("on close %d blocks are allocated\n", allocated_blocks); | ||
176 | return 0; | 172 | return 0; |
177 | } | 173 | } |
178 | 174 | ||
179 | int update_root_block(struct ctree_root *root) | 175 | int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s) |
180 | { | 176 | { |
181 | int ret; | 177 | int ret; |
182 | u64 root_block = root->node->blocknr; | 178 | __update_root(root, &s->root_info); |
183 | 179 | __update_root(root->extent_root, &s->extent_info); | |
184 | ret = pwrite(root->fp, &root_block, sizeof(u64), 0); | 180 | ret = pwrite(root->fp, s, sizeof(*s), CTREE_SUPER_INFO_OFFSET(CTREE_BLOCKSIZE)); |
185 | if (ret != sizeof(u64)) | 181 | if (ret != sizeof(*s)) { |
182 | fprintf(stderr, "failed to write new super block err %d\n", ret); | ||
186 | return 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); | ||
187 | return 0; | 197 | return 0; |
188 | } | 198 | } |
189 | 199 | ||
190 | void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) | 200 | void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) |
191 | { | 201 | { |
192 | return; | ||
193 | buf->count--; | 202 | buf->count--; |
203 | if (buf->count < 0) | ||
204 | BUG(); | ||
194 | if (buf->count == 0) { | 205 | if (buf->count == 0) { |
195 | if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) | 206 | if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) |
196 | BUG(); | 207 | BUG(); |