diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-09 10:42:37 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-09 10:42:37 -0400 |
commit | 0f7d52f4431c530b4f39c524448c688bb7754de5 (patch) | |
tree | 1ba4f62a2b7230456e1b4850ddad339148f44b3e | |
parent | d6e4a428eb8f92bbb3537ccabadfb1195efb432b (diff) |
Btrfs: groundwork for subvolume and snapshot roots
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/bit-radix.c | 2 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 20 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 178 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/super.c | 39 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 140 |
6 files changed, 282 insertions, 99 deletions
diff --git a/fs/btrfs/bit-radix.c b/fs/btrfs/bit-radix.c index 783f54c2a16c..9fc42e99c7df 100644 --- a/fs/btrfs/bit-radix.c +++ b/fs/btrfs/bit-radix.c | |||
@@ -86,7 +86,7 @@ int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits, | |||
86 | int i; | 86 | int i; |
87 | int total_found = 0; | 87 | int total_found = 0; |
88 | 88 | ||
89 | ret = radix_tree_gang_lookup(radix, (void *)&gang, 0, ARRAY_SIZE(gang)); | 89 | ret = radix_tree_gang_lookup(radix, (void **)gang, 0, ARRAY_SIZE(gang)); |
90 | for (i = 0; i < ret && nr > 0; i++) { | 90 | for (i = 0; i < ret && nr > 0; i++) { |
91 | found = 0; | 91 | found = 0; |
92 | bits = gang[i]; | 92 | bits = gang[i]; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1ff5b99af682..5460030c9e6a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -232,12 +232,12 @@ struct btrfs_inode_map_item { | |||
232 | 232 | ||
233 | struct crypto_hash; | 233 | struct crypto_hash; |
234 | struct btrfs_fs_info { | 234 | struct btrfs_fs_info { |
235 | struct btrfs_root *fs_root; | ||
236 | struct btrfs_root *extent_root; | 235 | struct btrfs_root *extent_root; |
237 | struct btrfs_root *tree_root; | 236 | struct btrfs_root *tree_root; |
238 | struct btrfs_root *inode_root; | 237 | struct btrfs_root *inode_root; |
239 | struct btrfs_key current_insert; | 238 | struct btrfs_key current_insert; |
240 | struct btrfs_key last_insert; | 239 | struct btrfs_key last_insert; |
240 | struct radix_tree_root fs_roots_radix; | ||
241 | struct radix_tree_root pending_del_radix; | 241 | struct radix_tree_root pending_del_radix; |
242 | struct radix_tree_root pinned_radix; | 242 | struct radix_tree_root pinned_radix; |
243 | u64 last_inode_alloc; | 243 | u64 last_inode_alloc; |
@@ -266,6 +266,9 @@ struct btrfs_root { | |||
266 | struct btrfs_root_item root_item; | 266 | struct btrfs_root_item root_item; |
267 | struct btrfs_key root_key; | 267 | struct btrfs_key root_key; |
268 | struct btrfs_fs_info *fs_info; | 268 | struct btrfs_fs_info *fs_info; |
269 | struct inode *inode; | ||
270 | u64 objectid; | ||
271 | u64 last_trans; | ||
269 | u32 blocksize; | 272 | u32 blocksize; |
270 | int ref_cows; | 273 | int ref_cows; |
271 | u32 type; | 274 | u32 type; |
@@ -595,7 +598,7 @@ static inline u32 btrfs_key_overflow(struct btrfs_key *key) | |||
595 | 598 | ||
596 | static inline void btrfs_set_key_overflow(struct btrfs_key *key, u32 over) | 599 | static inline void btrfs_set_key_overflow(struct btrfs_key *key, u32 over) |
597 | { | 600 | { |
598 | BUG_ON(over > BTRFS_KEY_OVERFLOW_MAX); | 601 | BUG_ON(over >= BTRFS_KEY_OVERFLOW_MAX); |
599 | over = over << BTRFS_KEY_OVERFLOW_SHIFT; | 602 | over = over << BTRFS_KEY_OVERFLOW_SHIFT; |
600 | key->flags = (key->flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over; | 603 | key->flags = (key->flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over; |
601 | } | 604 | } |
@@ -634,7 +637,7 @@ static inline void btrfs_set_disK_key_overflow(struct btrfs_disk_key *key, | |||
634 | u32 over) | 637 | u32 over) |
635 | { | 638 | { |
636 | u32 flags = btrfs_disk_key_flags(key); | 639 | u32 flags = btrfs_disk_key_flags(key); |
637 | BUG_ON(over > BTRFS_KEY_OVERFLOW_MAX); | 640 | BUG_ON(over >= BTRFS_KEY_OVERFLOW_MAX); |
638 | over = over << BTRFS_KEY_OVERFLOW_SHIFT; | 641 | over = over << BTRFS_KEY_OVERFLOW_SHIFT; |
639 | flags = (flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over; | 642 | flags = (flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over; |
640 | btrfs_set_disk_key_flags(key, flags); | 643 | btrfs_set_disk_key_flags(key, flags); |
@@ -748,6 +751,17 @@ static inline void btrfs_set_super_blocknr(struct btrfs_super_block *s, u64 val) | |||
748 | s->blocknr = cpu_to_le64(val); | 751 | s->blocknr = cpu_to_le64(val); |
749 | } | 752 | } |
750 | 753 | ||
754 | static inline u64 btrfs_super_generation(struct btrfs_super_block *s) | ||
755 | { | ||
756 | return le64_to_cpu(s->generation); | ||
757 | } | ||
758 | |||
759 | static inline void btrfs_set_super_generation(struct btrfs_super_block *s, | ||
760 | u64 val) | ||
761 | { | ||
762 | s->generation = cpu_to_le64(val); | ||
763 | } | ||
764 | |||
751 | static inline u64 btrfs_super_root(struct btrfs_super_block *s) | 765 | static inline u64 btrfs_super_root(struct btrfs_super_block *s) |
752 | { | 766 | { |
753 | return le64_to_cpu(s->root); | 767 | return le64_to_cpu(s->root); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b9301a5e4608..b557bdd1e26a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -4,9 +4,11 @@ | |||
4 | #include <linux/crypto.h> | 4 | #include <linux/crypto.h> |
5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
6 | #include <linux/swap.h> | 6 | #include <linux/swap.h> |
7 | #include <linux/radix-tree.h> | ||
7 | #include "ctree.h" | 8 | #include "ctree.h" |
8 | #include "disk-io.h" | 9 | #include "disk-io.h" |
9 | #include "transaction.h" | 10 | #include "transaction.h" |
11 | #include "btrfs_inode.h" | ||
10 | 12 | ||
11 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) | 13 | static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) |
12 | { | 14 | { |
@@ -180,7 +182,7 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, | |||
180 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 182 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
181 | { | 183 | { |
182 | struct buffer_head *bh; | 184 | struct buffer_head *bh; |
183 | struct btrfs_root *root = btrfs_sb(page->mapping->host->i_sb); | 185 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; |
184 | struct buffer_head *head; | 186 | struct buffer_head *head; |
185 | if (!page_has_buffers(page)) { | 187 | if (!page_has_buffers(page)) { |
186 | create_empty_buffers(page, root->fs_info->sb->s_blocksize, | 188 | create_empty_buffers(page, root->fs_info->sb->s_blocksize, |
@@ -259,10 +261,13 @@ static int __setup_root(int blocksize, | |||
259 | u64 objectid) | 261 | u64 objectid) |
260 | { | 262 | { |
261 | root->node = NULL; | 263 | root->node = NULL; |
264 | root->inode = NULL; | ||
262 | root->commit_root = NULL; | 265 | root->commit_root = NULL; |
263 | root->blocksize = blocksize; | 266 | root->blocksize = blocksize; |
264 | root->ref_cows = 0; | 267 | root->ref_cows = 0; |
265 | root->fs_info = fs_info; | 268 | root->fs_info = fs_info; |
269 | root->objectid = objectid; | ||
270 | root->last_trans = 0; | ||
266 | memset(&root->root_key, 0, sizeof(root->root_key)); | 271 | memset(&root->root_key, 0, sizeof(root->root_key)); |
267 | memset(&root->root_item, 0, sizeof(root->root_item)); | 272 | memset(&root->root_item, 0, sizeof(root->root_item)); |
268 | return 0; | 273 | return 0; |
@@ -287,10 +292,78 @@ static int find_and_setup_root(int blocksize, | |||
287 | return 0; | 292 | return 0; |
288 | } | 293 | } |
289 | 294 | ||
295 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | ||
296 | struct btrfs_key *location) | ||
297 | { | ||
298 | struct btrfs_root *root; | ||
299 | struct btrfs_root *tree_root = fs_info->tree_root; | ||
300 | struct btrfs_path *path; | ||
301 | struct btrfs_leaf *l; | ||
302 | int ret = 0; | ||
303 | |||
304 | printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags); | ||
305 | root = kmalloc(sizeof(*root), GFP_NOFS); | ||
306 | if (!root) { | ||
307 | printk("failed1\n"); | ||
308 | return ERR_PTR(-ENOMEM); | ||
309 | } | ||
310 | if (location->offset == (u64)-1) { | ||
311 | ret = find_and_setup_root(fs_info->sb->s_blocksize, | ||
312 | fs_info->tree_root, fs_info, | ||
313 | location->objectid, root); | ||
314 | if (ret) { | ||
315 | printk("failed2\n"); | ||
316 | kfree(root); | ||
317 | return ERR_PTR(ret); | ||
318 | } | ||
319 | goto insert; | ||
320 | } | ||
321 | |||
322 | __setup_root(fs_info->sb->s_blocksize, root, fs_info, | ||
323 | location->objectid); | ||
324 | |||
325 | path = btrfs_alloc_path(); | ||
326 | BUG_ON(!path); | ||
327 | ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); | ||
328 | if (ret != 0) { | ||
329 | printk("internal search_slot gives us %d\n", ret); | ||
330 | if (ret > 0) | ||
331 | ret = -ENOENT; | ||
332 | goto out; | ||
333 | } | ||
334 | l = btrfs_buffer_leaf(path->nodes[0]); | ||
335 | memcpy(&root->root_item, | ||
336 | btrfs_item_ptr(l, path->slots[0], struct btrfs_root_item), | ||
337 | sizeof(root->root_item)); | ||
338 | memcpy(&root->root_key, location, sizeof(*location)); | ||
339 | ret = 0; | ||
340 | out: | ||
341 | btrfs_release_path(root, path); | ||
342 | btrfs_free_path(path); | ||
343 | if (ret) { | ||
344 | kfree(root); | ||
345 | return ERR_PTR(ret); | ||
346 | } | ||
347 | root->node = read_tree_block(root, | ||
348 | btrfs_root_blocknr(&root->root_item)); | ||
349 | BUG_ON(!root->node); | ||
350 | insert: | ||
351 | printk("inserting %p\n", root); | ||
352 | root->ref_cows = 1; | ||
353 | ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root, | ||
354 | root); | ||
355 | if (ret) { | ||
356 | printk("radix_tree_insert gives us %d\n", ret); | ||
357 | brelse(root->node); | ||
358 | kfree(root); | ||
359 | return ERR_PTR(ret); | ||
360 | } | ||
361 | printk("all worked\n"); | ||
362 | return root; | ||
363 | } | ||
364 | |||
290 | struct btrfs_root *open_ctree(struct super_block *sb) | 365 | struct btrfs_root *open_ctree(struct super_block *sb) |
291 | { | 366 | { |
292 | struct btrfs_root *root = kmalloc(sizeof(struct btrfs_root), | ||
293 | GFP_NOFS); | ||
294 | struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), | 367 | struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), |
295 | GFP_NOFS); | 368 | GFP_NOFS); |
296 | struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), | 369 | struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), |
@@ -304,9 +377,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
304 | 377 | ||
305 | init_bit_radix(&fs_info->pinned_radix); | 378 | init_bit_radix(&fs_info->pinned_radix); |
306 | init_bit_radix(&fs_info->pending_del_radix); | 379 | init_bit_radix(&fs_info->pending_del_radix); |
380 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); | ||
307 | sb_set_blocksize(sb, 4096); | 381 | sb_set_blocksize(sb, 4096); |
308 | fs_info->running_transaction = NULL; | 382 | fs_info->running_transaction = NULL; |
309 | fs_info->fs_root = root; | ||
310 | fs_info->tree_root = tree_root; | 383 | fs_info->tree_root = tree_root; |
311 | fs_info->extent_root = extent_root; | 384 | fs_info->extent_root = extent_root; |
312 | fs_info->inode_root = inode_root; | 385 | fs_info->inode_root = inode_root; |
@@ -318,6 +391,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
318 | fs_info->btree_inode->i_nlink = 1; | 391 | fs_info->btree_inode->i_nlink = 1; |
319 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; | 392 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; |
320 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; | 393 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; |
394 | BTRFS_I(fs_info->btree_inode)->root = tree_root; | ||
395 | memset(&BTRFS_I(fs_info->btree_inode)->location, 0, | ||
396 | sizeof(struct btrfs_key)); | ||
321 | insert_inode_hash(fs_info->btree_inode); | 397 | insert_inode_hash(fs_info->btree_inode); |
322 | mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); | 398 | mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); |
323 | fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); | 399 | fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); |
@@ -337,13 +413,12 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
337 | BTRFS_SUPER_INFO_OFFSET / | 413 | BTRFS_SUPER_INFO_OFFSET / |
338 | sb->s_blocksize); | 414 | sb->s_blocksize); |
339 | 415 | ||
340 | if (!fs_info->sb_buffer) { | 416 | if (!fs_info->sb_buffer) |
341 | return NULL; | 417 | return NULL; |
342 | } | ||
343 | disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data; | 418 | disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data; |
344 | if (!btrfs_super_root(disk_super)) { | 419 | if (!btrfs_super_root(disk_super)) |
345 | return NULL; | 420 | return NULL; |
346 | } | 421 | |
347 | fs_info->disk_super = disk_super; | 422 | fs_info->disk_super = disk_super; |
348 | tree_root->node = read_tree_block(tree_root, | 423 | tree_root->node = read_tree_block(tree_root, |
349 | btrfs_super_root(disk_super)); | 424 | btrfs_super_root(disk_super)); |
@@ -358,14 +433,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
358 | BTRFS_INODE_MAP_OBJECTID, inode_root); | 433 | BTRFS_INODE_MAP_OBJECTID, inode_root); |
359 | BUG_ON(ret); | 434 | BUG_ON(ret); |
360 | 435 | ||
361 | ret = find_and_setup_root(sb->s_blocksize, tree_root, fs_info, | 436 | fs_info->generation = btrfs_super_generation(disk_super) + 1; |
362 | BTRFS_FS_TREE_OBJECTID, root); | 437 | ret = btrfs_find_highest_inode(tree_root, &fs_info->last_inode_alloc); |
363 | BUG_ON(ret); | ||
364 | root->commit_root = root->node; | ||
365 | get_bh(root->node); | ||
366 | root->ref_cows = 1; | ||
367 | root->fs_info->generation = root->root_key.offset + 1; | ||
368 | ret = btrfs_find_highest_inode(root, &root->fs_info->last_inode_alloc); | ||
369 | if (ret == 0) | 438 | if (ret == 0) |
370 | fs_info->highest_inode = fs_info->last_inode_alloc; | 439 | fs_info->highest_inode = fs_info->last_inode_alloc; |
371 | memset(&fs_info->kobj, 0, sizeof(fs_info->kobj)); | 440 | memset(&fs_info->kobj, 0, sizeof(fs_info->kobj)); |
@@ -373,7 +442,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
373 | kobject_set_name(&fs_info->kobj, "%s", sb->s_id); | 442 | kobject_set_name(&fs_info->kobj, "%s", sb->s_id); |
374 | kobject_register(&fs_info->kobj); | 443 | kobject_register(&fs_info->kobj); |
375 | mutex_unlock(&fs_info->fs_mutex); | 444 | mutex_unlock(&fs_info->fs_mutex); |
376 | return root; | 445 | return tree_root; |
377 | } | 446 | } |
378 | 447 | ||
379 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | 448 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root |
@@ -398,12 +467,42 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
398 | return 0; | 467 | return 0; |
399 | } | 468 | } |
400 | 469 | ||
470 | int del_fs_roots(struct btrfs_fs_info *fs_info) | ||
471 | { | ||
472 | int ret; | ||
473 | struct btrfs_root *gang[8]; | ||
474 | int i; | ||
475 | |||
476 | while(1) { | ||
477 | ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, | ||
478 | (void **)gang, 0, | ||
479 | ARRAY_SIZE(gang)); | ||
480 | if (!ret) | ||
481 | break; | ||
482 | for (i = 0; i < ret; i++) { | ||
483 | radix_tree_delete(&fs_info->fs_roots_radix, | ||
484 | (unsigned long)gang[i]); | ||
485 | if (gang[i]->inode) | ||
486 | iput(gang[i]->inode); | ||
487 | else | ||
488 | printk("no inode for root %p\n", gang[i]); | ||
489 | if (gang[i]->node) | ||
490 | brelse(gang[i]->node); | ||
491 | if (gang[i]->commit_root) | ||
492 | brelse(gang[i]->commit_root); | ||
493 | kfree(gang[i]); | ||
494 | } | ||
495 | } | ||
496 | return 0; | ||
497 | } | ||
498 | |||
401 | int close_ctree(struct btrfs_root *root) | 499 | int close_ctree(struct btrfs_root *root) |
402 | { | 500 | { |
403 | int ret; | 501 | int ret; |
404 | struct btrfs_trans_handle *trans; | 502 | struct btrfs_trans_handle *trans; |
503 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
405 | 504 | ||
406 | mutex_lock(&root->fs_info->fs_mutex); | 505 | mutex_lock(&fs_info->fs_mutex); |
407 | trans = btrfs_start_transaction(root, 1); | 506 | trans = btrfs_start_transaction(root, 1); |
408 | btrfs_commit_transaction(trans, root); | 507 | btrfs_commit_transaction(trans, root); |
409 | /* run commit again to drop the original snapshot */ | 508 | /* run commit again to drop the original snapshot */ |
@@ -412,29 +511,26 @@ int close_ctree(struct btrfs_root *root) | |||
412 | ret = btrfs_write_and_wait_transaction(NULL, root); | 511 | ret = btrfs_write_and_wait_transaction(NULL, root); |
413 | BUG_ON(ret); | 512 | BUG_ON(ret); |
414 | write_ctree_super(NULL, root); | 513 | write_ctree_super(NULL, root); |
415 | mutex_unlock(&root->fs_info->fs_mutex); | 514 | mutex_unlock(&fs_info->fs_mutex); |
416 | 515 | ||
417 | if (root->node) | 516 | if (fs_info->extent_root->node) |
418 | btrfs_block_release(root, root->node); | 517 | btrfs_block_release(fs_info->extent_root, |
419 | if (root->fs_info->extent_root->node) | 518 | fs_info->extent_root->node); |
420 | btrfs_block_release(root->fs_info->extent_root, | 519 | if (fs_info->inode_root->node) |
421 | root->fs_info->extent_root->node); | 520 | btrfs_block_release(fs_info->inode_root, |
422 | if (root->fs_info->inode_root->node) | 521 | fs_info->inode_root->node); |
423 | btrfs_block_release(root->fs_info->inode_root, | 522 | if (fs_info->tree_root->node) |
424 | root->fs_info->inode_root->node); | 523 | btrfs_block_release(fs_info->tree_root, |
425 | if (root->fs_info->tree_root->node) | 524 | fs_info->tree_root->node); |
426 | btrfs_block_release(root->fs_info->tree_root, | 525 | btrfs_block_release(root, fs_info->sb_buffer); |
427 | root->fs_info->tree_root->node); | 526 | crypto_free_hash(fs_info->hash_tfm); |
428 | btrfs_block_release(root, root->commit_root); | 527 | truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); |
429 | btrfs_block_release(root, root->fs_info->sb_buffer); | 528 | iput(fs_info->btree_inode); |
430 | crypto_free_hash(root->fs_info->hash_tfm); | 529 | del_fs_roots(fs_info); |
431 | truncate_inode_pages(root->fs_info->btree_inode->i_mapping, 0); | 530 | kfree(fs_info->extent_root); |
432 | iput(root->fs_info->btree_inode); | 531 | kfree(fs_info->inode_root); |
433 | kfree(root->fs_info->extent_root); | 532 | kfree(fs_info->tree_root); |
434 | kfree(root->fs_info->inode_root); | 533 | kobject_unregister(&fs_info->kobj); |
435 | kfree(root->fs_info->tree_root); | ||
436 | kobject_unregister(&root->fs_info->kobj); | ||
437 | kfree(root); | ||
438 | return 0; | 534 | return 0; |
439 | } | 535 | } |
440 | 536 | ||
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index ac6764ba8aa6..0ef6e6f714af 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -39,4 +39,6 @@ int write_ctree_super(struct btrfs_trans_handle *trans, | |||
39 | struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr); | 39 | struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr); |
40 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | 40 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, |
41 | char *result); | 41 | char *result); |
42 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | ||
43 | struct btrfs_key *location); | ||
42 | #endif | 44 | #endif |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 66d9fb2288c3..3c9236ca889c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -436,7 +436,6 @@ int fixup_tree_root_location(struct btrfs_root *root, | |||
436 | { | 436 | { |
437 | struct btrfs_path *path; | 437 | struct btrfs_path *path; |
438 | struct btrfs_root_item *ri; | 438 | struct btrfs_root_item *ri; |
439 | int ret; | ||
440 | 439 | ||
441 | if (btrfs_key_type(location) != BTRFS_ROOT_ITEM_KEY) | 440 | if (btrfs_key_type(location) != BTRFS_ROOT_ITEM_KEY) |
442 | return 0; | 441 | return 0; |
@@ -447,22 +446,19 @@ int fixup_tree_root_location(struct btrfs_root *root, | |||
447 | BUG_ON(!path); | 446 | BUG_ON(!path); |
448 | mutex_lock(&root->fs_info->fs_mutex); | 447 | mutex_lock(&root->fs_info->fs_mutex); |
449 | 448 | ||
450 | ret = btrfs_lookup_inode(NULL, root, path, location, 0); | 449 | *sub_root = btrfs_read_fs_root(root->fs_info, location); |
451 | if (ret) | 450 | if (IS_ERR(*sub_root)) |
452 | goto out; | 451 | return PTR_ERR(*sub_root); |
453 | ri = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), | 452 | |
454 | path->slots[0], | 453 | ri = &(*sub_root)->root_item; |
455 | struct btrfs_root_item); | ||
456 | location->objectid = btrfs_root_dirid(ri); | 454 | location->objectid = btrfs_root_dirid(ri); |
457 | location->flags = 0; | 455 | location->flags = 0; |
458 | btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); | 456 | btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); |
459 | location->offset = 0; | 457 | location->offset = 0; |
460 | /* FIXME properly select the root */ | 458 | |
461 | *sub_root = root->fs_info->fs_root; | ||
462 | out: | ||
463 | btrfs_free_path(path); | 459 | btrfs_free_path(path); |
464 | mutex_unlock(&root->fs_info->fs_mutex); | 460 | mutex_unlock(&root->fs_info->fs_mutex); |
465 | return ret; | 461 | return 0; |
466 | } | 462 | } |
467 | 463 | ||
468 | 464 | ||
@@ -494,6 +490,15 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
494 | if (!inode) | 490 | if (!inode) |
495 | return ERR_PTR(-EACCES); | 491 | return ERR_PTR(-EACCES); |
496 | if (inode->i_state & I_NEW) { | 492 | if (inode->i_state & I_NEW) { |
493 | if (sub_root != root) { | ||
494 | ret = radix_tree_insert( | ||
495 | &root->fs_info->fs_roots_radix, | ||
496 | (unsigned long)sub_root, | ||
497 | sub_root); | ||
498 | printk("adding new root for inode %lu\n", inode->i_ino); | ||
499 | igrab(inode); | ||
500 | sub_root->inode = inode; | ||
501 | } | ||
497 | BTRFS_I(inode)->root = sub_root; | 502 | BTRFS_I(inode)->root = sub_root; |
498 | memcpy(&BTRFS_I(inode)->location, &location, | 503 | memcpy(&BTRFS_I(inode)->location, &location, |
499 | sizeof(location)); | 504 | sizeof(location)); |
@@ -605,7 +610,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
605 | struct inode * inode; | 610 | struct inode * inode; |
606 | struct dentry * root_dentry; | 611 | struct dentry * root_dentry; |
607 | struct btrfs_super_block *disk_super; | 612 | struct btrfs_super_block *disk_super; |
608 | struct btrfs_root *root; | 613 | struct btrfs_root *tree_root; |
609 | struct btrfs_inode *bi; | 614 | struct btrfs_inode *bi; |
610 | 615 | ||
611 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 616 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
@@ -613,14 +618,14 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
613 | sb->s_op = &btrfs_super_ops; | 618 | sb->s_op = &btrfs_super_ops; |
614 | sb->s_time_gran = 1; | 619 | sb->s_time_gran = 1; |
615 | 620 | ||
616 | root = open_ctree(sb); | 621 | tree_root = open_ctree(sb); |
617 | 622 | ||
618 | if (!root) { | 623 | if (!tree_root) { |
619 | printk("btrfs: open_ctree failed\n"); | 624 | printk("btrfs: open_ctree failed\n"); |
620 | return -EIO; | 625 | return -EIO; |
621 | } | 626 | } |
622 | sb->s_fs_info = root; | 627 | sb->s_fs_info = tree_root; |
623 | disk_super = root->fs_info->disk_super; | 628 | disk_super = tree_root->fs_info->disk_super; |
624 | printk("read in super total blocks %Lu root %Lu\n", | 629 | printk("read in super total blocks %Lu root %Lu\n", |
625 | btrfs_super_total_blocks(disk_super), | 630 | btrfs_super_total_blocks(disk_super), |
626 | btrfs_super_root_dir(disk_super)); | 631 | btrfs_super_root_dir(disk_super)); |
@@ -630,7 +635,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
630 | bi->location.objectid = inode->i_ino; | 635 | bi->location.objectid = inode->i_ino; |
631 | bi->location.offset = 0; | 636 | bi->location.offset = 0; |
632 | bi->location.flags = 0; | 637 | bi->location.flags = 0; |
633 | bi->root = root->fs_info->tree_root; | 638 | bi->root = tree_root; |
634 | btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); | 639 | btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); |
635 | 640 | ||
636 | if (!inode) | 641 | if (!inode) |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 20d84bd03223..83a0194ab163 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -8,6 +8,8 @@ static int total_trans = 0; | |||
8 | extern struct kmem_cache *btrfs_trans_handle_cachep; | 8 | extern struct kmem_cache *btrfs_trans_handle_cachep; |
9 | extern struct kmem_cache *btrfs_transaction_cachep; | 9 | extern struct kmem_cache *btrfs_transaction_cachep; |
10 | 10 | ||
11 | #define BTRFS_ROOT_TRANS_TAG 0 | ||
12 | |||
11 | #define TRANS_MAGIC 0xE1E10E | 13 | #define TRANS_MAGIC 0xE1E10E |
12 | static void put_transaction(struct btrfs_transaction *transaction) | 14 | static void put_transaction(struct btrfs_transaction *transaction) |
13 | { | 15 | { |
@@ -31,9 +33,10 @@ static int join_transaction(struct btrfs_root *root) | |||
31 | GFP_NOFS); | 33 | GFP_NOFS); |
32 | total_trans++; | 34 | total_trans++; |
33 | BUG_ON(!cur_trans); | 35 | BUG_ON(!cur_trans); |
36 | root->fs_info->generation++; | ||
34 | root->fs_info->running_transaction = cur_trans; | 37 | root->fs_info->running_transaction = cur_trans; |
35 | cur_trans->num_writers = 0; | 38 | cur_trans->num_writers = 0; |
36 | cur_trans->transid = root->root_key.offset + 1; | 39 | cur_trans->transid = root->fs_info->generation; |
37 | init_waitqueue_head(&cur_trans->writer_wait); | 40 | init_waitqueue_head(&cur_trans->writer_wait); |
38 | init_waitqueue_head(&cur_trans->commit_wait); | 41 | init_waitqueue_head(&cur_trans->commit_wait); |
39 | cur_trans->magic = TRANS_MAGIC; | 42 | cur_trans->magic = TRANS_MAGIC; |
@@ -51,13 +54,22 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
51 | struct btrfs_trans_handle *h = | 54 | struct btrfs_trans_handle *h = |
52 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 55 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
53 | int ret; | 56 | int ret; |
57 | u64 running_trans_id; | ||
54 | 58 | ||
55 | /* FIXME, use the right root */ | ||
56 | root = root->fs_info->fs_root; | ||
57 | mutex_lock(&root->fs_info->trans_mutex); | 59 | mutex_lock(&root->fs_info->trans_mutex); |
58 | ret = join_transaction(root); | 60 | ret = join_transaction(root); |
59 | BUG_ON(ret); | 61 | BUG_ON(ret); |
60 | h->transid = root->fs_info->running_transaction->transid; | 62 | running_trans_id = root->fs_info->running_transaction->transid; |
63 | |||
64 | if (root != root->fs_info->tree_root && root->last_trans < | ||
65 | running_trans_id) { | ||
66 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | ||
67 | (unsigned long)root, BTRFS_ROOT_TRANS_TAG); | ||
68 | root->commit_root = root->node; | ||
69 | get_bh(root->node); | ||
70 | } | ||
71 | root->last_trans = running_trans_id; | ||
72 | h->transid = running_trans_id; | ||
61 | h->transaction = root->fs_info->running_transaction; | 73 | h->transaction = root->fs_info->running_transaction; |
62 | h->blocks_reserved = num_blocks; | 74 | h->blocks_reserved = num_blocks; |
63 | h->blocks_used = 0; | 75 | h->blocks_used = 0; |
@@ -72,9 +84,6 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
72 | { | 84 | { |
73 | struct btrfs_transaction *cur_trans; | 85 | struct btrfs_transaction *cur_trans; |
74 | 86 | ||
75 | /* FIXME, use the right root */ | ||
76 | root = root->fs_info->fs_root; | ||
77 | |||
78 | WARN_ON(trans->magic != TRANS_MAGIC); | 87 | WARN_ON(trans->magic != TRANS_MAGIC); |
79 | WARN_ON(trans->magic2 != TRANS_MAGIC); | 88 | WARN_ON(trans->magic2 != TRANS_MAGIC); |
80 | mutex_lock(&root->fs_info->trans_mutex); | 89 | mutex_lock(&root->fs_info->trans_mutex); |
@@ -145,17 +154,96 @@ static int wait_for_commit(struct btrfs_root *root, | |||
145 | return 0; | 154 | return 0; |
146 | } | 155 | } |
147 | 156 | ||
157 | struct dirty_root { | ||
158 | struct list_head list; | ||
159 | struct btrfs_key snap_key; | ||
160 | struct buffer_head *commit_root; | ||
161 | struct btrfs_root *root; | ||
162 | }; | ||
163 | |||
164 | int add_dirty_roots(struct btrfs_trans_handle *trans, | ||
165 | struct radix_tree_root *radix, struct list_head *list) | ||
166 | { | ||
167 | struct dirty_root *dirty; | ||
168 | struct btrfs_root *gang[8]; | ||
169 | struct btrfs_root *root; | ||
170 | int i; | ||
171 | int ret; | ||
172 | int err; | ||
173 | printk("add dirty\n"); | ||
174 | while(1) { | ||
175 | ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0, | ||
176 | ARRAY_SIZE(gang), | ||
177 | BTRFS_ROOT_TRANS_TAG); | ||
178 | if (ret == 0) | ||
179 | break; | ||
180 | for (i = 0; i < ret; i++) { | ||
181 | root = gang[i]; | ||
182 | radix_tree_tag_clear(radix, (unsigned long)root, | ||
183 | BTRFS_ROOT_TRANS_TAG); | ||
184 | if (root->commit_root == root->node) { | ||
185 | WARN_ON(root->node->b_blocknr != | ||
186 | btrfs_root_blocknr(&root->root_item)); | ||
187 | brelse(root->commit_root); | ||
188 | root->commit_root = NULL; | ||
189 | continue; | ||
190 | } | ||
191 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | ||
192 | BUG_ON(!dirty); | ||
193 | memcpy(&dirty->snap_key, &root->root_key, | ||
194 | sizeof(root->root_key)); | ||
195 | dirty->commit_root = root->commit_root; | ||
196 | root->commit_root = NULL; | ||
197 | dirty->root = root; | ||
198 | printk("adding dirty root %Lu gen %Lu blocknr %Lu\n", root->root_key.objectid, root->root_key.offset, dirty->commit_root->b_blocknr); | ||
199 | root->root_key.offset = root->fs_info->generation; | ||
200 | btrfs_set_root_blocknr(&root->root_item, | ||
201 | root->node->b_blocknr); | ||
202 | err = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
203 | &root->root_key, | ||
204 | &root->root_item); | ||
205 | BUG_ON(err); | ||
206 | list_add(&dirty->list, list); | ||
207 | } | ||
208 | } | ||
209 | printk("add dirty done\n"); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int drop_dirty_roots(struct btrfs_root *tree_root, struct list_head *list) | ||
214 | { | ||
215 | struct dirty_root *dirty; | ||
216 | struct btrfs_trans_handle *trans; | ||
217 | int ret; | ||
218 | |||
219 | while(!list_empty(list)) { | ||
220 | dirty = list_entry(list->next, struct dirty_root, list); | ||
221 | list_del_init(&dirty->list); | ||
222 | trans = btrfs_start_transaction(tree_root, 1); | ||
223 | printk("drop snapshot root %p, commit_root blocknr %Lu generation %Lu\n", dirty->root, dirty->commit_root->b_blocknr, dirty->snap_key.offset); | ||
224 | ret = btrfs_drop_snapshot(trans, dirty->root, | ||
225 | dirty->commit_root); | ||
226 | BUG_ON(ret); | ||
227 | |||
228 | printk("del root objectid %Lu, offset %Lu\n", dirty->snap_key.objectid, dirty->snap_key.offset); | ||
229 | ret = btrfs_del_root(trans, tree_root, &dirty->snap_key); | ||
230 | BUG_ON(ret); | ||
231 | ret = btrfs_end_transaction(trans, tree_root); | ||
232 | BUG_ON(ret); | ||
233 | kfree(dirty); | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
148 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 238 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
149 | struct btrfs_root *root) | 239 | struct btrfs_root *root) |
150 | { | 240 | { |
151 | int ret = 0; | 241 | int ret = 0; |
152 | struct buffer_head *snap; | ||
153 | struct btrfs_key snap_key; | ||
154 | struct btrfs_transaction *cur_trans; | 242 | struct btrfs_transaction *cur_trans; |
243 | struct list_head dirty_fs_roots; | ||
155 | DEFINE_WAIT(wait); | 244 | DEFINE_WAIT(wait); |
156 | 245 | ||
157 | /* FIXME, use the right root */ | 246 | INIT_LIST_HEAD(&dirty_fs_roots); |
158 | root = root->fs_info->fs_root; | ||
159 | 247 | ||
160 | mutex_lock(&root->fs_info->trans_mutex); | 248 | mutex_lock(&root->fs_info->trans_mutex); |
161 | if (trans->transaction->in_commit) { | 249 | if (trans->transaction->in_commit) { |
@@ -184,22 +272,13 @@ printk("already in commit!, waiting\n"); | |||
184 | } | 272 | } |
185 | finish_wait(&trans->transaction->writer_wait, &wait); | 273 | finish_wait(&trans->transaction->writer_wait, &wait); |
186 | WARN_ON(cur_trans != trans->transaction); | 274 | WARN_ON(cur_trans != trans->transaction); |
187 | if (root->node != root->commit_root) { | 275 | add_dirty_roots(trans, &root->fs_info->fs_roots_radix, &dirty_fs_roots); |
188 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | ||
189 | root->root_key.offset++; | ||
190 | } | ||
191 | |||
192 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { | ||
193 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | ||
194 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
195 | &root->root_key, &root->root_item); | ||
196 | BUG_ON(ret); | ||
197 | } | ||
198 | |||
199 | ret = btrfs_commit_tree_roots(trans, root); | 276 | ret = btrfs_commit_tree_roots(trans, root); |
200 | BUG_ON(ret); | 277 | BUG_ON(ret); |
201 | cur_trans = root->fs_info->running_transaction; | 278 | cur_trans = root->fs_info->running_transaction; |
202 | root->fs_info->running_transaction = NULL; | 279 | root->fs_info->running_transaction = NULL; |
280 | btrfs_set_super_generation(root->fs_info->disk_super, | ||
281 | root->fs_info->generation + 1); | ||
203 | mutex_unlock(&root->fs_info->trans_mutex); | 282 | mutex_unlock(&root->fs_info->trans_mutex); |
204 | ret = btrfs_write_and_wait_transaction(trans, root); | 283 | ret = btrfs_write_and_wait_transaction(trans, root); |
205 | BUG_ON(ret); | 284 | BUG_ON(ret); |
@@ -213,21 +292,8 @@ printk("already in commit!, waiting\n"); | |||
213 | put_transaction(cur_trans); | 292 | put_transaction(cur_trans); |
214 | mutex_unlock(&root->fs_info->trans_mutex); | 293 | mutex_unlock(&root->fs_info->trans_mutex); |
215 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 294 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
216 | if (root->node != root->commit_root) { | ||
217 | trans = btrfs_start_transaction(root, 1); | ||
218 | snap = root->commit_root; | ||
219 | root->commit_root = root->node; | ||
220 | get_bh(root->node); | ||
221 | ret = btrfs_drop_snapshot(trans, root, snap); | ||
222 | BUG_ON(ret); | ||
223 | 295 | ||
224 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | 296 | drop_dirty_roots(root->fs_info->tree_root, &dirty_fs_roots); |
225 | &snap_key); | ||
226 | BUG_ON(ret); | ||
227 | root->fs_info->generation = root->root_key.offset + 1; | ||
228 | ret = btrfs_end_transaction(trans, root); | ||
229 | BUG_ON(ret); | ||
230 | } | ||
231 | return ret; | 297 | return ret; |
232 | } | 298 | } |
233 | 299 | ||