1e20d96d6SChris Mason #include <linux/module.h> 2e20d96d6SChris Mason #include <linux/fs.h> 3d98237b3SChris Mason #include <linux/blkdev.h> 487cbda5cSChris Mason #include <linux/crypto.h> 587cbda5cSChris Mason #include <linux/scatterlist.h> 622b0ebdaSChris Mason #include <linux/swap.h> 70f7d52f4SChris Mason #include <linux/radix-tree.h> 8eb60ceacSChris Mason #include "ctree.h" 9eb60ceacSChris Mason #include "disk-io.h" 10e089f05cSChris Mason #include "transaction.h" 110f7d52f4SChris Mason #include "btrfs_inode.h" 12eb60ceacSChris Mason 13e20d96d6SChris Mason static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) 14eb60ceacSChris Mason { 15e20d96d6SChris Mason struct btrfs_node *node = btrfs_buffer_node(buf); 16d98237b3SChris Mason if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) { 179a8dd150SChris Mason BUG(); 18d98237b3SChris Mason } 199a8dd150SChris Mason return 0; 20eb60ceacSChris Mason } 21eb60ceacSChris Mason 22d98237b3SChris Mason struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr) 23ed2ff2cbSChris Mason { 24d98237b3SChris Mason struct address_space *mapping = root->fs_info->btree_inode->i_mapping; 25d98237b3SChris Mason int blockbits = root->fs_info->sb->s_blocksize_bits; 26d98237b3SChris Mason unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits); 27d98237b3SChris Mason struct page *page; 28d98237b3SChris Mason struct buffer_head *bh; 29d98237b3SChris Mason struct buffer_head *head; 30d98237b3SChris Mason struct buffer_head *ret = NULL; 31d98237b3SChris Mason 322c90e5d6SChris Mason 33d98237b3SChris Mason page = find_lock_page(mapping, index); 34d98237b3SChris Mason if (!page) 35d98237b3SChris Mason return NULL; 36d98237b3SChris Mason 37d98237b3SChris Mason if (!page_has_buffers(page)) 38d98237b3SChris Mason goto out_unlock; 39d98237b3SChris Mason 40d98237b3SChris Mason head = page_buffers(page); 41d98237b3SChris Mason bh = head; 42d98237b3SChris Mason do { 43d98237b3SChris Mason if (buffer_mapped(bh) && bh->b_blocknr == blocknr) { 44d98237b3SChris Mason ret = bh; 45d98237b3SChris Mason get_bh(bh); 46d98237b3SChris Mason goto out_unlock; 47d98237b3SChris Mason } 48d98237b3SChris Mason bh = bh->b_this_page; 49d98237b3SChris Mason } while (bh != head); 50d98237b3SChris Mason out_unlock: 51d98237b3SChris Mason unlock_page(page); 52d6025579SChris Mason if (ret) { 5322b0ebdaSChris Mason touch_buffer(ret); 54d6025579SChris Mason } 55d98237b3SChris Mason page_cache_release(page); 56d98237b3SChris Mason return ret; 57ed2ff2cbSChris Mason } 58ed2ff2cbSChris Mason 59d98237b3SChris Mason struct buffer_head *btrfs_find_create_tree_block(struct btrfs_root *root, 60d98237b3SChris Mason u64 blocknr) 61eb60ceacSChris Mason { 62d98237b3SChris Mason struct address_space *mapping = root->fs_info->btree_inode->i_mapping; 63d98237b3SChris Mason int blockbits = root->fs_info->sb->s_blocksize_bits; 64d98237b3SChris Mason unsigned long index = blocknr >> (PAGE_CACHE_SHIFT - blockbits); 65d98237b3SChris Mason struct page *page; 66d98237b3SChris Mason struct buffer_head *bh; 67d98237b3SChris Mason struct buffer_head *head; 68d98237b3SChris Mason struct buffer_head *ret = NULL; 69d98237b3SChris Mason u64 first_block = index << (PAGE_CACHE_SHIFT - blockbits); 7022b0ebdaSChris Mason 71d98237b3SChris Mason page = grab_cache_page(mapping, index); 72d98237b3SChris Mason if (!page) 73d98237b3SChris Mason return NULL; 74d98237b3SChris Mason 75d98237b3SChris Mason if (!page_has_buffers(page)) 76d98237b3SChris Mason create_empty_buffers(page, root->fs_info->sb->s_blocksize, 0); 77d98237b3SChris Mason head = page_buffers(page); 78d98237b3SChris Mason bh = head; 79d98237b3SChris Mason do { 80d98237b3SChris Mason if (!buffer_mapped(bh)) { 81d98237b3SChris Mason bh->b_bdev = root->fs_info->sb->s_bdev; 82d98237b3SChris Mason bh->b_blocknr = first_block; 83d98237b3SChris Mason set_buffer_mapped(bh); 84e20d96d6SChris Mason } 85d98237b3SChris Mason if (bh->b_blocknr == blocknr) { 86d98237b3SChris Mason ret = bh; 87d98237b3SChris Mason get_bh(bh); 88d98237b3SChris Mason goto out_unlock; 89d98237b3SChris Mason } 90d98237b3SChris Mason bh = bh->b_this_page; 91d98237b3SChris Mason first_block++; 92d98237b3SChris Mason } while (bh != head); 93d98237b3SChris Mason out_unlock: 94d98237b3SChris Mason unlock_page(page); 9522b0ebdaSChris Mason if (ret) 9622b0ebdaSChris Mason touch_buffer(ret); 97d98237b3SChris Mason page_cache_release(page); 98d98237b3SChris Mason return ret; 99d98237b3SChris Mason } 100d98237b3SChris Mason 101d98237b3SChris Mason static sector_t max_block(struct block_device *bdev) 102d98237b3SChris Mason { 103d98237b3SChris Mason sector_t retval = ~((sector_t)0); 104d98237b3SChris Mason loff_t sz = i_size_read(bdev->bd_inode); 105d98237b3SChris Mason 106d98237b3SChris Mason if (sz) { 107d98237b3SChris Mason unsigned int size = block_size(bdev); 108d98237b3SChris Mason unsigned int sizebits = blksize_bits(size); 109d98237b3SChris Mason retval = (sz >> sizebits); 110d98237b3SChris Mason } 111d98237b3SChris Mason return retval; 112d98237b3SChris Mason } 113d98237b3SChris Mason 114d98237b3SChris Mason static int btree_get_block(struct inode *inode, sector_t iblock, 115d98237b3SChris Mason struct buffer_head *bh, int create) 116d98237b3SChris Mason { 117d98237b3SChris Mason if (iblock >= max_block(inode->i_sb->s_bdev)) { 118d98237b3SChris Mason if (create) 119d98237b3SChris Mason return -EIO; 120d98237b3SChris Mason 121d98237b3SChris Mason /* 122d98237b3SChris Mason * for reads, we're just trying to fill a partial page. 123d98237b3SChris Mason * return a hole, they will have to call get_block again 124d98237b3SChris Mason * before they can fill it, and they will get -EIO at that 125d98237b3SChris Mason * time 126d98237b3SChris Mason */ 127d98237b3SChris Mason return 0; 128d98237b3SChris Mason } 129d98237b3SChris Mason bh->b_bdev = inode->i_sb->s_bdev; 130d98237b3SChris Mason bh->b_blocknr = iblock; 131d98237b3SChris Mason set_buffer_mapped(bh); 132d98237b3SChris Mason return 0; 133d98237b3SChris Mason } 134d98237b3SChris Mason 135f254e52cSChris Mason int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, 136f254e52cSChris Mason char *result) 13787cbda5cSChris Mason { 13887cbda5cSChris Mason struct scatterlist sg; 13987cbda5cSChris Mason struct crypto_hash *tfm = root->fs_info->hash_tfm; 14087cbda5cSChris Mason struct hash_desc desc; 14187cbda5cSChris Mason int ret; 14287cbda5cSChris Mason 14387cbda5cSChris Mason desc.tfm = tfm; 14487cbda5cSChris Mason desc.flags = 0; 145f254e52cSChris Mason sg_init_one(&sg, data, len); 14687cbda5cSChris Mason spin_lock(&root->fs_info->hash_lock); 14722b0ebdaSChris Mason ret = crypto_hash_digest(&desc, &sg, 1, result); 14887cbda5cSChris Mason spin_unlock(&root->fs_info->hash_lock); 14987cbda5cSChris Mason if (ret) { 15087cbda5cSChris Mason printk("sha256 digest failed\n"); 15187cbda5cSChris Mason } 152f254e52cSChris Mason return ret; 153f254e52cSChris Mason } 154f254e52cSChris Mason static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh, 155f254e52cSChris Mason int verify) 156f254e52cSChris Mason { 157f254e52cSChris Mason char result[BTRFS_CSUM_SIZE]; 158f254e52cSChris Mason int ret; 159f254e52cSChris Mason struct btrfs_node *node; 160f254e52cSChris Mason 161f254e52cSChris Mason ret = btrfs_csum_data(root, bh->b_data + BTRFS_CSUM_SIZE, 162f254e52cSChris Mason bh->b_size - BTRFS_CSUM_SIZE, result); 163f254e52cSChris Mason if (ret) 164f254e52cSChris Mason return ret; 16587cbda5cSChris Mason if (verify) { 166f254e52cSChris Mason if (memcmp(bh->b_data, result, BTRFS_CSUM_SIZE)) { 167f254e52cSChris Mason printk("checksum verify failed on %lu\n", 168f254e52cSChris Mason bh->b_blocknr); 169f254e52cSChris Mason return 1; 170f254e52cSChris Mason } 171f254e52cSChris Mason } else { 172f254e52cSChris Mason node = btrfs_buffer_node(bh); 17322b0ebdaSChris Mason memcpy(node->header.csum, result, BTRFS_CSUM_SIZE); 174f254e52cSChris Mason } 17587cbda5cSChris Mason return 0; 17687cbda5cSChris Mason } 17787cbda5cSChris Mason 178d98237b3SChris Mason static int btree_writepage(struct page *page, struct writeback_control *wbc) 179d98237b3SChris Mason { 18087cbda5cSChris Mason struct buffer_head *bh; 1810f7d52f4SChris Mason struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; 18287cbda5cSChris Mason struct buffer_head *head; 18387cbda5cSChris Mason if (!page_has_buffers(page)) { 18487cbda5cSChris Mason create_empty_buffers(page, root->fs_info->sb->s_blocksize, 18587cbda5cSChris Mason (1 << BH_Dirty)|(1 << BH_Uptodate)); 18687cbda5cSChris Mason } 18787cbda5cSChris Mason head = page_buffers(page); 18887cbda5cSChris Mason bh = head; 18987cbda5cSChris Mason do { 19087cbda5cSChris Mason if (buffer_dirty(bh)) 19187cbda5cSChris Mason csum_tree_block(root, bh, 0); 19287cbda5cSChris Mason bh = bh->b_this_page; 19387cbda5cSChris Mason } while (bh != head); 194d98237b3SChris Mason return block_write_full_page(page, btree_get_block, wbc); 195d98237b3SChris Mason } 196d98237b3SChris Mason 197d98237b3SChris Mason static int btree_readpage(struct file * file, struct page * page) 198d98237b3SChris Mason { 199d98237b3SChris Mason return block_read_full_page(page, btree_get_block); 200d98237b3SChris Mason } 201d98237b3SChris Mason 202d98237b3SChris Mason static struct address_space_operations btree_aops = { 203d98237b3SChris Mason .readpage = btree_readpage, 204d98237b3SChris Mason .writepage = btree_writepage, 205d98237b3SChris Mason .sync_page = block_sync_page, 206d98237b3SChris Mason }; 207123abc88SChris Mason 208e20d96d6SChris Mason struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) 209e20d96d6SChris Mason { 210d98237b3SChris Mason struct buffer_head *bh = NULL; 211e20d96d6SChris Mason 212d98237b3SChris Mason bh = btrfs_find_create_tree_block(root, blocknr); 213d98237b3SChris Mason if (!bh) 214d98237b3SChris Mason return bh; 2159d64272cSChris Mason if (buffer_uptodate(bh)) 2169d64272cSChris Mason goto uptodate; 217d98237b3SChris Mason lock_buffer(bh); 218d98237b3SChris Mason if (!buffer_uptodate(bh)) { 219d98237b3SChris Mason get_bh(bh); 220d98237b3SChris Mason bh->b_end_io = end_buffer_read_sync; 221d98237b3SChris Mason submit_bh(READ, bh); 222d98237b3SChris Mason wait_on_buffer(bh); 223d98237b3SChris Mason if (!buffer_uptodate(bh)) 224d98237b3SChris Mason goto fail; 22587cbda5cSChris Mason csum_tree_block(root, bh, 1); 226d98237b3SChris Mason } else { 227d98237b3SChris Mason unlock_buffer(bh); 228d98237b3SChris Mason } 2299d64272cSChris Mason uptodate: 230d98237b3SChris Mason if (check_tree_block(root, bh)) 231cfaa7295SChris Mason BUG(); 232d98237b3SChris Mason return bh; 233d98237b3SChris Mason fail: 234d98237b3SChris Mason brelse(bh); 235d98237b3SChris Mason return NULL; 236eb60ceacSChris Mason } 237eb60ceacSChris Mason 238e089f05cSChris Mason int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 239e20d96d6SChris Mason struct buffer_head *buf) 240ed2ff2cbSChris Mason { 241d6025579SChris Mason WARN_ON(atomic_read(&buf->b_count) == 0); 242e20d96d6SChris Mason mark_buffer_dirty(buf); 243ed2ff2cbSChris Mason return 0; 244ed2ff2cbSChris Mason } 245ed2ff2cbSChris Mason 246e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 247e20d96d6SChris Mason struct buffer_head *buf) 248ed2ff2cbSChris Mason { 249d6025579SChris Mason WARN_ON(atomic_read(&buf->b_count) == 0); 250e20d96d6SChris Mason clear_buffer_dirty(buf); 251ed2ff2cbSChris Mason return 0; 252ed2ff2cbSChris Mason } 253ed2ff2cbSChris Mason 2542c90e5d6SChris Mason static int __setup_root(int blocksize, 2559f5fae2fSChris Mason struct btrfs_root *root, 2569f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 257e20d96d6SChris Mason u64 objectid) 258d97e63b6SChris Mason { 259cfaa7295SChris Mason root->node = NULL; 2600f7d52f4SChris Mason root->inode = NULL; 261a28ec197SChris Mason root->commit_root = NULL; 2622c90e5d6SChris Mason root->blocksize = blocksize; 263123abc88SChris Mason root->ref_cows = 0; 2649f5fae2fSChris Mason root->fs_info = fs_info; 2650f7d52f4SChris Mason root->objectid = objectid; 2660f7d52f4SChris Mason root->last_trans = 0; 2671b05da2eSChris Mason root->highest_inode = 0; 2681b05da2eSChris Mason root->last_inode_alloc = 0; 2693768f368SChris Mason memset(&root->root_key, 0, sizeof(root->root_key)); 2703768f368SChris Mason memset(&root->root_item, 0, sizeof(root->root_item)); 2713768f368SChris Mason return 0; 2723768f368SChris Mason } 2733768f368SChris Mason 2742c90e5d6SChris Mason static int find_and_setup_root(int blocksize, 2759f5fae2fSChris Mason struct btrfs_root *tree_root, 2769f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 2779f5fae2fSChris Mason u64 objectid, 278e20d96d6SChris Mason struct btrfs_root *root) 2793768f368SChris Mason { 2803768f368SChris Mason int ret; 2813768f368SChris Mason 2822c90e5d6SChris Mason __setup_root(blocksize, root, fs_info, objectid); 2833768f368SChris Mason ret = btrfs_find_last_root(tree_root, objectid, 2843768f368SChris Mason &root->root_item, &root->root_key); 2853768f368SChris Mason BUG_ON(ret); 2863768f368SChris Mason 2873768f368SChris Mason root->node = read_tree_block(root, 2883768f368SChris Mason btrfs_root_blocknr(&root->root_item)); 2893768f368SChris Mason BUG_ON(!root->node); 290d97e63b6SChris Mason return 0; 291d97e63b6SChris Mason } 292d97e63b6SChris Mason 2930f7d52f4SChris Mason struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 2940f7d52f4SChris Mason struct btrfs_key *location) 2950f7d52f4SChris Mason { 2960f7d52f4SChris Mason struct btrfs_root *root; 2970f7d52f4SChris Mason struct btrfs_root *tree_root = fs_info->tree_root; 2980f7d52f4SChris Mason struct btrfs_path *path; 2990f7d52f4SChris Mason struct btrfs_leaf *l; 3001b05da2eSChris Mason u64 highest_inode; 3010f7d52f4SChris Mason int ret = 0; 3020f7d52f4SChris Mason 3030f7d52f4SChris Mason printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags); 3042619ba1fSChris Mason root = radix_tree_lookup(&fs_info->fs_roots_radix, 3052619ba1fSChris Mason (unsigned long)location->objectid); 3062619ba1fSChris Mason if (root) { 3072619ba1fSChris Mason printk("found %p in cache\n", root); 3082619ba1fSChris Mason return root; 3092619ba1fSChris Mason } 3100f7d52f4SChris Mason root = kmalloc(sizeof(*root), GFP_NOFS); 3110f7d52f4SChris Mason if (!root) { 3120f7d52f4SChris Mason printk("failed1\n"); 3130f7d52f4SChris Mason return ERR_PTR(-ENOMEM); 3140f7d52f4SChris Mason } 3150f7d52f4SChris Mason if (location->offset == (u64)-1) { 3160f7d52f4SChris Mason ret = find_and_setup_root(fs_info->sb->s_blocksize, 3170f7d52f4SChris Mason fs_info->tree_root, fs_info, 3180f7d52f4SChris Mason location->objectid, root); 3190f7d52f4SChris Mason if (ret) { 3200f7d52f4SChris Mason printk("failed2\n"); 3210f7d52f4SChris Mason kfree(root); 3220f7d52f4SChris Mason return ERR_PTR(ret); 3230f7d52f4SChris Mason } 3240f7d52f4SChris Mason goto insert; 3250f7d52f4SChris Mason } 3260f7d52f4SChris Mason 3270f7d52f4SChris Mason __setup_root(fs_info->sb->s_blocksize, root, fs_info, 3280f7d52f4SChris Mason location->objectid); 3290f7d52f4SChris Mason 3300f7d52f4SChris Mason path = btrfs_alloc_path(); 3310f7d52f4SChris Mason BUG_ON(!path); 3320f7d52f4SChris Mason ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); 3330f7d52f4SChris Mason if (ret != 0) { 3340f7d52f4SChris Mason printk("internal search_slot gives us %d\n", ret); 3350f7d52f4SChris Mason if (ret > 0) 3360f7d52f4SChris Mason ret = -ENOENT; 3370f7d52f4SChris Mason goto out; 3380f7d52f4SChris Mason } 3390f7d52f4SChris Mason l = btrfs_buffer_leaf(path->nodes[0]); 3400f7d52f4SChris Mason memcpy(&root->root_item, 3410f7d52f4SChris Mason btrfs_item_ptr(l, path->slots[0], struct btrfs_root_item), 3420f7d52f4SChris Mason sizeof(root->root_item)); 3430f7d52f4SChris Mason memcpy(&root->root_key, location, sizeof(*location)); 3440f7d52f4SChris Mason ret = 0; 3450f7d52f4SChris Mason out: 3460f7d52f4SChris Mason btrfs_release_path(root, path); 3470f7d52f4SChris Mason btrfs_free_path(path); 3480f7d52f4SChris Mason if (ret) { 3490f7d52f4SChris Mason kfree(root); 3500f7d52f4SChris Mason return ERR_PTR(ret); 3510f7d52f4SChris Mason } 3520f7d52f4SChris Mason root->node = read_tree_block(root, 3530f7d52f4SChris Mason btrfs_root_blocknr(&root->root_item)); 3540f7d52f4SChris Mason BUG_ON(!root->node); 3550f7d52f4SChris Mason insert: 3560f7d52f4SChris Mason printk("inserting %p\n", root); 3570f7d52f4SChris Mason root->ref_cows = 1; 3582619ba1fSChris Mason ret = radix_tree_insert(&fs_info->fs_roots_radix, 3592619ba1fSChris Mason (unsigned long)root->root_key.objectid, 3600f7d52f4SChris Mason root); 3610f7d52f4SChris Mason if (ret) { 3620f7d52f4SChris Mason printk("radix_tree_insert gives us %d\n", ret); 3630f7d52f4SChris Mason brelse(root->node); 3640f7d52f4SChris Mason kfree(root); 3650f7d52f4SChris Mason return ERR_PTR(ret); 3660f7d52f4SChris Mason } 3671b05da2eSChris Mason ret = btrfs_find_highest_inode(root, &highest_inode); 3681b05da2eSChris Mason if (ret == 0) { 3691b05da2eSChris Mason root->highest_inode = highest_inode; 3701b05da2eSChris Mason root->last_inode_alloc = highest_inode; 3711b05da2eSChris Mason printk("highest inode is %Lu\n", highest_inode); 3721b05da2eSChris Mason } 3730f7d52f4SChris Mason printk("all worked\n"); 3740f7d52f4SChris Mason return root; 3750f7d52f4SChris Mason } 3760f7d52f4SChris Mason 3772c90e5d6SChris Mason struct btrfs_root *open_ctree(struct super_block *sb) 378eb60ceacSChris Mason { 379e20d96d6SChris Mason struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), 380e20d96d6SChris Mason GFP_NOFS); 381e20d96d6SChris Mason struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), 382e20d96d6SChris Mason GFP_NOFS); 383e20d96d6SChris Mason struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), 384e20d96d6SChris Mason GFP_NOFS); 385eb60ceacSChris Mason int ret; 3862c90e5d6SChris Mason struct btrfs_super_block *disk_super; 387eb60ceacSChris Mason 3888ef97622SChris Mason init_bit_radix(&fs_info->pinned_radix); 3898ef97622SChris Mason init_bit_radix(&fs_info->pending_del_radix); 3900f7d52f4SChris Mason INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); 3912c90e5d6SChris Mason sb_set_blocksize(sb, 4096); 3929f5fae2fSChris Mason fs_info->running_transaction = NULL; 3939f5fae2fSChris Mason fs_info->tree_root = tree_root; 3949f5fae2fSChris Mason fs_info->extent_root = extent_root; 395e20d96d6SChris Mason fs_info->sb = sb; 396d98237b3SChris Mason fs_info->btree_inode = new_inode(sb); 397d98237b3SChris Mason fs_info->btree_inode->i_ino = 1; 3982c90e5d6SChris Mason fs_info->btree_inode->i_nlink = 1; 399d98237b3SChris Mason fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; 400d98237b3SChris Mason fs_info->btree_inode->i_mapping->a_ops = &btree_aops; 4010f7d52f4SChris Mason BTRFS_I(fs_info->btree_inode)->root = tree_root; 4020f7d52f4SChris Mason memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 4030f7d52f4SChris Mason sizeof(struct btrfs_key)); 40422b0ebdaSChris Mason insert_inode_hash(fs_info->btree_inode); 405d98237b3SChris Mason mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); 40687cbda5cSChris Mason fs_info->hash_tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); 40730ae8467SChris Mason spin_lock_init(&fs_info->hash_lock); 40830ae8467SChris Mason if (!fs_info->hash_tfm || IS_ERR(fs_info->hash_tfm)) { 40987cbda5cSChris Mason printk("failed to allocate sha256 hash\n"); 41087cbda5cSChris Mason return NULL; 41187cbda5cSChris Mason } 41279154b1bSChris Mason mutex_init(&fs_info->trans_mutex); 413d561c025SChris Mason mutex_init(&fs_info->fs_mutex); 4149f5fae2fSChris Mason memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); 4159f5fae2fSChris Mason memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); 4163768f368SChris Mason 4172c90e5d6SChris Mason __setup_root(sb->s_blocksize, tree_root, 4182c90e5d6SChris Mason fs_info, BTRFS_ROOT_TREE_OBJECTID); 4192c90e5d6SChris Mason fs_info->sb_buffer = read_tree_block(tree_root, 4202c90e5d6SChris Mason BTRFS_SUPER_INFO_OFFSET / 4212c90e5d6SChris Mason sb->s_blocksize); 422d98237b3SChris Mason 4230f7d52f4SChris Mason if (!fs_info->sb_buffer) 424d98237b3SChris Mason return NULL; 425d98237b3SChris Mason disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data; 4260f7d52f4SChris Mason if (!btrfs_super_root(disk_super)) 4272c90e5d6SChris Mason return NULL; 4280f7d52f4SChris Mason 429d98237b3SChris Mason fs_info->disk_super = disk_super; 430e20d96d6SChris Mason tree_root->node = read_tree_block(tree_root, 431e20d96d6SChris Mason btrfs_super_root(disk_super)); 4323768f368SChris Mason BUG_ON(!tree_root->node); 4333768f368SChris Mason 4342c90e5d6SChris Mason mutex_lock(&fs_info->fs_mutex); 4352c90e5d6SChris Mason ret = find_and_setup_root(sb->s_blocksize, tree_root, fs_info, 436e20d96d6SChris Mason BTRFS_EXTENT_TREE_OBJECTID, extent_root); 4373768f368SChris Mason BUG_ON(ret); 4383768f368SChris Mason 4390f7d52f4SChris Mason fs_info->generation = btrfs_super_generation(disk_super) + 1; 440d6e4a428SChris Mason memset(&fs_info->kobj, 0, sizeof(fs_info->kobj)); 441d6e4a428SChris Mason kobj_set_kset_s(fs_info, btrfs_subsys); 442d6e4a428SChris Mason kobject_set_name(&fs_info->kobj, "%s", sb->s_id); 443d6e4a428SChris Mason kobject_register(&fs_info->kobj); 4445be6f7f1SChris Mason mutex_unlock(&fs_info->fs_mutex); 4450f7d52f4SChris Mason return tree_root; 446eb60ceacSChris Mason } 447eb60ceacSChris Mason 448e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 44979154b1bSChris Mason *root) 450cfaa7295SChris Mason { 451d5719762SChris Mason struct buffer_head *bh = root->fs_info->sb_buffer; 4522c90e5d6SChris Mason 453d5719762SChris Mason btrfs_set_super_root(root->fs_info->disk_super, 454d5719762SChris Mason root->fs_info->tree_root->node->b_blocknr); 455d5719762SChris Mason lock_buffer(bh); 4562c90e5d6SChris Mason WARN_ON(atomic_read(&bh->b_count) < 1); 457d5719762SChris Mason clear_buffer_dirty(bh); 45887cbda5cSChris Mason csum_tree_block(root, bh, 0); 459d5719762SChris Mason bh->b_end_io = end_buffer_write_sync; 460d5719762SChris Mason get_bh(bh); 461d5719762SChris Mason submit_bh(WRITE, bh); 462d5719762SChris Mason wait_on_buffer(bh); 463d5719762SChris Mason if (!buffer_uptodate(bh)) { 464d5719762SChris Mason WARN_ON(1); 465d5719762SChris Mason return -EIO; 466cfaa7295SChris Mason } 467cfaa7295SChris Mason return 0; 468cfaa7295SChris Mason } 469cfaa7295SChris Mason 4702619ba1fSChris Mason static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) 4712619ba1fSChris Mason { 4722619ba1fSChris Mason radix_tree_delete(&fs_info->fs_roots_radix, 4732619ba1fSChris Mason (unsigned long)root->root_key.objectid); 4742619ba1fSChris Mason if (root->inode) 4752619ba1fSChris Mason iput(root->inode); 4762619ba1fSChris Mason if (root->node) 4772619ba1fSChris Mason brelse(root->node); 4782619ba1fSChris Mason if (root->commit_root) 4792619ba1fSChris Mason brelse(root->commit_root); 4802619ba1fSChris Mason kfree(root); 4812619ba1fSChris Mason return 0; 4822619ba1fSChris Mason } 4832619ba1fSChris Mason 4840f7d52f4SChris Mason int del_fs_roots(struct btrfs_fs_info *fs_info) 4850f7d52f4SChris Mason { 4860f7d52f4SChris Mason int ret; 4870f7d52f4SChris Mason struct btrfs_root *gang[8]; 4880f7d52f4SChris Mason int i; 4890f7d52f4SChris Mason 4900f7d52f4SChris Mason while(1) { 4910f7d52f4SChris Mason ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, 4920f7d52f4SChris Mason (void **)gang, 0, 4930f7d52f4SChris Mason ARRAY_SIZE(gang)); 4940f7d52f4SChris Mason if (!ret) 4950f7d52f4SChris Mason break; 4962619ba1fSChris Mason for (i = 0; i < ret; i++) 4972619ba1fSChris Mason free_fs_root(fs_info, gang[i]); 4980f7d52f4SChris Mason } 4990f7d52f4SChris Mason return 0; 5000f7d52f4SChris Mason } 5010f7d52f4SChris Mason 502e20d96d6SChris Mason int close_ctree(struct btrfs_root *root) 503eb60ceacSChris Mason { 5043768f368SChris Mason int ret; 505e089f05cSChris Mason struct btrfs_trans_handle *trans; 5060f7d52f4SChris Mason struct btrfs_fs_info *fs_info = root->fs_info; 507e089f05cSChris Mason 5080f7d52f4SChris Mason mutex_lock(&fs_info->fs_mutex); 50979154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 51079154b1bSChris Mason btrfs_commit_transaction(trans, root); 51179154b1bSChris Mason /* run commit again to drop the original snapshot */ 51279154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 51379154b1bSChris Mason btrfs_commit_transaction(trans, root); 51479154b1bSChris Mason ret = btrfs_write_and_wait_transaction(NULL, root); 5159f5fae2fSChris Mason BUG_ON(ret); 51679154b1bSChris Mason write_ctree_super(NULL, root); 5170f7d52f4SChris Mason mutex_unlock(&fs_info->fs_mutex); 518ed2ff2cbSChris Mason 5190f7d52f4SChris Mason if (fs_info->extent_root->node) 5200f7d52f4SChris Mason btrfs_block_release(fs_info->extent_root, 5210f7d52f4SChris Mason fs_info->extent_root->node); 5220f7d52f4SChris Mason if (fs_info->tree_root->node) 5230f7d52f4SChris Mason btrfs_block_release(fs_info->tree_root, 5240f7d52f4SChris Mason fs_info->tree_root->node); 5250f7d52f4SChris Mason btrfs_block_release(root, fs_info->sb_buffer); 5260f7d52f4SChris Mason crypto_free_hash(fs_info->hash_tfm); 5270f7d52f4SChris Mason truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); 5280f7d52f4SChris Mason iput(fs_info->btree_inode); 5290f7d52f4SChris Mason del_fs_roots(fs_info); 5300f7d52f4SChris Mason kfree(fs_info->extent_root); 5310f7d52f4SChris Mason kfree(fs_info->tree_root); 5320f7d52f4SChris Mason kobject_unregister(&fs_info->kobj); 533eb60ceacSChris Mason return 0; 534eb60ceacSChris Mason } 535eb60ceacSChris Mason 536e20d96d6SChris Mason void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) 537eb60ceacSChris Mason { 5387cfcc17eSChris Mason brelse(buf); 539eb60ceacSChris Mason } 540eb60ceacSChris Mason 541