1e20d96d6SChris Mason #include <linux/module.h> 2e20d96d6SChris Mason #include <linux/fs.h> 3eb60ceacSChris Mason #include "ctree.h" 4eb60ceacSChris Mason #include "disk-io.h" 5e089f05cSChris Mason #include "transaction.h" 6eb60ceacSChris Mason 7e20d96d6SChris Mason static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) 8eb60ceacSChris Mason { 9e20d96d6SChris Mason struct btrfs_node *node = btrfs_buffer_node(buf); 10e20d96d6SChris Mason if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) 119a8dd150SChris Mason BUG(); 12e20d96d6SChris Mason if (root->node && btrfs_header_parentid(&node->header) != 13e20d96d6SChris Mason btrfs_header_parentid(btrfs_buffer_header(root->node))) 149a8dd150SChris Mason BUG(); 159a8dd150SChris Mason return 0; 16eb60ceacSChris Mason } 17eb60ceacSChris Mason 18e20d96d6SChris Mason struct buffer_head *alloc_tree_block(struct btrfs_root *root, u64 blocknr) 19ed2ff2cbSChris Mason { 20e20d96d6SChris Mason return sb_getblk(root->fs_info->sb, blocknr); 21ed2ff2cbSChris Mason } 22ed2ff2cbSChris Mason 23e20d96d6SChris Mason struct buffer_head *find_tree_block(struct btrfs_root *root, u64 blocknr) 24eb60ceacSChris Mason { 25e20d96d6SChris Mason return sb_getblk(root->fs_info->sb, blocknr); 26e20d96d6SChris Mason } 27123abc88SChris Mason 28e20d96d6SChris Mason struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) 29e20d96d6SChris Mason { 30e20d96d6SChris Mason struct buffer_head *buf = sb_bread(root->fs_info->sb, blocknr); 31e20d96d6SChris Mason 32eb60ceacSChris Mason if (!buf) 33eb60ceacSChris Mason return buf; 349a8dd150SChris Mason if (check_tree_block(root, buf)) 35cfaa7295SChris Mason BUG(); 36eb60ceacSChris Mason return buf; 37eb60ceacSChris Mason } 38eb60ceacSChris Mason 39e089f05cSChris Mason int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 40e20d96d6SChris Mason struct buffer_head *buf) 41ed2ff2cbSChris Mason { 42e20d96d6SChris Mason mark_buffer_dirty(buf); 43ed2ff2cbSChris Mason return 0; 44ed2ff2cbSChris Mason } 45ed2ff2cbSChris Mason 46e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 47e20d96d6SChris Mason struct buffer_head *buf) 48ed2ff2cbSChris Mason { 49e20d96d6SChris Mason clear_buffer_dirty(buf); 50ed2ff2cbSChris Mason return 0; 51ed2ff2cbSChris Mason } 52ed2ff2cbSChris Mason 53e089f05cSChris Mason int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 54e20d96d6SChris Mason struct buffer_head *buf) 55eb60ceacSChris Mason { 56e20d96d6SChris Mason mark_buffer_dirty(buf); 57eb60ceacSChris Mason return 0; 58eb60ceacSChris Mason } 59eb60ceacSChris Mason 60e089f05cSChris Mason static int __commit_transaction(struct btrfs_trans_handle *trans, struct 61e089f05cSChris Mason btrfs_root *root) 62ed2ff2cbSChris Mason { 63e20d96d6SChris Mason filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping); 64e20d96d6SChris Mason return 0; 65ed2ff2cbSChris Mason } 66ed2ff2cbSChris Mason 679f5fae2fSChris Mason static int commit_tree_roots(struct btrfs_trans_handle *trans, 689f5fae2fSChris Mason struct btrfs_fs_info *fs_info) 693768f368SChris Mason { 703768f368SChris Mason int ret; 713768f368SChris Mason u64 old_extent_block; 729f5fae2fSChris Mason struct btrfs_root *tree_root = fs_info->tree_root; 739f5fae2fSChris Mason struct btrfs_root *extent_root = fs_info->extent_root; 749f5fae2fSChris Mason struct btrfs_root *inode_root = fs_info->inode_root; 753768f368SChris Mason 769f5fae2fSChris Mason btrfs_set_root_blocknr(&inode_root->root_item, 77e20d96d6SChris Mason inode_root->node->b_blocknr); 789f5fae2fSChris Mason ret = btrfs_update_root(trans, tree_root, 799f5fae2fSChris Mason &inode_root->root_key, 809f5fae2fSChris Mason &inode_root->root_item); 819f5fae2fSChris Mason BUG_ON(ret); 823768f368SChris Mason while(1) { 833768f368SChris Mason old_extent_block = btrfs_root_blocknr(&extent_root->root_item); 84e20d96d6SChris Mason if (old_extent_block == extent_root->node->b_blocknr) 853768f368SChris Mason break; 863768f368SChris Mason btrfs_set_root_blocknr(&extent_root->root_item, 87e20d96d6SChris Mason extent_root->node->b_blocknr); 88e089f05cSChris Mason ret = btrfs_update_root(trans, tree_root, 893768f368SChris Mason &extent_root->root_key, 903768f368SChris Mason &extent_root->root_item); 913768f368SChris Mason BUG_ON(ret); 923768f368SChris Mason } 933768f368SChris Mason return 0; 943768f368SChris Mason } 953768f368SChris Mason 96e089f05cSChris Mason int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct 97e089f05cSChris Mason btrfs_root *root, struct btrfs_super_block *s) 98ed2ff2cbSChris Mason { 99a28ec197SChris Mason int ret = 0; 100e20d96d6SChris Mason struct buffer_head *snap = root->commit_root; 1013768f368SChris Mason struct btrfs_key snap_key; 102a28ec197SChris Mason 1033768f368SChris Mason if (root->commit_root == root->node) 1043768f368SChris Mason return 0; 1053768f368SChris Mason 1063768f368SChris Mason memcpy(&snap_key, &root->root_key, sizeof(snap_key)); 1073768f368SChris Mason root->root_key.offset++; 1083768f368SChris Mason 109e20d96d6SChris Mason btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); 1109f5fae2fSChris Mason ret = btrfs_insert_root(trans, root->fs_info->tree_root, 1119f5fae2fSChris Mason &root->root_key, &root->root_item); 1123768f368SChris Mason BUG_ON(ret); 1133768f368SChris Mason 1149f5fae2fSChris Mason ret = commit_tree_roots(trans, root->fs_info); 1159f5fae2fSChris Mason BUG_ON(ret); 1169f5fae2fSChris Mason 1179f5fae2fSChris Mason ret = __commit_transaction(trans, root); 1183768f368SChris Mason BUG_ON(ret); 1193768f368SChris Mason 120e089f05cSChris Mason write_ctree_super(trans, root, s); 1219f5fae2fSChris Mason btrfs_finish_extent_commit(trans, root->fs_info->extent_root); 1229f5fae2fSChris Mason btrfs_finish_extent_commit(trans, root->fs_info->tree_root); 1233768f368SChris Mason 124a28ec197SChris Mason root->commit_root = root->node; 125e20d96d6SChris Mason get_bh(root->node); 126e089f05cSChris Mason ret = btrfs_drop_snapshot(trans, root, snap); 127a28ec197SChris Mason BUG_ON(ret); 1283768f368SChris Mason 1299f5fae2fSChris Mason ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key); 1303768f368SChris Mason BUG_ON(ret); 131293ffd5fSChris Mason root->fs_info->generation = root->root_key.offset + 1; 1323768f368SChris Mason 133ed2ff2cbSChris Mason return ret; 134ed2ff2cbSChris Mason } 135ed2ff2cbSChris Mason 136123abc88SChris Mason static int __setup_root(struct btrfs_super_block *super, 1379f5fae2fSChris Mason struct btrfs_root *root, 1389f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 139e20d96d6SChris Mason u64 objectid) 140d97e63b6SChris Mason { 141cfaa7295SChris Mason root->node = NULL; 142a28ec197SChris Mason root->commit_root = NULL; 143123abc88SChris Mason root->blocksize = btrfs_super_blocksize(super); 144123abc88SChris Mason root->ref_cows = 0; 1459f5fae2fSChris Mason root->fs_info = fs_info; 1463768f368SChris Mason memset(&root->root_key, 0, sizeof(root->root_key)); 1473768f368SChris Mason memset(&root->root_item, 0, sizeof(root->root_item)); 1483768f368SChris Mason return 0; 1493768f368SChris Mason } 1503768f368SChris Mason 151123abc88SChris Mason static int find_and_setup_root(struct btrfs_super_block *super, 1529f5fae2fSChris Mason struct btrfs_root *tree_root, 1539f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 1549f5fae2fSChris Mason u64 objectid, 155e20d96d6SChris Mason struct btrfs_root *root) 1563768f368SChris Mason { 1573768f368SChris Mason int ret; 1583768f368SChris Mason 159e20d96d6SChris Mason __setup_root(super, root, fs_info, objectid); 1603768f368SChris Mason ret = btrfs_find_last_root(tree_root, objectid, 1613768f368SChris Mason &root->root_item, &root->root_key); 1623768f368SChris Mason BUG_ON(ret); 1633768f368SChris Mason 1643768f368SChris Mason root->node = read_tree_block(root, 1653768f368SChris Mason btrfs_root_blocknr(&root->root_item)); 1663768f368SChris Mason BUG_ON(!root->node); 167d97e63b6SChris Mason return 0; 168d97e63b6SChris Mason } 169d97e63b6SChris Mason 170e20d96d6SChris Mason struct btrfs_root *open_ctree(struct super_block *sb, 171e20d96d6SChris Mason struct buffer_head *sb_buffer, 172e20d96d6SChris Mason struct btrfs_super_block *disk_super) 173eb60ceacSChris Mason { 174e20d96d6SChris Mason struct btrfs_root *root = kmalloc(sizeof(struct btrfs_root), 175e20d96d6SChris Mason GFP_NOFS); 176e20d96d6SChris Mason struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), 177e20d96d6SChris Mason GFP_NOFS); 178e20d96d6SChris Mason struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), 179e20d96d6SChris Mason GFP_NOFS); 180e20d96d6SChris Mason struct btrfs_root *inode_root = kmalloc(sizeof(struct btrfs_root), 181e20d96d6SChris Mason GFP_NOFS); 182e20d96d6SChris Mason struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), 183e20d96d6SChris Mason GFP_NOFS); 184eb60ceacSChris Mason int ret; 185eb60ceacSChris Mason 186e20d96d6SChris Mason /* FIXME: don't be stupid */ 187e20d96d6SChris Mason if (!btrfs_super_root(disk_super)) 188e20d96d6SChris Mason return NULL; 1899f5fae2fSChris Mason INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); 1909f5fae2fSChris Mason fs_info->running_transaction = NULL; 1919f5fae2fSChris Mason fs_info->fs_root = root; 1929f5fae2fSChris Mason fs_info->tree_root = tree_root; 1939f5fae2fSChris Mason fs_info->extent_root = extent_root; 1949f5fae2fSChris Mason fs_info->inode_root = inode_root; 1959f5fae2fSChris Mason fs_info->last_inode_alloc = 0; 1969f5fae2fSChris Mason fs_info->last_inode_alloc_dirid = 0; 197e20d96d6SChris Mason fs_info->disk_super = disk_super; 198e20d96d6SChris Mason fs_info->sb_buffer = sb_buffer; 199e20d96d6SChris Mason fs_info->sb = sb; 2009f5fae2fSChris Mason memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); 2019f5fae2fSChris Mason memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); 2023768f368SChris Mason 203e20d96d6SChris Mason __setup_root(disk_super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID); 204e20d96d6SChris Mason tree_root->node = read_tree_block(tree_root, 205e20d96d6SChris Mason btrfs_super_root(disk_super)); 2063768f368SChris Mason BUG_ON(!tree_root->node); 2073768f368SChris Mason 208e20d96d6SChris Mason ret = find_and_setup_root(disk_super, tree_root, fs_info, 209e20d96d6SChris Mason BTRFS_EXTENT_TREE_OBJECTID, extent_root); 2103768f368SChris Mason BUG_ON(ret); 2113768f368SChris Mason 212e20d96d6SChris Mason ret = find_and_setup_root(disk_super, tree_root, fs_info, 213e20d96d6SChris Mason BTRFS_INODE_MAP_OBJECTID, inode_root); 2149f5fae2fSChris Mason BUG_ON(ret); 2159f5fae2fSChris Mason 216e20d96d6SChris Mason ret = find_and_setup_root(disk_super, tree_root, fs_info, 217e20d96d6SChris Mason BTRFS_FS_TREE_OBJECTID, root); 2183768f368SChris Mason BUG_ON(ret); 2193768f368SChris Mason 220a28ec197SChris Mason root->commit_root = root->node; 221e20d96d6SChris Mason get_bh(root->node); 2223768f368SChris Mason root->ref_cows = 1; 223293ffd5fSChris Mason root->fs_info->generation = root->root_key.offset + 1; 224eb60ceacSChris Mason return root; 225eb60ceacSChris Mason } 226eb60ceacSChris Mason 227e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 228e089f05cSChris Mason *root, struct btrfs_super_block *s) 229cfaa7295SChris Mason { 230e20d96d6SChris Mason return 0; 231e20d96d6SChris Mason #if 0 232cfaa7295SChris Mason int ret; 233e20d96d6SChris Mason btrfs_set_super_root(s, root->fs_info->tree_root->node->b_blocknr); 234e20d96d6SChris Mason 2359f5fae2fSChris Mason ret = pwrite(root->fs_info->fp, s, sizeof(*s), 236123abc88SChris Mason BTRFS_SUPER_INFO_OFFSET); 237cfaa7295SChris Mason if (ret != sizeof(*s)) { 238cfaa7295SChris Mason fprintf(stderr, "failed to write new super block err %d\n", ret); 239cfaa7295SChris Mason return ret; 240cfaa7295SChris Mason } 241cfaa7295SChris Mason return 0; 242e20d96d6SChris Mason #endif 243cfaa7295SChris Mason } 244cfaa7295SChris Mason 245234b63a0SChris Mason static int drop_cache(struct btrfs_root *root) 246ed2ff2cbSChris Mason { 247e20d96d6SChris Mason return 0; 248e20d96d6SChris Mason #if 0 2499f5fae2fSChris Mason while(!list_empty(&root->fs_info->cache)) { 250e20d96d6SChris Mason struct buffer_head *b = list_entry(root->fs_info->cache.next, 251e20d96d6SChris Mason struct buffer_head, 2529f5fae2fSChris Mason cache); 253ed2ff2cbSChris Mason list_del_init(&b->cache); 254234b63a0SChris Mason btrfs_block_release(root, b); 255ed2ff2cbSChris Mason } 256ed2ff2cbSChris Mason return 0; 257e20d96d6SChris Mason #endif 258ed2ff2cbSChris Mason } 259e20d96d6SChris Mason 260e20d96d6SChris Mason int close_ctree(struct btrfs_root *root) 261eb60ceacSChris Mason { 2623768f368SChris Mason int ret; 263e089f05cSChris Mason struct btrfs_trans_handle *trans; 264e089f05cSChris Mason 2659f5fae2fSChris Mason trans = root->fs_info->running_transaction; 266e20d96d6SChris Mason btrfs_commit_transaction(trans, root, root->fs_info->disk_super); 2679f5fae2fSChris Mason ret = commit_tree_roots(trans, root->fs_info); 2689f5fae2fSChris Mason BUG_ON(ret); 2699f5fae2fSChris Mason ret = __commit_transaction(trans, root); 2703768f368SChris Mason BUG_ON(ret); 271e20d96d6SChris Mason write_ctree_super(trans, root, root->fs_info->disk_super); 272ed2ff2cbSChris Mason drop_cache(root); 273ed2ff2cbSChris Mason 274eb60ceacSChris Mason if (root->node) 275234b63a0SChris Mason btrfs_block_release(root, root->node); 2769f5fae2fSChris Mason if (root->fs_info->extent_root->node) 2779f5fae2fSChris Mason btrfs_block_release(root->fs_info->extent_root, 2789f5fae2fSChris Mason root->fs_info->extent_root->node); 2799f5fae2fSChris Mason if (root->fs_info->inode_root->node) 2809f5fae2fSChris Mason btrfs_block_release(root->fs_info->inode_root, 2819f5fae2fSChris Mason root->fs_info->inode_root->node); 2829f5fae2fSChris Mason if (root->fs_info->tree_root->node) 2839f5fae2fSChris Mason btrfs_block_release(root->fs_info->tree_root, 2849f5fae2fSChris Mason root->fs_info->tree_root->node); 285234b63a0SChris Mason btrfs_block_release(root, root->commit_root); 286e20d96d6SChris Mason btrfs_block_release(root, root->fs_info->sb_buffer); 287e20d96d6SChris Mason kfree(root->fs_info->extent_root); 288e20d96d6SChris Mason kfree(root->fs_info->inode_root); 289e20d96d6SChris Mason kfree(root->fs_info->tree_root); 290e20d96d6SChris Mason kfree(root->fs_info); 291e20d96d6SChris Mason kfree(root); 292eb60ceacSChris Mason return 0; 293eb60ceacSChris Mason } 294eb60ceacSChris Mason 295e20d96d6SChris Mason void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) 296eb60ceacSChris Mason { 297e20d96d6SChris Mason brelse(buf); 298eb60ceacSChris Mason } 299eb60ceacSChris Mason 300