diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 178 |
1 files changed, 137 insertions, 41 deletions
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 | ||