16cbd5570SChris Mason /* 26cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 36cbd5570SChris Mason * 46cbd5570SChris Mason * This program is free software; you can redistribute it and/or 56cbd5570SChris Mason * modify it under the terms of the GNU General Public 66cbd5570SChris Mason * License v2 as published by the Free Software Foundation. 76cbd5570SChris Mason * 86cbd5570SChris Mason * This program is distributed in the hope that it will be useful, 96cbd5570SChris Mason * but WITHOUT ANY WARRANTY; without even the implied warranty of 106cbd5570SChris Mason * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 116cbd5570SChris Mason * General Public License for more details. 126cbd5570SChris Mason * 136cbd5570SChris Mason * You should have received a copy of the GNU General Public 146cbd5570SChris Mason * License along with this program; if not, write to the 156cbd5570SChris Mason * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 166cbd5570SChris Mason * Boston, MA 021110-1307, USA. 176cbd5570SChris Mason */ 186cbd5570SChris Mason 19e20d96d6SChris Mason #include <linux/fs.h> 20d98237b3SChris Mason #include <linux/blkdev.h> 2111bd143fSChris Mason #include <linux/crc32c.h> 2287cbda5cSChris Mason #include <linux/scatterlist.h> 2322b0ebdaSChris Mason #include <linux/swap.h> 240f7d52f4SChris Mason #include <linux/radix-tree.h> 2535b7e476SChris Mason #include <linux/writeback.h> 265f39d397SChris Mason #include <linux/buffer_head.h> // for block_sync_page 27eb60ceacSChris Mason #include "ctree.h" 28eb60ceacSChris Mason #include "disk-io.h" 29e089f05cSChris Mason #include "transaction.h" 300f7d52f4SChris Mason #include "btrfs_inode.h" 31db94535dSChris Mason #include "print-tree.h" 32eb60ceacSChris Mason 335f39d397SChris Mason #if 0 345f39d397SChris Mason static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) 357eccb903SChris Mason { 365f39d397SChris Mason if (extent_buffer_blocknr(buf) != btrfs_header_blocknr(buf)) { 375f39d397SChris Mason printk(KERN_CRIT "buf blocknr(buf) is %llu, header is %llu\n", 385f39d397SChris Mason (unsigned long long)extent_buffer_blocknr(buf), 395f39d397SChris Mason (unsigned long long)btrfs_header_blocknr(buf)); 4039279cc3SChris Mason return 1; 41d98237b3SChris Mason } 429a8dd150SChris Mason return 0; 43eb60ceacSChris Mason } 445f39d397SChris Mason #endif 45eb60ceacSChris Mason 460da5468fSChris Mason static struct extent_map_ops btree_extent_map_ops; 470da5468fSChris Mason 485f39d397SChris Mason struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, 49db94535dSChris Mason u64 bytenr, u32 blocksize) 50eb60ceacSChris Mason { 515f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 52f510cfecSChris Mason struct extent_buffer *eb; 53f510cfecSChris Mason eb = find_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, 54db94535dSChris Mason bytenr, blocksize, GFP_NOFS); 55f510cfecSChris Mason return eb; 56e20d96d6SChris Mason } 575f39d397SChris Mason 585f39d397SChris Mason struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, 59db94535dSChris Mason u64 bytenr, u32 blocksize) 605f39d397SChris Mason { 615f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 62f510cfecSChris Mason struct extent_buffer *eb; 63db94535dSChris Mason 64f510cfecSChris Mason eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->extent_tree, 6519c00ddcSChris Mason bytenr, blocksize, NULL, GFP_NOFS); 66f510cfecSChris Mason return eb; 67d98237b3SChris Mason } 685f39d397SChris Mason 695f39d397SChris Mason struct extent_map *btree_get_extent(struct inode *inode, struct page *page, 705f39d397SChris Mason size_t page_offset, u64 start, u64 end, 715f39d397SChris Mason int create) 725f39d397SChris Mason { 735f39d397SChris Mason struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; 745f39d397SChris Mason struct extent_map *em; 755f39d397SChris Mason int ret; 765f39d397SChris Mason 775f39d397SChris Mason again: 785f39d397SChris Mason em = lookup_extent_mapping(em_tree, start, end); 795f39d397SChris Mason if (em) { 805f39d397SChris Mason goto out; 815f39d397SChris Mason } 825f39d397SChris Mason em = alloc_extent_map(GFP_NOFS); 835f39d397SChris Mason if (!em) { 845f39d397SChris Mason em = ERR_PTR(-ENOMEM); 855f39d397SChris Mason goto out; 865f39d397SChris Mason } 875f39d397SChris Mason em->start = 0; 885f39d397SChris Mason em->end = (i_size_read(inode) & ~((u64)PAGE_CACHE_SIZE -1)) - 1; 895f39d397SChris Mason em->block_start = 0; 905f39d397SChris Mason em->block_end = em->end; 915f39d397SChris Mason em->bdev = inode->i_sb->s_bdev; 925f39d397SChris Mason ret = add_extent_mapping(em_tree, em); 935f39d397SChris Mason if (ret == -EEXIST) { 945f39d397SChris Mason free_extent_map(em); 955f39d397SChris Mason em = NULL; 965f39d397SChris Mason goto again; 975f39d397SChris Mason } else if (ret) { 985f39d397SChris Mason em = ERR_PTR(ret); 995f39d397SChris Mason } 1005f39d397SChris Mason out: 1015f39d397SChris Mason return em; 1025f39d397SChris Mason } 1035f39d397SChris Mason 10419c00ddcSChris Mason u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) 10519c00ddcSChris Mason { 10619c00ddcSChris Mason return crc32c(seed, data, len); 10719c00ddcSChris Mason } 10819c00ddcSChris Mason 10919c00ddcSChris Mason void btrfs_csum_final(u32 crc, char *result) 11019c00ddcSChris Mason { 11119c00ddcSChris Mason *(__le32 *)result = ~cpu_to_le32(crc); 11219c00ddcSChris Mason } 11319c00ddcSChris Mason 11419c00ddcSChris Mason static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, 11519c00ddcSChris Mason int verify) 11619c00ddcSChris Mason { 11719c00ddcSChris Mason char result[BTRFS_CRC32_SIZE]; 11819c00ddcSChris Mason unsigned long len; 11919c00ddcSChris Mason unsigned long cur_len; 12019c00ddcSChris Mason unsigned long offset = BTRFS_CSUM_SIZE; 12119c00ddcSChris Mason char *map_token = NULL; 12219c00ddcSChris Mason char *kaddr; 12319c00ddcSChris Mason unsigned long map_start; 12419c00ddcSChris Mason unsigned long map_len; 12519c00ddcSChris Mason int err; 12619c00ddcSChris Mason u32 crc = ~(u32)0; 12719c00ddcSChris Mason 12819c00ddcSChris Mason len = buf->len - offset; 12919c00ddcSChris Mason while(len > 0) { 13019c00ddcSChris Mason err = map_private_extent_buffer(buf, offset, 32, 13119c00ddcSChris Mason &map_token, &kaddr, 13219c00ddcSChris Mason &map_start, &map_len, KM_USER0); 13319c00ddcSChris Mason if (err) { 13419c00ddcSChris Mason printk("failed to map extent buffer! %lu\n", 13519c00ddcSChris Mason offset); 13619c00ddcSChris Mason return 1; 13719c00ddcSChris Mason } 13819c00ddcSChris Mason cur_len = min(len, map_len - (offset - map_start)); 13919c00ddcSChris Mason crc = btrfs_csum_data(root, kaddr + offset - map_start, 14019c00ddcSChris Mason crc, cur_len); 14119c00ddcSChris Mason len -= cur_len; 14219c00ddcSChris Mason offset += cur_len; 14319c00ddcSChris Mason unmap_extent_buffer(buf, map_token, KM_USER0); 14419c00ddcSChris Mason } 14519c00ddcSChris Mason btrfs_csum_final(crc, result); 14619c00ddcSChris Mason 14719c00ddcSChris Mason if (verify) { 14819c00ddcSChris Mason if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) { 14919c00ddcSChris Mason printk("btrfs: %s checksum verify failed on %llu\n", 15019c00ddcSChris Mason root->fs_info->sb->s_id, 15119c00ddcSChris Mason buf->start); 15219c00ddcSChris Mason return 1; 15319c00ddcSChris Mason } 15419c00ddcSChris Mason } else { 15519c00ddcSChris Mason write_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE); 15619c00ddcSChris Mason } 15719c00ddcSChris Mason return 0; 15819c00ddcSChris Mason } 15919c00ddcSChris Mason 16019c00ddcSChris Mason 16119c00ddcSChris Mason int csum_dirty_buffer(struct btrfs_root *root, struct page *page) 16219c00ddcSChris Mason { 16319c00ddcSChris Mason struct extent_map_tree *tree; 16435ebb934SChris Mason u64 start = (u64)page->index << PAGE_CACHE_SHIFT; 16519c00ddcSChris Mason u64 found_start; 16619c00ddcSChris Mason int found_level; 16719c00ddcSChris Mason unsigned long len; 16819c00ddcSChris Mason struct extent_buffer *eb; 16919c00ddcSChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 17019c00ddcSChris Mason 17119c00ddcSChris Mason if (page->private == EXTENT_PAGE_PRIVATE) 17219c00ddcSChris Mason goto out; 17319c00ddcSChris Mason if (!page->private) 17419c00ddcSChris Mason goto out; 17519c00ddcSChris Mason len = page->private >> 2; 17619c00ddcSChris Mason if (len == 0) { 17719c00ddcSChris Mason WARN_ON(1); 17819c00ddcSChris Mason } 17919c00ddcSChris Mason eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); 18019c00ddcSChris Mason read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1); 18119c00ddcSChris Mason found_start = btrfs_header_bytenr(eb); 18219c00ddcSChris Mason if (found_start != start) { 18319c00ddcSChris Mason printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", 18419c00ddcSChris Mason start, found_start, len); 18519c00ddcSChris Mason } 18619c00ddcSChris Mason found_level = btrfs_header_level(eb); 18719c00ddcSChris Mason csum_tree_block(root, eb, 0); 18819c00ddcSChris Mason free_extent_buffer(eb); 18919c00ddcSChris Mason out: 19019c00ddcSChris Mason return 0; 19119c00ddcSChris Mason } 19219c00ddcSChris Mason 1930da5468fSChris Mason static int btree_writepage_io_hook(struct page *page, u64 start, u64 end) 1940da5468fSChris Mason { 1950da5468fSChris Mason struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; 1960da5468fSChris Mason 1970da5468fSChris Mason csum_dirty_buffer(root, page); 1980da5468fSChris Mason return 0; 1990da5468fSChris Mason } 2000da5468fSChris Mason 2015f39d397SChris Mason static int btree_writepage(struct page *page, struct writeback_control *wbc) 2025f39d397SChris Mason { 2035f39d397SChris Mason struct extent_map_tree *tree; 2045f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2055f39d397SChris Mason return extent_write_full_page(tree, page, btree_get_extent, wbc); 2065f39d397SChris Mason } 2070da5468fSChris Mason 2080da5468fSChris Mason static int btree_writepages(struct address_space *mapping, 2090da5468fSChris Mason struct writeback_control *wbc) 2100da5468fSChris Mason { 2110da5468fSChris Mason struct extent_map_tree *tree; 2120da5468fSChris Mason tree = &BTRFS_I(mapping->host)->extent_tree; 213d8d5f3e1SChris Mason if (wbc->sync_mode == WB_SYNC_NONE) { 214793955bcSChris Mason u64 num_dirty; 215793955bcSChris Mason u64 start = 0; 216793955bcSChris Mason unsigned long thresh = 96 * 1024 * 1024; 217448d640bSChris Mason 218448d640bSChris Mason if (wbc->for_kupdate) 219448d640bSChris Mason return 0; 220448d640bSChris Mason 221ca664626SChris Mason if (current_is_pdflush()) { 222ca664626SChris Mason thresh = 96 * 1024 * 1024; 223ca664626SChris Mason } else { 224ca664626SChris Mason thresh = 8 * 1024 * 1024; 225ca664626SChris Mason } 226793955bcSChris Mason num_dirty = count_range_bits(tree, &start, thresh, EXTENT_DIRTY); 227793955bcSChris Mason if (num_dirty < thresh) { 228793955bcSChris Mason return 0; 229793955bcSChris Mason } 230793955bcSChris Mason } 2310da5468fSChris Mason return extent_writepages(tree, mapping, btree_get_extent, wbc); 2320da5468fSChris Mason } 2330da5468fSChris Mason 2345f39d397SChris Mason int btree_readpage(struct file *file, struct page *page) 2355f39d397SChris Mason { 2365f39d397SChris Mason struct extent_map_tree *tree; 2375f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2385f39d397SChris Mason return extent_read_full_page(tree, page, btree_get_extent); 2395f39d397SChris Mason } 2405f39d397SChris Mason 2415f39d397SChris Mason static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags) 2425f39d397SChris Mason { 2435f39d397SChris Mason struct extent_map_tree *tree; 2445f39d397SChris Mason int ret; 2455f39d397SChris Mason 2465f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2475f39d397SChris Mason ret = try_release_extent_mapping(tree, page); 2485f39d397SChris Mason if (ret == 1) { 2495f39d397SChris Mason ClearPagePrivate(page); 2505f39d397SChris Mason set_page_private(page, 0); 251d98237b3SChris Mason page_cache_release(page); 2525f39d397SChris Mason } 253d98237b3SChris Mason return ret; 254d98237b3SChris Mason } 255d98237b3SChris Mason 2565f39d397SChris Mason static void btree_invalidatepage(struct page *page, unsigned long offset) 257d98237b3SChris Mason { 2585f39d397SChris Mason struct extent_map_tree *tree; 2595f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2605f39d397SChris Mason extent_invalidatepage(tree, page, offset); 2615f39d397SChris Mason btree_releasepage(page, GFP_NOFS); 262d98237b3SChris Mason } 263d98237b3SChris Mason 2645f39d397SChris Mason #if 0 265d98237b3SChris Mason static int btree_writepage(struct page *page, struct writeback_control *wbc) 266d98237b3SChris Mason { 26787cbda5cSChris Mason struct buffer_head *bh; 2680f7d52f4SChris Mason struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; 26987cbda5cSChris Mason struct buffer_head *head; 27087cbda5cSChris Mason if (!page_has_buffers(page)) { 27187cbda5cSChris Mason create_empty_buffers(page, root->fs_info->sb->s_blocksize, 27287cbda5cSChris Mason (1 << BH_Dirty)|(1 << BH_Uptodate)); 27387cbda5cSChris Mason } 27487cbda5cSChris Mason head = page_buffers(page); 27587cbda5cSChris Mason bh = head; 27687cbda5cSChris Mason do { 27787cbda5cSChris Mason if (buffer_dirty(bh)) 27887cbda5cSChris Mason csum_tree_block(root, bh, 0); 27987cbda5cSChris Mason bh = bh->b_this_page; 28087cbda5cSChris Mason } while (bh != head); 281d98237b3SChris Mason return block_write_full_page(page, btree_get_block, wbc); 282d98237b3SChris Mason } 2835f39d397SChris Mason #endif 284d98237b3SChris Mason 285d98237b3SChris Mason static struct address_space_operations btree_aops = { 286d98237b3SChris Mason .readpage = btree_readpage, 287d98237b3SChris Mason .writepage = btree_writepage, 2880da5468fSChris Mason .writepages = btree_writepages, 2895f39d397SChris Mason .releasepage = btree_releasepage, 2905f39d397SChris Mason .invalidatepage = btree_invalidatepage, 291d98237b3SChris Mason .sync_page = block_sync_page, 292d98237b3SChris Mason }; 293123abc88SChris Mason 294db94535dSChris Mason int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) 295090d1875SChris Mason { 2965f39d397SChris Mason struct extent_buffer *buf = NULL; 2975f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 298de428b63SChris Mason int ret = 0; 299090d1875SChris Mason 300db94535dSChris Mason buf = btrfs_find_create_tree_block(root, bytenr, blocksize); 3015f39d397SChris Mason if (!buf) 302090d1875SChris Mason return 0; 3035f39d397SChris Mason read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 30419c00ddcSChris Mason buf, 0, 0); 3055f39d397SChris Mason free_extent_buffer(buf); 306de428b63SChris Mason return ret; 307090d1875SChris Mason } 308090d1875SChris Mason 309db94535dSChris Mason struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, 310db94535dSChris Mason u32 blocksize) 311e20d96d6SChris Mason { 3125f39d397SChris Mason struct extent_buffer *buf = NULL; 3135f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 31419c00ddcSChris Mason struct extent_map_tree *extent_tree; 31519c00ddcSChris Mason int ret; 31619c00ddcSChris Mason 31719c00ddcSChris Mason extent_tree = &BTRFS_I(btree_inode)->extent_tree; 318e20d96d6SChris Mason 319db94535dSChris Mason buf = btrfs_find_create_tree_block(root, bytenr, blocksize); 3205f39d397SChris Mason if (!buf) 321d98237b3SChris Mason return NULL; 3225f39d397SChris Mason read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 32319c00ddcSChris Mason buf, 0, 1); 32419c00ddcSChris Mason if (buf->flags & EXTENT_CSUM) { 32519c00ddcSChris Mason return buf; 32619c00ddcSChris Mason } 32719c00ddcSChris Mason if (test_range_bit(extent_tree, buf->start, buf->start + buf->len - 1, 32819c00ddcSChris Mason EXTENT_CSUM, 1)) { 32919c00ddcSChris Mason buf->flags |= EXTENT_CSUM; 33019c00ddcSChris Mason return buf; 33119c00ddcSChris Mason } 33219c00ddcSChris Mason ret = csum_tree_block(root, buf, 1); 33319c00ddcSChris Mason set_extent_bits(extent_tree, buf->start, 33419c00ddcSChris Mason buf->start + buf->len - 1, 33519c00ddcSChris Mason EXTENT_CSUM, GFP_NOFS); 33619c00ddcSChris Mason buf->flags |= EXTENT_CSUM; 3375f39d397SChris Mason return buf; 338eb60ceacSChris Mason } 339eb60ceacSChris Mason 340e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 3415f39d397SChris Mason struct extent_buffer *buf) 342ed2ff2cbSChris Mason { 3435f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 3445f39d397SChris Mason clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); 3455f39d397SChris Mason return 0; 3465f39d397SChris Mason } 3475f39d397SChris Mason 3485f39d397SChris Mason int wait_on_tree_block_writeback(struct btrfs_root *root, 3495f39d397SChris Mason struct extent_buffer *buf) 3505f39d397SChris Mason { 3515f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 3525f39d397SChris Mason wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->extent_tree, 3535f39d397SChris Mason buf); 3545f39d397SChris Mason return 0; 3555f39d397SChris Mason } 3565f39d397SChris Mason 357db94535dSChris Mason static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, 35887ee04ebSChris Mason u32 stripesize, struct btrfs_root *root, 3599f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 360e20d96d6SChris Mason u64 objectid) 361d97e63b6SChris Mason { 362cfaa7295SChris Mason root->node = NULL; 3630f7d52f4SChris Mason root->inode = NULL; 364a28ec197SChris Mason root->commit_root = NULL; 365db94535dSChris Mason root->sectorsize = sectorsize; 366db94535dSChris Mason root->nodesize = nodesize; 367db94535dSChris Mason root->leafsize = leafsize; 36887ee04ebSChris Mason root->stripesize = stripesize; 369123abc88SChris Mason root->ref_cows = 0; 3709f5fae2fSChris Mason root->fs_info = fs_info; 3710f7d52f4SChris Mason root->objectid = objectid; 3720f7d52f4SChris Mason root->last_trans = 0; 3731b05da2eSChris Mason root->highest_inode = 0; 3741b05da2eSChris Mason root->last_inode_alloc = 0; 37558176a96SJosef Bacik root->name = NULL; 3763768f368SChris Mason memset(&root->root_key, 0, sizeof(root->root_key)); 3773768f368SChris Mason memset(&root->root_item, 0, sizeof(root->root_item)); 3786702ed49SChris Mason memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); 37958176a96SJosef Bacik memset(&root->root_kobj, 0, sizeof(root->root_kobj)); 38058176a96SJosef Bacik init_completion(&root->kobj_unregister); 381011410bdSChris Mason init_rwsem(&root->snap_sem); 3826702ed49SChris Mason root->defrag_running = 0; 3836702ed49SChris Mason root->defrag_level = 0; 3844d775673SChris Mason root->root_key.objectid = objectid; 3853768f368SChris Mason return 0; 3863768f368SChris Mason } 3873768f368SChris Mason 388db94535dSChris Mason static int find_and_setup_root(struct btrfs_root *tree_root, 3899f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 3909f5fae2fSChris Mason u64 objectid, 391e20d96d6SChris Mason struct btrfs_root *root) 3923768f368SChris Mason { 3933768f368SChris Mason int ret; 394db94535dSChris Mason u32 blocksize; 3953768f368SChris Mason 396db94535dSChris Mason __setup_root(tree_root->nodesize, tree_root->leafsize, 39787ee04ebSChris Mason tree_root->sectorsize, tree_root->stripesize, 39887ee04ebSChris Mason root, fs_info, objectid); 3993768f368SChris Mason ret = btrfs_find_last_root(tree_root, objectid, 4003768f368SChris Mason &root->root_item, &root->root_key); 4013768f368SChris Mason BUG_ON(ret); 4023768f368SChris Mason 403db94535dSChris Mason blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); 404db94535dSChris Mason root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), 405db94535dSChris Mason blocksize); 4063768f368SChris Mason BUG_ON(!root->node); 407d97e63b6SChris Mason return 0; 408d97e63b6SChris Mason } 409d97e63b6SChris Mason 4105eda7b5eSChris Mason struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, 4110f7d52f4SChris Mason struct btrfs_key *location) 4120f7d52f4SChris Mason { 4130f7d52f4SChris Mason struct btrfs_root *root; 4140f7d52f4SChris Mason struct btrfs_root *tree_root = fs_info->tree_root; 4150f7d52f4SChris Mason struct btrfs_path *path; 4165f39d397SChris Mason struct extent_buffer *l; 4171b05da2eSChris Mason u64 highest_inode; 418db94535dSChris Mason u32 blocksize; 4190f7d52f4SChris Mason int ret = 0; 4200f7d52f4SChris Mason 4215eda7b5eSChris Mason root = kzalloc(sizeof(*root), GFP_NOFS); 4220cf6c620SChris Mason if (!root) 4230f7d52f4SChris Mason return ERR_PTR(-ENOMEM); 4240f7d52f4SChris Mason if (location->offset == (u64)-1) { 425db94535dSChris Mason ret = find_and_setup_root(tree_root, fs_info, 4260f7d52f4SChris Mason location->objectid, root); 4270f7d52f4SChris Mason if (ret) { 4280f7d52f4SChris Mason kfree(root); 4290f7d52f4SChris Mason return ERR_PTR(ret); 4300f7d52f4SChris Mason } 4310f7d52f4SChris Mason goto insert; 4320f7d52f4SChris Mason } 4330f7d52f4SChris Mason 434db94535dSChris Mason __setup_root(tree_root->nodesize, tree_root->leafsize, 43587ee04ebSChris Mason tree_root->sectorsize, tree_root->stripesize, 43687ee04ebSChris Mason root, fs_info, location->objectid); 4370f7d52f4SChris Mason 4380f7d52f4SChris Mason path = btrfs_alloc_path(); 4390f7d52f4SChris Mason BUG_ON(!path); 4400f7d52f4SChris Mason ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); 4410f7d52f4SChris Mason if (ret != 0) { 4420f7d52f4SChris Mason if (ret > 0) 4430f7d52f4SChris Mason ret = -ENOENT; 4440f7d52f4SChris Mason goto out; 4450f7d52f4SChris Mason } 4465f39d397SChris Mason l = path->nodes[0]; 4475f39d397SChris Mason read_extent_buffer(l, &root->root_item, 4485f39d397SChris Mason btrfs_item_ptr_offset(l, path->slots[0]), 4490f7d52f4SChris Mason sizeof(root->root_item)); 45044b36eb2SYan Zheng memcpy(&root->root_key, location, sizeof(*location)); 4510f7d52f4SChris Mason ret = 0; 4520f7d52f4SChris Mason out: 4530f7d52f4SChris Mason btrfs_release_path(root, path); 4540f7d52f4SChris Mason btrfs_free_path(path); 4550f7d52f4SChris Mason if (ret) { 4560f7d52f4SChris Mason kfree(root); 4570f7d52f4SChris Mason return ERR_PTR(ret); 4580f7d52f4SChris Mason } 459db94535dSChris Mason blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); 460db94535dSChris Mason root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), 461db94535dSChris Mason blocksize); 4620f7d52f4SChris Mason BUG_ON(!root->node); 4630f7d52f4SChris Mason insert: 4640f7d52f4SChris Mason root->ref_cows = 1; 4655eda7b5eSChris Mason ret = btrfs_find_highest_inode(root, &highest_inode); 4665eda7b5eSChris Mason if (ret == 0) { 4675eda7b5eSChris Mason root->highest_inode = highest_inode; 4685eda7b5eSChris Mason root->last_inode_alloc = highest_inode; 4695eda7b5eSChris Mason } 4705eda7b5eSChris Mason return root; 4715eda7b5eSChris Mason } 4725eda7b5eSChris Mason 4735eda7b5eSChris Mason struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 47458176a96SJosef Bacik struct btrfs_key *location, 47558176a96SJosef Bacik const char *name, int namelen) 4765eda7b5eSChris Mason { 4775eda7b5eSChris Mason struct btrfs_root *root; 4785eda7b5eSChris Mason int ret; 4795eda7b5eSChris Mason 4805eda7b5eSChris Mason root = radix_tree_lookup(&fs_info->fs_roots_radix, 4815eda7b5eSChris Mason (unsigned long)location->objectid); 4825eda7b5eSChris Mason if (root) 4835eda7b5eSChris Mason return root; 4845eda7b5eSChris Mason 4855eda7b5eSChris Mason root = btrfs_read_fs_root_no_radix(fs_info, location); 4865eda7b5eSChris Mason if (IS_ERR(root)) 4875eda7b5eSChris Mason return root; 4882619ba1fSChris Mason ret = radix_tree_insert(&fs_info->fs_roots_radix, 4892619ba1fSChris Mason (unsigned long)root->root_key.objectid, 4900f7d52f4SChris Mason root); 4910f7d52f4SChris Mason if (ret) { 4925f39d397SChris Mason free_extent_buffer(root->node); 4930f7d52f4SChris Mason kfree(root); 4940f7d52f4SChris Mason return ERR_PTR(ret); 4950f7d52f4SChris Mason } 49658176a96SJosef Bacik 49758176a96SJosef Bacik ret = btrfs_set_root_name(root, name, namelen); 49858176a96SJosef Bacik if (ret) { 4995f39d397SChris Mason free_extent_buffer(root->node); 50058176a96SJosef Bacik kfree(root); 50158176a96SJosef Bacik return ERR_PTR(ret); 50258176a96SJosef Bacik } 50358176a96SJosef Bacik 50458176a96SJosef Bacik ret = btrfs_sysfs_add_root(root); 50558176a96SJosef Bacik if (ret) { 5065f39d397SChris Mason free_extent_buffer(root->node); 50758176a96SJosef Bacik kfree(root->name); 50858176a96SJosef Bacik kfree(root); 50958176a96SJosef Bacik return ERR_PTR(ret); 51058176a96SJosef Bacik } 51158176a96SJosef Bacik 5125ce14bbcSChris Mason ret = btrfs_find_dead_roots(fs_info->tree_root, 5135ce14bbcSChris Mason root->root_key.objectid, root); 5145ce14bbcSChris Mason BUG_ON(ret); 5155ce14bbcSChris Mason 5160f7d52f4SChris Mason return root; 5170f7d52f4SChris Mason } 51819c00ddcSChris Mason #if 0 51919c00ddcSChris Mason static int add_hasher(struct btrfs_fs_info *info, char *type) { 52019c00ddcSChris Mason struct btrfs_hasher *hasher; 5210f7d52f4SChris Mason 52219c00ddcSChris Mason hasher = kmalloc(sizeof(*hasher), GFP_NOFS); 52319c00ddcSChris Mason if (!hasher) 52419c00ddcSChris Mason return -ENOMEM; 52519c00ddcSChris Mason hasher->hash_tfm = crypto_alloc_hash(type, 0, CRYPTO_ALG_ASYNC); 52619c00ddcSChris Mason if (!hasher->hash_tfm) { 52719c00ddcSChris Mason kfree(hasher); 52819c00ddcSChris Mason return -EINVAL; 52919c00ddcSChris Mason } 53019c00ddcSChris Mason spin_lock(&info->hash_lock); 53119c00ddcSChris Mason list_add(&hasher->list, &info->hashers); 53219c00ddcSChris Mason spin_unlock(&info->hash_lock); 53319c00ddcSChris Mason return 0; 53419c00ddcSChris Mason } 53519c00ddcSChris Mason #endif 5362c90e5d6SChris Mason struct btrfs_root *open_ctree(struct super_block *sb) 537eb60ceacSChris Mason { 538db94535dSChris Mason u32 sectorsize; 539db94535dSChris Mason u32 nodesize; 540db94535dSChris Mason u32 leafsize; 541db94535dSChris Mason u32 blocksize; 54287ee04ebSChris Mason u32 stripesize; 543e20d96d6SChris Mason struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), 544e20d96d6SChris Mason GFP_NOFS); 545e20d96d6SChris Mason struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), 546e20d96d6SChris Mason GFP_NOFS); 547e20d96d6SChris Mason struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), 548e20d96d6SChris Mason GFP_NOFS); 549eb60ceacSChris Mason int ret; 55039279cc3SChris Mason int err = -EIO; 5512c90e5d6SChris Mason struct btrfs_super_block *disk_super; 552eb60ceacSChris Mason 55339279cc3SChris Mason if (!extent_root || !tree_root || !fs_info) { 55439279cc3SChris Mason err = -ENOMEM; 55539279cc3SChris Mason goto fail; 55639279cc3SChris Mason } 5570f7d52f4SChris Mason INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); 5588fd17795SChris Mason INIT_LIST_HEAD(&fs_info->trans_list); 559facda1e7SChris Mason INIT_LIST_HEAD(&fs_info->dead_roots); 56019c00ddcSChris Mason INIT_LIST_HEAD(&fs_info->hashers); 56119c00ddcSChris Mason spin_lock_init(&fs_info->hash_lock); 56219c00ddcSChris Mason 56358176a96SJosef Bacik memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); 56458176a96SJosef Bacik init_completion(&fs_info->kobj_unregister); 5652c90e5d6SChris Mason sb_set_blocksize(sb, 4096); 5669f5fae2fSChris Mason fs_info->running_transaction = NULL; 56715ee9bc7SJosef Bacik fs_info->last_trans_committed = 0; 5689f5fae2fSChris Mason fs_info->tree_root = tree_root; 5699f5fae2fSChris Mason fs_info->extent_root = extent_root; 570e20d96d6SChris Mason fs_info->sb = sb; 571d98237b3SChris Mason fs_info->btree_inode = new_inode(sb); 572d98237b3SChris Mason fs_info->btree_inode->i_ino = 1; 5732c90e5d6SChris Mason fs_info->btree_inode->i_nlink = 1; 574d98237b3SChris Mason fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; 575d98237b3SChris Mason fs_info->btree_inode->i_mapping->a_ops = &btree_aops; 5765f39d397SChris Mason extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, 5775f39d397SChris Mason fs_info->btree_inode->i_mapping, 5785f39d397SChris Mason GFP_NOFS); 5790da5468fSChris Mason BTRFS_I(fs_info->btree_inode)->extent_tree.ops = &btree_extent_map_ops; 5800da5468fSChris Mason 581f510cfecSChris Mason extent_map_tree_init(&fs_info->free_space_cache, 582f510cfecSChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 58396b5179dSChris Mason extent_map_tree_init(&fs_info->block_group_cache, 58496b5179dSChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5851a5bc167SChris Mason extent_map_tree_init(&fs_info->pinned_extents, 5861a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5871a5bc167SChris Mason extent_map_tree_init(&fs_info->pending_del, 5881a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5891a5bc167SChris Mason extent_map_tree_init(&fs_info->extent_ins, 5901a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 591e66f709bSChris Mason fs_info->do_barriers = 1; 592facda1e7SChris Mason fs_info->closing = 0; 593324ae4dfSYan fs_info->total_pinned = 0; 594facda1e7SChris Mason 59508607c1bSChris Mason INIT_DELAYED_WORK(&fs_info->trans_work, btrfs_transaction_cleaner); 5960f7d52f4SChris Mason BTRFS_I(fs_info->btree_inode)->root = tree_root; 5970f7d52f4SChris Mason memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 5980f7d52f4SChris Mason sizeof(struct btrfs_key)); 59922b0ebdaSChris Mason insert_inode_hash(fs_info->btree_inode); 600d98237b3SChris Mason mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); 60139279cc3SChris Mason 60279154b1bSChris Mason mutex_init(&fs_info->trans_mutex); 603d561c025SChris Mason mutex_init(&fs_info->fs_mutex); 6043768f368SChris Mason 60519c00ddcSChris Mason #if 0 60619c00ddcSChris Mason ret = add_hasher(fs_info, "crc32c"); 60719c00ddcSChris Mason if (ret) { 60819c00ddcSChris Mason printk("btrfs: failed hash setup, modprobe cryptomgr?\n"); 60919c00ddcSChris Mason err = -ENOMEM; 61019c00ddcSChris Mason goto fail_iput; 61119c00ddcSChris Mason } 61219c00ddcSChris Mason #endif 61387ee04ebSChris Mason __setup_root(512, 512, 512, 512, tree_root, 6142c90e5d6SChris Mason fs_info, BTRFS_ROOT_TREE_OBJECTID); 6157eccb903SChris Mason 6162c90e5d6SChris Mason fs_info->sb_buffer = read_tree_block(tree_root, 617db94535dSChris Mason BTRFS_SUPER_INFO_OFFSET, 618db94535dSChris Mason 512); 619d98237b3SChris Mason 6200f7d52f4SChris Mason if (!fs_info->sb_buffer) 62139279cc3SChris Mason goto fail_iput; 62239279cc3SChris Mason 6235f39d397SChris Mason read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0, 6245f39d397SChris Mason sizeof(fs_info->super_copy)); 6255f39d397SChris Mason 6265f39d397SChris Mason read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, 6275f39d397SChris Mason (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), 6285f39d397SChris Mason BTRFS_FSID_SIZE); 6295f39d397SChris Mason disk_super = &fs_info->super_copy; 6300f7d52f4SChris Mason if (!btrfs_super_root(disk_super)) 63139279cc3SChris Mason goto fail_sb_buffer; 6320f7d52f4SChris Mason 633db94535dSChris Mason nodesize = btrfs_super_nodesize(disk_super); 634db94535dSChris Mason leafsize = btrfs_super_leafsize(disk_super); 635db94535dSChris Mason sectorsize = btrfs_super_sectorsize(disk_super); 63687ee04ebSChris Mason stripesize = btrfs_super_stripesize(disk_super); 637db94535dSChris Mason tree_root->nodesize = nodesize; 638db94535dSChris Mason tree_root->leafsize = leafsize; 639db94535dSChris Mason tree_root->sectorsize = sectorsize; 64087ee04ebSChris Mason tree_root->stripesize = stripesize; 641ff79f819SChris Mason sb_set_blocksize(sb, sectorsize); 642db94535dSChris Mason 6438352d8a4SChris Mason i_size_write(fs_info->btree_inode, 644db94535dSChris Mason btrfs_super_total_bytes(disk_super)); 6458352d8a4SChris Mason 64639279cc3SChris Mason if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, 64739279cc3SChris Mason sizeof(disk_super->magic))) { 64839279cc3SChris Mason printk("btrfs: valid FS not found on %s\n", sb->s_id); 64939279cc3SChris Mason goto fail_sb_buffer; 65039279cc3SChris Mason } 65119c00ddcSChris Mason 652db94535dSChris Mason blocksize = btrfs_level_size(tree_root, 653db94535dSChris Mason btrfs_super_root_level(disk_super)); 65419c00ddcSChris Mason 655e20d96d6SChris Mason tree_root->node = read_tree_block(tree_root, 656db94535dSChris Mason btrfs_super_root(disk_super), 657db94535dSChris Mason blocksize); 65839279cc3SChris Mason if (!tree_root->node) 65939279cc3SChris Mason goto fail_sb_buffer; 6603768f368SChris Mason 6612c90e5d6SChris Mason mutex_lock(&fs_info->fs_mutex); 662db94535dSChris Mason 663db94535dSChris Mason ret = find_and_setup_root(tree_root, fs_info, 664e20d96d6SChris Mason BTRFS_EXTENT_TREE_OBJECTID, extent_root); 66539279cc3SChris Mason if (ret) { 66639279cc3SChris Mason mutex_unlock(&fs_info->fs_mutex); 66739279cc3SChris Mason goto fail_tree_root; 66839279cc3SChris Mason } 6693768f368SChris Mason 6709078a3e1SChris Mason btrfs_read_block_groups(extent_root); 6719078a3e1SChris Mason 6720f7d52f4SChris Mason fs_info->generation = btrfs_super_generation(disk_super) + 1; 6735be6f7f1SChris Mason mutex_unlock(&fs_info->fs_mutex); 6740f7d52f4SChris Mason return tree_root; 67539279cc3SChris Mason 67639279cc3SChris Mason fail_tree_root: 6775f39d397SChris Mason free_extent_buffer(tree_root->node); 67839279cc3SChris Mason fail_sb_buffer: 6795f39d397SChris Mason free_extent_buffer(fs_info->sb_buffer); 68039279cc3SChris Mason fail_iput: 68139279cc3SChris Mason iput(fs_info->btree_inode); 68239279cc3SChris Mason fail: 68339279cc3SChris Mason kfree(extent_root); 68439279cc3SChris Mason kfree(tree_root); 68539279cc3SChris Mason kfree(fs_info); 68639279cc3SChris Mason return ERR_PTR(err); 687eb60ceacSChris Mason } 688eb60ceacSChris Mason 689e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 69079154b1bSChris Mason *root) 691cfaa7295SChris Mason { 692e66f709bSChris Mason int ret; 6935f39d397SChris Mason struct extent_buffer *super = root->fs_info->sb_buffer; 6945f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 6952c90e5d6SChris Mason 6965f39d397SChris Mason set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, super); 6975f39d397SChris Mason ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping, 6985f39d397SChris Mason super->start, super->len); 6995f39d397SChris Mason return ret; 700cfaa7295SChris Mason } 701cfaa7295SChris Mason 7025eda7b5eSChris Mason int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) 7032619ba1fSChris Mason { 7042619ba1fSChris Mason radix_tree_delete(&fs_info->fs_roots_radix, 7052619ba1fSChris Mason (unsigned long)root->root_key.objectid); 70658176a96SJosef Bacik btrfs_sysfs_del_root(root); 7072619ba1fSChris Mason if (root->inode) 7082619ba1fSChris Mason iput(root->inode); 7092619ba1fSChris Mason if (root->node) 7105f39d397SChris Mason free_extent_buffer(root->node); 7112619ba1fSChris Mason if (root->commit_root) 7125f39d397SChris Mason free_extent_buffer(root->commit_root); 71358176a96SJosef Bacik if (root->name) 71458176a96SJosef Bacik kfree(root->name); 7152619ba1fSChris Mason kfree(root); 7162619ba1fSChris Mason return 0; 7172619ba1fSChris Mason } 7182619ba1fSChris Mason 71935b7e476SChris Mason static int del_fs_roots(struct btrfs_fs_info *fs_info) 7200f7d52f4SChris Mason { 7210f7d52f4SChris Mason int ret; 7220f7d52f4SChris Mason struct btrfs_root *gang[8]; 7230f7d52f4SChris Mason int i; 7240f7d52f4SChris Mason 7250f7d52f4SChris Mason while(1) { 7260f7d52f4SChris Mason ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, 7270f7d52f4SChris Mason (void **)gang, 0, 7280f7d52f4SChris Mason ARRAY_SIZE(gang)); 7290f7d52f4SChris Mason if (!ret) 7300f7d52f4SChris Mason break; 7312619ba1fSChris Mason for (i = 0; i < ret; i++) 7325eda7b5eSChris Mason btrfs_free_fs_root(fs_info, gang[i]); 7330f7d52f4SChris Mason } 7340f7d52f4SChris Mason return 0; 7350f7d52f4SChris Mason } 736b4100d64SChris Mason 737e20d96d6SChris Mason int close_ctree(struct btrfs_root *root) 738eb60ceacSChris Mason { 7393768f368SChris Mason int ret; 740e089f05cSChris Mason struct btrfs_trans_handle *trans; 7410f7d52f4SChris Mason struct btrfs_fs_info *fs_info = root->fs_info; 742e089f05cSChris Mason 743facda1e7SChris Mason fs_info->closing = 1; 74408607c1bSChris Mason btrfs_transaction_flush_work(root); 7450f7d52f4SChris Mason mutex_lock(&fs_info->fs_mutex); 7466702ed49SChris Mason btrfs_defrag_dirty_roots(root->fs_info); 74779154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 74854aa1f4dSChris Mason ret = btrfs_commit_transaction(trans, root); 74979154b1bSChris Mason /* run commit again to drop the original snapshot */ 75079154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 75179154b1bSChris Mason btrfs_commit_transaction(trans, root); 75279154b1bSChris Mason ret = btrfs_write_and_wait_transaction(NULL, root); 7539f5fae2fSChris Mason BUG_ON(ret); 75479154b1bSChris Mason write_ctree_super(NULL, root); 7550f7d52f4SChris Mason mutex_unlock(&fs_info->fs_mutex); 756ed2ff2cbSChris Mason 7570f7d52f4SChris Mason if (fs_info->extent_root->node) 7585f39d397SChris Mason free_extent_buffer(fs_info->extent_root->node); 759f510cfecSChris Mason 7600f7d52f4SChris Mason if (fs_info->tree_root->node) 7615f39d397SChris Mason free_extent_buffer(fs_info->tree_root->node); 762f510cfecSChris Mason 7635f39d397SChris Mason free_extent_buffer(fs_info->sb_buffer); 7647eccb903SChris Mason 7659078a3e1SChris Mason btrfs_free_block_groups(root->fs_info); 7660f7d52f4SChris Mason del_fs_roots(fs_info); 76719c00ddcSChris Mason extent_map_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->extent_tree); 768db94535dSChris Mason truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); 769db94535dSChris Mason iput(fs_info->btree_inode); 77019c00ddcSChris Mason #if 0 77119c00ddcSChris Mason while(!list_empty(&fs_info->hashers)) { 77219c00ddcSChris Mason struct btrfs_hasher *hasher; 77319c00ddcSChris Mason hasher = list_entry(fs_info->hashers.next, struct btrfs_hasher, 77419c00ddcSChris Mason hashers); 77519c00ddcSChris Mason list_del(&hasher->hashers); 77619c00ddcSChris Mason crypto_free_hash(&fs_info->hash_tfm); 77719c00ddcSChris Mason kfree(hasher); 77819c00ddcSChris Mason } 77919c00ddcSChris Mason #endif 7800f7d52f4SChris Mason kfree(fs_info->extent_root); 7810f7d52f4SChris Mason kfree(fs_info->tree_root); 782eb60ceacSChris Mason return 0; 783eb60ceacSChris Mason } 784eb60ceacSChris Mason 7855f39d397SChris Mason int btrfs_buffer_uptodate(struct extent_buffer *buf) 786ccd467d6SChris Mason { 787810191ffSChris Mason struct inode *btree_inode = buf->first_page->mapping->host; 7885f39d397SChris Mason return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf); 7895f39d397SChris Mason } 7906702ed49SChris Mason 7915f39d397SChris Mason int btrfs_set_buffer_uptodate(struct extent_buffer *buf) 7925f39d397SChris Mason { 793810191ffSChris Mason struct inode *btree_inode = buf->first_page->mapping->host; 7945f39d397SChris Mason return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, 7955f39d397SChris Mason buf); 7965f39d397SChris Mason } 7975f39d397SChris Mason 7985f39d397SChris Mason void btrfs_mark_buffer_dirty(struct extent_buffer *buf) 7995f39d397SChris Mason { 800810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8015f39d397SChris Mason u64 transid = btrfs_header_generation(buf); 8025f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8036702ed49SChris Mason 804ccd467d6SChris Mason if (transid != root->fs_info->generation) { 805ccd467d6SChris Mason printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", 806db94535dSChris Mason (unsigned long long)buf->start, 807ccd467d6SChris Mason transid, root->fs_info->generation); 808ccd467d6SChris Mason WARN_ON(1); 809ccd467d6SChris Mason } 8105f39d397SChris Mason set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); 811eb60ceacSChris Mason } 812eb60ceacSChris Mason 813d3c2fdcfSChris Mason void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) 81435b7e476SChris Mason { 815d3c2fdcfSChris Mason balance_dirty_pages_ratelimited_nr( 816304fced6SChris Mason root->fs_info->btree_inode->i_mapping, 1); 81735b7e476SChris Mason } 8186b80053dSChris Mason 8196b80053dSChris Mason void btrfs_set_buffer_defrag(struct extent_buffer *buf) 8206b80053dSChris Mason { 821810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8226b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8236b80053dSChris Mason set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start, 8246b80053dSChris Mason buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS); 8256b80053dSChris Mason } 8266b80053dSChris Mason 8276b80053dSChris Mason void btrfs_set_buffer_defrag_done(struct extent_buffer *buf) 8286b80053dSChris Mason { 829810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8306b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8316b80053dSChris Mason set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start, 8326b80053dSChris Mason buf->start + buf->len - 1, EXTENT_DEFRAG_DONE, 8336b80053dSChris Mason GFP_NOFS); 8346b80053dSChris Mason } 8356b80053dSChris Mason 8366b80053dSChris Mason int btrfs_buffer_defrag(struct extent_buffer *buf) 8376b80053dSChris Mason { 838810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8396b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8406b80053dSChris Mason return test_range_bit(&BTRFS_I(btree_inode)->extent_tree, 8416b80053dSChris Mason buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0); 8426b80053dSChris Mason } 8436b80053dSChris Mason 8446b80053dSChris Mason int btrfs_buffer_defrag_done(struct extent_buffer *buf) 8456b80053dSChris Mason { 846810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8476b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8486b80053dSChris Mason return test_range_bit(&BTRFS_I(btree_inode)->extent_tree, 8496b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8506b80053dSChris Mason EXTENT_DEFRAG_DONE, 0); 8516b80053dSChris Mason } 8526b80053dSChris Mason 8536b80053dSChris Mason int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf) 8546b80053dSChris Mason { 855810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8566b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8576b80053dSChris Mason return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree, 8586b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8596b80053dSChris Mason EXTENT_DEFRAG_DONE, GFP_NOFS); 8606b80053dSChris Mason } 8616b80053dSChris Mason 8626b80053dSChris Mason int btrfs_clear_buffer_defrag(struct extent_buffer *buf) 8636b80053dSChris Mason { 864810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8656b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8666b80053dSChris Mason return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree, 8676b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8686b80053dSChris Mason EXTENT_DEFRAG, GFP_NOFS); 8696b80053dSChris Mason } 8706b80053dSChris Mason 8716b80053dSChris Mason int btrfs_read_buffer(struct extent_buffer *buf) 8726b80053dSChris Mason { 873810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8746b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8756b80053dSChris Mason return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 87619c00ddcSChris Mason buf, 0, 1); 8776b80053dSChris Mason } 8780da5468fSChris Mason 8790da5468fSChris Mason static struct extent_map_ops btree_extent_map_ops = { 8800da5468fSChris Mason .writepage_io_hook = btree_writepage_io_hook, 8810da5468fSChris Mason }; 882