diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-13 16:47:54 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-13 16:47:54 -0400 |
commit | 3768f3689fc76ecea17414936dff7a02746a4355 (patch) | |
tree | 0494b12e3ba0be0a25f122922e205bc91d88957b /fs/btrfs/disk-io.c | |
parent | eaee50e881b88766d9a781c54c4142456cf5e527 (diff) |
Btrfs: Change the super to point to a tree of trees to enable persistent snapshots
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 135 |
1 files changed, 107 insertions, 28 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c34c0c60935f..3d4bf6833f2a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -154,41 +154,96 @@ static int __commit_transaction(struct btrfs_root *root) | |||
154 | return ret; | 154 | return ret; |
155 | } | 155 | } |
156 | 156 | ||
157 | static int commit_extent_and_tree_roots(struct btrfs_root *tree_root, | ||
158 | struct btrfs_root *extent_root) | ||
159 | { | ||
160 | int ret; | ||
161 | u64 old_extent_block; | ||
162 | |||
163 | while(1) { | ||
164 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | ||
165 | if (old_extent_block == extent_root->node->blocknr) | ||
166 | break; | ||
167 | btrfs_set_root_blocknr(&extent_root->root_item, | ||
168 | extent_root->node->blocknr); | ||
169 | ret = btrfs_update_root(tree_root, | ||
170 | &extent_root->root_key, | ||
171 | &extent_root->root_item); | ||
172 | BUG_ON(ret); | ||
173 | } | ||
174 | __commit_transaction(extent_root); | ||
175 | __commit_transaction(tree_root); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
157 | int btrfs_commit_transaction(struct btrfs_root *root, | 179 | int btrfs_commit_transaction(struct btrfs_root *root, |
158 | struct btrfs_super_block *s) | 180 | struct btrfs_super_block *s) |
159 | { | 181 | { |
160 | int ret = 0; | 182 | int ret = 0; |
183 | struct btrfs_buffer *snap = root->commit_root; | ||
184 | struct btrfs_key snap_key; | ||
161 | 185 | ||
162 | ret = __commit_transaction(root); | 186 | ret = __commit_transaction(root); |
163 | if (!ret && root != root->extent_root) | ||
164 | ret = __commit_transaction(root->extent_root); | ||
165 | BUG_ON(ret); | 187 | BUG_ON(ret); |
166 | if (root->commit_root != root->node) { | 188 | |
167 | struct btrfs_buffer *snap = root->commit_root; | 189 | if (root->commit_root == root->node) |
168 | root->commit_root = root->node; | 190 | return 0; |
169 | root->node->count++; | 191 | |
170 | ret = btrfs_drop_snapshot(root, snap); | 192 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); |
171 | BUG_ON(ret); | 193 | root->root_key.offset++; |
172 | // btrfs_block_release(root, snap); | 194 | |
173 | } | 195 | btrfs_set_root_blocknr(&root->root_item, root->node->blocknr); |
196 | ret = btrfs_insert_root(root->tree_root, &root->root_key, | ||
197 | &root->root_item); | ||
198 | BUG_ON(ret); | ||
199 | |||
200 | ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root); | ||
201 | BUG_ON(ret); | ||
202 | |||
174 | write_ctree_super(root, s); | 203 | write_ctree_super(root, s); |
175 | btrfs_finish_extent_commit(root); | 204 | btrfs_finish_extent_commit(root->extent_root); |
205 | btrfs_finish_extent_commit(root->tree_root); | ||
206 | |||
207 | root->commit_root = root->node; | ||
208 | root->node->count++; | ||
209 | ret = btrfs_drop_snapshot(root, snap); | ||
210 | BUG_ON(ret); | ||
211 | |||
212 | ret = btrfs_del_root(root->tree_root, &snap_key); | ||
213 | BUG_ON(ret); | ||
214 | |||
176 | return ret; | 215 | return ret; |
177 | } | 216 | } |
178 | 217 | ||
179 | static int __setup_root(struct btrfs_root *root, struct btrfs_root *extent_root, | 218 | static int __setup_root(struct btrfs_root *root, u64 objectid, int fp) |
180 | struct btrfs_root_info *info, int fp) | ||
181 | { | 219 | { |
182 | INIT_LIST_HEAD(&root->trans); | 220 | INIT_LIST_HEAD(&root->trans); |
183 | INIT_LIST_HEAD(&root->cache); | 221 | INIT_LIST_HEAD(&root->cache); |
184 | root->cache_size = 0; | 222 | root->cache_size = 0; |
185 | root->fp = fp; | 223 | root->fp = fp; |
186 | root->node = NULL; | 224 | root->node = NULL; |
187 | root->extent_root = extent_root; | ||
188 | root->commit_root = NULL; | 225 | root->commit_root = NULL; |
189 | root->node = read_tree_block(root, info->tree_root); | ||
190 | memset(&root->current_insert, 0, sizeof(root->current_insert)); | 226 | memset(&root->current_insert, 0, sizeof(root->current_insert)); |
191 | memset(&root->last_insert, 0, sizeof(root->last_insert)); | 227 | memset(&root->last_insert, 0, sizeof(root->last_insert)); |
228 | memset(&root->root_key, 0, sizeof(root->root_key)); | ||
229 | memset(&root->root_item, 0, sizeof(root->root_item)); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int find_and_setup_root(struct btrfs_root *tree_root, u64 objectid, | ||
234 | struct btrfs_root *root, int fp) | ||
235 | { | ||
236 | int ret; | ||
237 | |||
238 | __setup_root(root, objectid, fp); | ||
239 | ret = btrfs_find_last_root(tree_root, objectid, | ||
240 | &root->root_item, &root->root_key); | ||
241 | BUG_ON(ret); | ||
242 | |||
243 | root->node = read_tree_block(root, | ||
244 | btrfs_root_blocknr(&root->root_item)); | ||
245 | root->ref_cows = 0; | ||
246 | BUG_ON(!root->node); | ||
192 | return 0; | 247 | return 0; |
193 | } | 248 | } |
194 | 249 | ||
@@ -196,9 +251,19 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
196 | { | 251 | { |
197 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); | 252 | struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); |
198 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); | 253 | struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); |
254 | struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); | ||
199 | int fp; | 255 | int fp; |
200 | int ret; | 256 | int ret; |
201 | 257 | ||
258 | root->extent_root = extent_root; | ||
259 | root->tree_root = tree_root; | ||
260 | |||
261 | extent_root->extent_root = extent_root; | ||
262 | extent_root->tree_root = tree_root; | ||
263 | |||
264 | tree_root->extent_root = extent_root; | ||
265 | tree_root->tree_root = tree_root; | ||
266 | |||
202 | fp = open(filename, O_CREAT | O_RDWR, 0600); | 267 | fp = open(filename, O_CREAT | O_RDWR, 0600); |
203 | if (fp < 0) { | 268 | if (fp < 0) { |
204 | free(root); | 269 | free(root); |
@@ -208,11 +273,14 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
208 | INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); | 273 | INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); |
209 | INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); | 274 | INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); |
210 | INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); | 275 | INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); |
276 | INIT_RADIX_TREE(&tree_root->pinned_radix, GFP_KERNEL); | ||
277 | INIT_RADIX_TREE(&tree_root->cache_radix, GFP_KERNEL); | ||
278 | |||
211 | ret = pread(fp, super, sizeof(struct btrfs_super_block), | 279 | ret = pread(fp, super, sizeof(struct btrfs_super_block), |
212 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); | 280 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); |
213 | if (ret == 0 || super->root_info.tree_root == 0) { | 281 | if (ret == 0 || btrfs_super_root(super) == 0) { |
214 | printf("making new FS!\n"); | 282 | printf("making new FS!\n"); |
215 | ret = mkfs(fp); | 283 | ret = mkfs(fp, 0, BTRFS_BLOCKSIZE); |
216 | if (ret) | 284 | if (ret) |
217 | return NULL; | 285 | return NULL; |
218 | ret = pread(fp, super, sizeof(struct btrfs_super_block), | 286 | ret = pread(fp, super, sizeof(struct btrfs_super_block), |
@@ -221,24 +289,29 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) | |||
221 | return NULL; | 289 | return NULL; |
222 | } | 290 | } |
223 | BUG_ON(ret < 0); | 291 | BUG_ON(ret < 0); |
224 | __setup_root(root, extent_root, &super->root_info, fp); | 292 | |
225 | __setup_root(extent_root, extent_root, &super->extent_info, fp); | 293 | __setup_root(tree_root, BTRFS_ROOT_TREE_OBJECTID, fp); |
294 | tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); | ||
295 | BUG_ON(!tree_root->node); | ||
296 | |||
297 | ret = find_and_setup_root(tree_root, BTRFS_EXTENT_TREE_OBJECTID, | ||
298 | extent_root, fp); | ||
299 | BUG_ON(ret); | ||
300 | |||
301 | ret = find_and_setup_root(tree_root, BTRFS_FS_TREE_OBJECTID, | ||
302 | root, fp); | ||
303 | BUG_ON(ret); | ||
304 | |||
226 | root->commit_root = root->node; | 305 | root->commit_root = root->node; |
227 | root->node->count++; | 306 | root->node->count++; |
307 | root->ref_cows = 1; | ||
228 | return root; | 308 | return root; |
229 | } | 309 | } |
230 | 310 | ||
231 | static int __update_root(struct btrfs_root *root, struct btrfs_root_info *info) | ||
232 | { | ||
233 | info->tree_root = root->node->blocknr; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s) | 311 | int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s) |
238 | { | 312 | { |
239 | int ret; | 313 | int ret; |
240 | __update_root(root, &s->root_info); | 314 | btrfs_set_super_root(s, root->tree_root->node->blocknr); |
241 | __update_root(root->extent_root, &s->extent_info); | ||
242 | ret = pwrite(root->fp, s, sizeof(*s), | 315 | ret = pwrite(root->fp, s, sizeof(*s), |
243 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); | 316 | BTRFS_SUPER_INFO_OFFSET(BTRFS_BLOCKSIZE)); |
244 | if (ret != sizeof(*s)) { | 317 | if (ret != sizeof(*s)) { |
@@ -260,19 +333,25 @@ static int drop_cache(struct btrfs_root *root) | |||
260 | } | 333 | } |
261 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) | 334 | int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) |
262 | { | 335 | { |
336 | int ret; | ||
263 | btrfs_commit_transaction(root, s); | 337 | btrfs_commit_transaction(root, s); |
264 | __commit_transaction(root->extent_root); | 338 | ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root); |
339 | BUG_ON(ret); | ||
265 | write_ctree_super(root, s); | 340 | write_ctree_super(root, s); |
266 | drop_cache(root->extent_root); | 341 | drop_cache(root->extent_root); |
342 | drop_cache(root->tree_root); | ||
267 | drop_cache(root); | 343 | drop_cache(root); |
268 | BUG_ON(!list_empty(&root->trans)); | 344 | BUG_ON(!list_empty(&root->trans)); |
269 | BUG_ON(!list_empty(&root->extent_root->trans)); | 345 | BUG_ON(!list_empty(&root->extent_root->trans)); |
346 | BUG_ON(!list_empty(&root->tree_root->trans)); | ||
270 | 347 | ||
271 | close(root->fp); | 348 | close(root->fp); |
272 | if (root->node) | 349 | if (root->node) |
273 | btrfs_block_release(root, root->node); | 350 | btrfs_block_release(root, root->node); |
274 | if (root->extent_root->node) | 351 | if (root->extent_root->node) |
275 | btrfs_block_release(root->extent_root, root->extent_root->node); | 352 | btrfs_block_release(root->extent_root, root->extent_root->node); |
353 | if (root->tree_root->node) | ||
354 | btrfs_block_release(root->tree_root, root->tree_root->node); | ||
276 | btrfs_block_release(root, root->commit_root); | 355 | btrfs_block_release(root, root->commit_root); |
277 | free(root); | 356 | free(root); |
278 | printf("on close %d blocks are allocated\n", allocated_blocks); | 357 | printf("on close %d blocks are allocated\n", allocated_blocks); |