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; 2130da5468fSChris Mason return extent_writepages(tree, mapping, btree_get_extent, wbc); 2140da5468fSChris Mason } 2150da5468fSChris Mason 2165f39d397SChris Mason int btree_readpage(struct file *file, struct page *page) 2175f39d397SChris Mason { 2185f39d397SChris Mason struct extent_map_tree *tree; 2195f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2205f39d397SChris Mason return extent_read_full_page(tree, page, btree_get_extent); 2215f39d397SChris Mason } 2225f39d397SChris Mason 2235f39d397SChris Mason static int btree_releasepage(struct page *page, gfp_t unused_gfp_flags) 2245f39d397SChris Mason { 2255f39d397SChris Mason struct extent_map_tree *tree; 2265f39d397SChris Mason int ret; 2275f39d397SChris Mason 2285f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2295f39d397SChris Mason ret = try_release_extent_mapping(tree, page); 2305f39d397SChris Mason if (ret == 1) { 2315f39d397SChris Mason ClearPagePrivate(page); 2325f39d397SChris Mason set_page_private(page, 0); 233d98237b3SChris Mason page_cache_release(page); 2345f39d397SChris Mason } 235d98237b3SChris Mason return ret; 236d98237b3SChris Mason } 237d98237b3SChris Mason 2385f39d397SChris Mason static void btree_invalidatepage(struct page *page, unsigned long offset) 239d98237b3SChris Mason { 2405f39d397SChris Mason struct extent_map_tree *tree; 2415f39d397SChris Mason tree = &BTRFS_I(page->mapping->host)->extent_tree; 2425f39d397SChris Mason extent_invalidatepage(tree, page, offset); 2435f39d397SChris Mason btree_releasepage(page, GFP_NOFS); 244d98237b3SChris Mason } 245d98237b3SChris Mason 2465f39d397SChris Mason #if 0 247d98237b3SChris Mason static int btree_writepage(struct page *page, struct writeback_control *wbc) 248d98237b3SChris Mason { 24987cbda5cSChris Mason struct buffer_head *bh; 2500f7d52f4SChris Mason struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; 25187cbda5cSChris Mason struct buffer_head *head; 25287cbda5cSChris Mason if (!page_has_buffers(page)) { 25387cbda5cSChris Mason create_empty_buffers(page, root->fs_info->sb->s_blocksize, 25487cbda5cSChris Mason (1 << BH_Dirty)|(1 << BH_Uptodate)); 25587cbda5cSChris Mason } 25687cbda5cSChris Mason head = page_buffers(page); 25787cbda5cSChris Mason bh = head; 25887cbda5cSChris Mason do { 25987cbda5cSChris Mason if (buffer_dirty(bh)) 26087cbda5cSChris Mason csum_tree_block(root, bh, 0); 26187cbda5cSChris Mason bh = bh->b_this_page; 26287cbda5cSChris Mason } while (bh != head); 263d98237b3SChris Mason return block_write_full_page(page, btree_get_block, wbc); 264d98237b3SChris Mason } 2655f39d397SChris Mason #endif 266d98237b3SChris Mason 267d98237b3SChris Mason static struct address_space_operations btree_aops = { 268d98237b3SChris Mason .readpage = btree_readpage, 269d98237b3SChris Mason .writepage = btree_writepage, 2700da5468fSChris Mason .writepages = btree_writepages, 2715f39d397SChris Mason .releasepage = btree_releasepage, 2725f39d397SChris Mason .invalidatepage = btree_invalidatepage, 273d98237b3SChris Mason .sync_page = block_sync_page, 274d98237b3SChris Mason }; 275123abc88SChris Mason 276db94535dSChris Mason int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) 277090d1875SChris Mason { 2785f39d397SChris Mason struct extent_buffer *buf = NULL; 2795f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 280de428b63SChris Mason int ret = 0; 281090d1875SChris Mason 282db94535dSChris Mason buf = btrfs_find_create_tree_block(root, bytenr, blocksize); 2835f39d397SChris Mason if (!buf) 284090d1875SChris Mason return 0; 2855f39d397SChris Mason read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 28619c00ddcSChris Mason buf, 0, 0); 2875f39d397SChris Mason free_extent_buffer(buf); 288de428b63SChris Mason return ret; 289090d1875SChris Mason } 290090d1875SChris Mason 291db94535dSChris Mason struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, 292db94535dSChris Mason u32 blocksize) 293e20d96d6SChris Mason { 2945f39d397SChris Mason struct extent_buffer *buf = NULL; 2955f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 29619c00ddcSChris Mason struct extent_map_tree *extent_tree; 29719c00ddcSChris Mason int ret; 29819c00ddcSChris Mason 29919c00ddcSChris Mason extent_tree = &BTRFS_I(btree_inode)->extent_tree; 300e20d96d6SChris Mason 301db94535dSChris Mason buf = btrfs_find_create_tree_block(root, bytenr, blocksize); 3025f39d397SChris Mason if (!buf) 303d98237b3SChris Mason return NULL; 3045f39d397SChris Mason read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 30519c00ddcSChris Mason buf, 0, 1); 30619c00ddcSChris Mason if (buf->flags & EXTENT_CSUM) { 30719c00ddcSChris Mason return buf; 30819c00ddcSChris Mason } 30919c00ddcSChris Mason if (test_range_bit(extent_tree, buf->start, buf->start + buf->len - 1, 31019c00ddcSChris Mason EXTENT_CSUM, 1)) { 31119c00ddcSChris Mason buf->flags |= EXTENT_CSUM; 31219c00ddcSChris Mason return buf; 31319c00ddcSChris Mason } 31419c00ddcSChris Mason ret = csum_tree_block(root, buf, 1); 31519c00ddcSChris Mason set_extent_bits(extent_tree, buf->start, 31619c00ddcSChris Mason buf->start + buf->len - 1, 31719c00ddcSChris Mason EXTENT_CSUM, GFP_NOFS); 31819c00ddcSChris Mason buf->flags |= EXTENT_CSUM; 3195f39d397SChris Mason return buf; 320eb60ceacSChris Mason } 321eb60ceacSChris Mason 322e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 3235f39d397SChris Mason struct extent_buffer *buf) 324ed2ff2cbSChris Mason { 3255f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 3265f39d397SChris Mason clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); 3275f39d397SChris Mason return 0; 3285f39d397SChris Mason } 3295f39d397SChris Mason 3305f39d397SChris Mason int wait_on_tree_block_writeback(struct btrfs_root *root, 3315f39d397SChris Mason struct extent_buffer *buf) 3325f39d397SChris Mason { 3335f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 3345f39d397SChris Mason wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->extent_tree, 3355f39d397SChris Mason buf); 3365f39d397SChris Mason return 0; 3375f39d397SChris Mason } 3385f39d397SChris Mason 339db94535dSChris Mason static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, 3409f5fae2fSChris Mason struct btrfs_root *root, 3419f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 342e20d96d6SChris Mason u64 objectid) 343d97e63b6SChris Mason { 344cfaa7295SChris Mason root->node = NULL; 3450f7d52f4SChris Mason root->inode = NULL; 346a28ec197SChris Mason root->commit_root = NULL; 347db94535dSChris Mason root->sectorsize = sectorsize; 348db94535dSChris Mason root->nodesize = nodesize; 349db94535dSChris Mason root->leafsize = leafsize; 350123abc88SChris Mason root->ref_cows = 0; 3519f5fae2fSChris Mason root->fs_info = fs_info; 3520f7d52f4SChris Mason root->objectid = objectid; 3530f7d52f4SChris Mason root->last_trans = 0; 3541b05da2eSChris Mason root->highest_inode = 0; 3551b05da2eSChris Mason root->last_inode_alloc = 0; 35658176a96SJosef Bacik root->name = NULL; 3573768f368SChris Mason memset(&root->root_key, 0, sizeof(root->root_key)); 3583768f368SChris Mason memset(&root->root_item, 0, sizeof(root->root_item)); 3596702ed49SChris Mason memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); 36058176a96SJosef Bacik memset(&root->root_kobj, 0, sizeof(root->root_kobj)); 36158176a96SJosef Bacik init_completion(&root->kobj_unregister); 362011410bdSChris Mason init_rwsem(&root->snap_sem); 3636702ed49SChris Mason root->defrag_running = 0; 3646702ed49SChris Mason root->defrag_level = 0; 3654d775673SChris Mason root->root_key.objectid = objectid; 3663768f368SChris Mason return 0; 3673768f368SChris Mason } 3683768f368SChris Mason 369db94535dSChris Mason static int find_and_setup_root(struct btrfs_root *tree_root, 3709f5fae2fSChris Mason struct btrfs_fs_info *fs_info, 3719f5fae2fSChris Mason u64 objectid, 372e20d96d6SChris Mason struct btrfs_root *root) 3733768f368SChris Mason { 3743768f368SChris Mason int ret; 375db94535dSChris Mason u32 blocksize; 3763768f368SChris Mason 377db94535dSChris Mason __setup_root(tree_root->nodesize, tree_root->leafsize, 378db94535dSChris Mason tree_root->sectorsize, root, fs_info, objectid); 3793768f368SChris Mason ret = btrfs_find_last_root(tree_root, objectid, 3803768f368SChris Mason &root->root_item, &root->root_key); 3813768f368SChris Mason BUG_ON(ret); 3823768f368SChris Mason 383db94535dSChris Mason blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); 384db94535dSChris Mason root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), 385db94535dSChris Mason blocksize); 3863768f368SChris Mason BUG_ON(!root->node); 387d97e63b6SChris Mason return 0; 388d97e63b6SChris Mason } 389d97e63b6SChris Mason 3905eda7b5eSChris Mason struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, 3910f7d52f4SChris Mason struct btrfs_key *location) 3920f7d52f4SChris Mason { 3930f7d52f4SChris Mason struct btrfs_root *root; 3940f7d52f4SChris Mason struct btrfs_root *tree_root = fs_info->tree_root; 3950f7d52f4SChris Mason struct btrfs_path *path; 3965f39d397SChris Mason struct extent_buffer *l; 3971b05da2eSChris Mason u64 highest_inode; 398db94535dSChris Mason u32 blocksize; 3990f7d52f4SChris Mason int ret = 0; 4000f7d52f4SChris Mason 4015eda7b5eSChris Mason root = kzalloc(sizeof(*root), GFP_NOFS); 4020cf6c620SChris Mason if (!root) 4030f7d52f4SChris Mason return ERR_PTR(-ENOMEM); 4040f7d52f4SChris Mason if (location->offset == (u64)-1) { 405db94535dSChris Mason ret = find_and_setup_root(tree_root, fs_info, 4060f7d52f4SChris Mason location->objectid, root); 4070f7d52f4SChris Mason if (ret) { 4080f7d52f4SChris Mason kfree(root); 4090f7d52f4SChris Mason return ERR_PTR(ret); 4100f7d52f4SChris Mason } 4110f7d52f4SChris Mason goto insert; 4120f7d52f4SChris Mason } 4130f7d52f4SChris Mason 414db94535dSChris Mason __setup_root(tree_root->nodesize, tree_root->leafsize, 415db94535dSChris Mason tree_root->sectorsize, root, fs_info, 4160f7d52f4SChris Mason location->objectid); 4170f7d52f4SChris Mason 4180f7d52f4SChris Mason path = btrfs_alloc_path(); 4190f7d52f4SChris Mason BUG_ON(!path); 4200f7d52f4SChris Mason ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); 4210f7d52f4SChris Mason if (ret != 0) { 4220f7d52f4SChris Mason if (ret > 0) 4230f7d52f4SChris Mason ret = -ENOENT; 4240f7d52f4SChris Mason goto out; 4250f7d52f4SChris Mason } 4265f39d397SChris Mason l = path->nodes[0]; 4275f39d397SChris Mason read_extent_buffer(l, &root->root_item, 4285f39d397SChris Mason btrfs_item_ptr_offset(l, path->slots[0]), 4290f7d52f4SChris Mason sizeof(root->root_item)); 43044b36eb2SYan Zheng memcpy(&root->root_key, location, sizeof(*location)); 4310f7d52f4SChris Mason ret = 0; 4320f7d52f4SChris Mason out: 4330f7d52f4SChris Mason btrfs_release_path(root, path); 4340f7d52f4SChris Mason btrfs_free_path(path); 4350f7d52f4SChris Mason if (ret) { 4360f7d52f4SChris Mason kfree(root); 4370f7d52f4SChris Mason return ERR_PTR(ret); 4380f7d52f4SChris Mason } 439db94535dSChris Mason blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); 440db94535dSChris Mason root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), 441db94535dSChris Mason blocksize); 4420f7d52f4SChris Mason BUG_ON(!root->node); 4430f7d52f4SChris Mason insert: 4440f7d52f4SChris Mason root->ref_cows = 1; 4455eda7b5eSChris Mason ret = btrfs_find_highest_inode(root, &highest_inode); 4465eda7b5eSChris Mason if (ret == 0) { 4475eda7b5eSChris Mason root->highest_inode = highest_inode; 4485eda7b5eSChris Mason root->last_inode_alloc = highest_inode; 4495eda7b5eSChris Mason } 4505eda7b5eSChris Mason return root; 4515eda7b5eSChris Mason } 4525eda7b5eSChris Mason 4535eda7b5eSChris Mason struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 45458176a96SJosef Bacik struct btrfs_key *location, 45558176a96SJosef Bacik const char *name, int namelen) 4565eda7b5eSChris Mason { 4575eda7b5eSChris Mason struct btrfs_root *root; 4585eda7b5eSChris Mason int ret; 4595eda7b5eSChris Mason 4605eda7b5eSChris Mason root = radix_tree_lookup(&fs_info->fs_roots_radix, 4615eda7b5eSChris Mason (unsigned long)location->objectid); 4625eda7b5eSChris Mason if (root) 4635eda7b5eSChris Mason return root; 4645eda7b5eSChris Mason 4655eda7b5eSChris Mason root = btrfs_read_fs_root_no_radix(fs_info, location); 4665eda7b5eSChris Mason if (IS_ERR(root)) 4675eda7b5eSChris Mason return root; 4682619ba1fSChris Mason ret = radix_tree_insert(&fs_info->fs_roots_radix, 4692619ba1fSChris Mason (unsigned long)root->root_key.objectid, 4700f7d52f4SChris Mason root); 4710f7d52f4SChris Mason if (ret) { 4725f39d397SChris Mason free_extent_buffer(root->node); 4730f7d52f4SChris Mason kfree(root); 4740f7d52f4SChris Mason return ERR_PTR(ret); 4750f7d52f4SChris Mason } 47658176a96SJosef Bacik 47758176a96SJosef Bacik ret = btrfs_set_root_name(root, name, namelen); 47858176a96SJosef Bacik if (ret) { 4795f39d397SChris Mason free_extent_buffer(root->node); 48058176a96SJosef Bacik kfree(root); 48158176a96SJosef Bacik return ERR_PTR(ret); 48258176a96SJosef Bacik } 48358176a96SJosef Bacik 48458176a96SJosef Bacik ret = btrfs_sysfs_add_root(root); 48558176a96SJosef Bacik if (ret) { 4865f39d397SChris Mason free_extent_buffer(root->node); 48758176a96SJosef Bacik kfree(root->name); 48858176a96SJosef Bacik kfree(root); 48958176a96SJosef Bacik return ERR_PTR(ret); 49058176a96SJosef Bacik } 49158176a96SJosef Bacik 4925ce14bbcSChris Mason ret = btrfs_find_dead_roots(fs_info->tree_root, 4935ce14bbcSChris Mason root->root_key.objectid, root); 4945ce14bbcSChris Mason BUG_ON(ret); 4955ce14bbcSChris Mason 4960f7d52f4SChris Mason return root; 4970f7d52f4SChris Mason } 49819c00ddcSChris Mason #if 0 49919c00ddcSChris Mason static int add_hasher(struct btrfs_fs_info *info, char *type) { 50019c00ddcSChris Mason struct btrfs_hasher *hasher; 5010f7d52f4SChris Mason 50219c00ddcSChris Mason hasher = kmalloc(sizeof(*hasher), GFP_NOFS); 50319c00ddcSChris Mason if (!hasher) 50419c00ddcSChris Mason return -ENOMEM; 50519c00ddcSChris Mason hasher->hash_tfm = crypto_alloc_hash(type, 0, CRYPTO_ALG_ASYNC); 50619c00ddcSChris Mason if (!hasher->hash_tfm) { 50719c00ddcSChris Mason kfree(hasher); 50819c00ddcSChris Mason return -EINVAL; 50919c00ddcSChris Mason } 51019c00ddcSChris Mason spin_lock(&info->hash_lock); 51119c00ddcSChris Mason list_add(&hasher->list, &info->hashers); 51219c00ddcSChris Mason spin_unlock(&info->hash_lock); 51319c00ddcSChris Mason return 0; 51419c00ddcSChris Mason } 51519c00ddcSChris Mason #endif 5162c90e5d6SChris Mason struct btrfs_root *open_ctree(struct super_block *sb) 517eb60ceacSChris Mason { 518db94535dSChris Mason u32 sectorsize; 519db94535dSChris Mason u32 nodesize; 520db94535dSChris Mason u32 leafsize; 521db94535dSChris Mason u32 blocksize; 522e20d96d6SChris Mason struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), 523e20d96d6SChris Mason GFP_NOFS); 524e20d96d6SChris Mason struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), 525e20d96d6SChris Mason GFP_NOFS); 526e20d96d6SChris Mason struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info), 527e20d96d6SChris Mason GFP_NOFS); 528eb60ceacSChris Mason int ret; 52939279cc3SChris Mason int err = -EIO; 5302c90e5d6SChris Mason struct btrfs_super_block *disk_super; 531eb60ceacSChris Mason 53239279cc3SChris Mason if (!extent_root || !tree_root || !fs_info) { 53339279cc3SChris Mason err = -ENOMEM; 53439279cc3SChris Mason goto fail; 53539279cc3SChris Mason } 5360f7d52f4SChris Mason INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS); 5378fd17795SChris Mason INIT_LIST_HEAD(&fs_info->trans_list); 538facda1e7SChris Mason INIT_LIST_HEAD(&fs_info->dead_roots); 53919c00ddcSChris Mason INIT_LIST_HEAD(&fs_info->hashers); 54019c00ddcSChris Mason spin_lock_init(&fs_info->hash_lock); 54119c00ddcSChris Mason 54258176a96SJosef Bacik memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); 54358176a96SJosef Bacik init_completion(&fs_info->kobj_unregister); 5442c90e5d6SChris Mason sb_set_blocksize(sb, 4096); 5459f5fae2fSChris Mason fs_info->running_transaction = NULL; 54615ee9bc7SJosef Bacik fs_info->last_trans_committed = 0; 5479f5fae2fSChris Mason fs_info->tree_root = tree_root; 5489f5fae2fSChris Mason fs_info->extent_root = extent_root; 549e20d96d6SChris Mason fs_info->sb = sb; 550d98237b3SChris Mason fs_info->btree_inode = new_inode(sb); 551d98237b3SChris Mason fs_info->btree_inode->i_ino = 1; 5522c90e5d6SChris Mason fs_info->btree_inode->i_nlink = 1; 553d98237b3SChris Mason fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; 554d98237b3SChris Mason fs_info->btree_inode->i_mapping->a_ops = &btree_aops; 5555f39d397SChris Mason extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, 5565f39d397SChris Mason fs_info->btree_inode->i_mapping, 5575f39d397SChris Mason GFP_NOFS); 5580da5468fSChris Mason BTRFS_I(fs_info->btree_inode)->extent_tree.ops = &btree_extent_map_ops; 5590da5468fSChris Mason 560f510cfecSChris Mason extent_map_tree_init(&fs_info->free_space_cache, 561f510cfecSChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 56296b5179dSChris Mason extent_map_tree_init(&fs_info->block_group_cache, 56396b5179dSChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5641a5bc167SChris Mason extent_map_tree_init(&fs_info->pinned_extents, 5651a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5661a5bc167SChris Mason extent_map_tree_init(&fs_info->pending_del, 5671a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 5681a5bc167SChris Mason extent_map_tree_init(&fs_info->extent_ins, 5691a5bc167SChris Mason fs_info->btree_inode->i_mapping, GFP_NOFS); 570e66f709bSChris Mason fs_info->do_barriers = 1; 571facda1e7SChris Mason fs_info->closing = 0; 572facda1e7SChris Mason 57308607c1bSChris Mason INIT_DELAYED_WORK(&fs_info->trans_work, btrfs_transaction_cleaner); 5740f7d52f4SChris Mason BTRFS_I(fs_info->btree_inode)->root = tree_root; 5750f7d52f4SChris Mason memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 5760f7d52f4SChris Mason sizeof(struct btrfs_key)); 57722b0ebdaSChris Mason insert_inode_hash(fs_info->btree_inode); 578d98237b3SChris Mason mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); 57939279cc3SChris Mason 58079154b1bSChris Mason mutex_init(&fs_info->trans_mutex); 581d561c025SChris Mason mutex_init(&fs_info->fs_mutex); 5823768f368SChris Mason 58319c00ddcSChris Mason #if 0 58419c00ddcSChris Mason ret = add_hasher(fs_info, "crc32c"); 58519c00ddcSChris Mason if (ret) { 58619c00ddcSChris Mason printk("btrfs: failed hash setup, modprobe cryptomgr?\n"); 58719c00ddcSChris Mason err = -ENOMEM; 58819c00ddcSChris Mason goto fail_iput; 58919c00ddcSChris Mason } 59019c00ddcSChris Mason #endif 591db94535dSChris Mason __setup_root(512, 512, 512, tree_root, 5922c90e5d6SChris Mason fs_info, BTRFS_ROOT_TREE_OBJECTID); 5937eccb903SChris Mason 5942c90e5d6SChris Mason fs_info->sb_buffer = read_tree_block(tree_root, 595db94535dSChris Mason BTRFS_SUPER_INFO_OFFSET, 596db94535dSChris Mason 512); 597d98237b3SChris Mason 5980f7d52f4SChris Mason if (!fs_info->sb_buffer) 59939279cc3SChris Mason goto fail_iput; 60039279cc3SChris Mason 6015f39d397SChris Mason read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0, 6025f39d397SChris Mason sizeof(fs_info->super_copy)); 6035f39d397SChris Mason 6045f39d397SChris Mason read_extent_buffer(fs_info->sb_buffer, fs_info->fsid, 6055f39d397SChris Mason (unsigned long)btrfs_super_fsid(fs_info->sb_buffer), 6065f39d397SChris Mason BTRFS_FSID_SIZE); 6075f39d397SChris Mason disk_super = &fs_info->super_copy; 6080f7d52f4SChris Mason if (!btrfs_super_root(disk_super)) 60939279cc3SChris Mason goto fail_sb_buffer; 6100f7d52f4SChris Mason 611db94535dSChris Mason nodesize = btrfs_super_nodesize(disk_super); 612db94535dSChris Mason leafsize = btrfs_super_leafsize(disk_super); 613db94535dSChris Mason sectorsize = btrfs_super_sectorsize(disk_super); 614db94535dSChris Mason tree_root->nodesize = nodesize; 615db94535dSChris Mason tree_root->leafsize = leafsize; 616db94535dSChris Mason tree_root->sectorsize = sectorsize; 617ff79f819SChris Mason sb_set_blocksize(sb, sectorsize); 618db94535dSChris Mason 6198352d8a4SChris Mason i_size_write(fs_info->btree_inode, 620db94535dSChris Mason btrfs_super_total_bytes(disk_super)); 6218352d8a4SChris Mason 62239279cc3SChris Mason if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, 62339279cc3SChris Mason sizeof(disk_super->magic))) { 62439279cc3SChris Mason printk("btrfs: valid FS not found on %s\n", sb->s_id); 62539279cc3SChris Mason goto fail_sb_buffer; 62639279cc3SChris Mason } 62719c00ddcSChris Mason 628db94535dSChris Mason blocksize = btrfs_level_size(tree_root, 629db94535dSChris Mason btrfs_super_root_level(disk_super)); 63019c00ddcSChris Mason 631e20d96d6SChris Mason tree_root->node = read_tree_block(tree_root, 632db94535dSChris Mason btrfs_super_root(disk_super), 633db94535dSChris Mason blocksize); 63439279cc3SChris Mason if (!tree_root->node) 63539279cc3SChris Mason goto fail_sb_buffer; 6363768f368SChris Mason 6372c90e5d6SChris Mason mutex_lock(&fs_info->fs_mutex); 638db94535dSChris Mason 639db94535dSChris Mason ret = find_and_setup_root(tree_root, fs_info, 640e20d96d6SChris Mason BTRFS_EXTENT_TREE_OBJECTID, extent_root); 64139279cc3SChris Mason if (ret) { 64239279cc3SChris Mason mutex_unlock(&fs_info->fs_mutex); 64339279cc3SChris Mason goto fail_tree_root; 64439279cc3SChris Mason } 6453768f368SChris Mason 6469078a3e1SChris Mason btrfs_read_block_groups(extent_root); 6479078a3e1SChris Mason 6480f7d52f4SChris Mason fs_info->generation = btrfs_super_generation(disk_super) + 1; 6495be6f7f1SChris Mason mutex_unlock(&fs_info->fs_mutex); 6500f7d52f4SChris Mason return tree_root; 65139279cc3SChris Mason 65239279cc3SChris Mason fail_tree_root: 6535f39d397SChris Mason free_extent_buffer(tree_root->node); 65439279cc3SChris Mason fail_sb_buffer: 6555f39d397SChris Mason free_extent_buffer(fs_info->sb_buffer); 65639279cc3SChris Mason fail_iput: 65739279cc3SChris Mason iput(fs_info->btree_inode); 65839279cc3SChris Mason fail: 65939279cc3SChris Mason kfree(extent_root); 66039279cc3SChris Mason kfree(tree_root); 66139279cc3SChris Mason kfree(fs_info); 66239279cc3SChris Mason return ERR_PTR(err); 663eb60ceacSChris Mason } 664eb60ceacSChris Mason 665e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 66679154b1bSChris Mason *root) 667cfaa7295SChris Mason { 668e66f709bSChris Mason int ret; 6695f39d397SChris Mason struct extent_buffer *super = root->fs_info->sb_buffer; 6705f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 6712c90e5d6SChris Mason 6725f39d397SChris Mason set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, super); 6735f39d397SChris Mason ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping, 6745f39d397SChris Mason super->start, super->len); 6755f39d397SChris Mason return ret; 676cfaa7295SChris Mason } 677cfaa7295SChris Mason 6785eda7b5eSChris Mason int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) 6792619ba1fSChris Mason { 6802619ba1fSChris Mason radix_tree_delete(&fs_info->fs_roots_radix, 6812619ba1fSChris Mason (unsigned long)root->root_key.objectid); 68258176a96SJosef Bacik btrfs_sysfs_del_root(root); 6832619ba1fSChris Mason if (root->inode) 6842619ba1fSChris Mason iput(root->inode); 6852619ba1fSChris Mason if (root->node) 6865f39d397SChris Mason free_extent_buffer(root->node); 6872619ba1fSChris Mason if (root->commit_root) 6885f39d397SChris Mason free_extent_buffer(root->commit_root); 68958176a96SJosef Bacik if (root->name) 69058176a96SJosef Bacik kfree(root->name); 6912619ba1fSChris Mason kfree(root); 6922619ba1fSChris Mason return 0; 6932619ba1fSChris Mason } 6942619ba1fSChris Mason 69535b7e476SChris Mason static int del_fs_roots(struct btrfs_fs_info *fs_info) 6960f7d52f4SChris Mason { 6970f7d52f4SChris Mason int ret; 6980f7d52f4SChris Mason struct btrfs_root *gang[8]; 6990f7d52f4SChris Mason int i; 7000f7d52f4SChris Mason 7010f7d52f4SChris Mason while(1) { 7020f7d52f4SChris Mason ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, 7030f7d52f4SChris Mason (void **)gang, 0, 7040f7d52f4SChris Mason ARRAY_SIZE(gang)); 7050f7d52f4SChris Mason if (!ret) 7060f7d52f4SChris Mason break; 7072619ba1fSChris Mason for (i = 0; i < ret; i++) 7085eda7b5eSChris Mason btrfs_free_fs_root(fs_info, gang[i]); 7090f7d52f4SChris Mason } 7100f7d52f4SChris Mason return 0; 7110f7d52f4SChris Mason } 712b4100d64SChris Mason 713e20d96d6SChris Mason int close_ctree(struct btrfs_root *root) 714eb60ceacSChris Mason { 7153768f368SChris Mason int ret; 716e089f05cSChris Mason struct btrfs_trans_handle *trans; 7170f7d52f4SChris Mason struct btrfs_fs_info *fs_info = root->fs_info; 718e089f05cSChris Mason 719facda1e7SChris Mason fs_info->closing = 1; 72008607c1bSChris Mason btrfs_transaction_flush_work(root); 7210f7d52f4SChris Mason mutex_lock(&fs_info->fs_mutex); 7226702ed49SChris Mason btrfs_defrag_dirty_roots(root->fs_info); 72379154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 72454aa1f4dSChris Mason ret = btrfs_commit_transaction(trans, root); 72579154b1bSChris Mason /* run commit again to drop the original snapshot */ 72679154b1bSChris Mason trans = btrfs_start_transaction(root, 1); 72779154b1bSChris Mason btrfs_commit_transaction(trans, root); 72879154b1bSChris Mason ret = btrfs_write_and_wait_transaction(NULL, root); 7299f5fae2fSChris Mason BUG_ON(ret); 73079154b1bSChris Mason write_ctree_super(NULL, root); 7310f7d52f4SChris Mason mutex_unlock(&fs_info->fs_mutex); 732ed2ff2cbSChris Mason 7330f7d52f4SChris Mason if (fs_info->extent_root->node) 7345f39d397SChris Mason free_extent_buffer(fs_info->extent_root->node); 735f510cfecSChris Mason 7360f7d52f4SChris Mason if (fs_info->tree_root->node) 7375f39d397SChris Mason free_extent_buffer(fs_info->tree_root->node); 738f510cfecSChris Mason 7395f39d397SChris Mason free_extent_buffer(fs_info->sb_buffer); 7407eccb903SChris Mason 7419078a3e1SChris Mason btrfs_free_block_groups(root->fs_info); 7420f7d52f4SChris Mason del_fs_roots(fs_info); 74319c00ddcSChris Mason extent_map_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->extent_tree); 744db94535dSChris Mason truncate_inode_pages(fs_info->btree_inode->i_mapping, 0); 745db94535dSChris Mason iput(fs_info->btree_inode); 74619c00ddcSChris Mason #if 0 74719c00ddcSChris Mason while(!list_empty(&fs_info->hashers)) { 74819c00ddcSChris Mason struct btrfs_hasher *hasher; 74919c00ddcSChris Mason hasher = list_entry(fs_info->hashers.next, struct btrfs_hasher, 75019c00ddcSChris Mason hashers); 75119c00ddcSChris Mason list_del(&hasher->hashers); 75219c00ddcSChris Mason crypto_free_hash(&fs_info->hash_tfm); 75319c00ddcSChris Mason kfree(hasher); 75419c00ddcSChris Mason } 75519c00ddcSChris Mason #endif 7560f7d52f4SChris Mason kfree(fs_info->extent_root); 7570f7d52f4SChris Mason kfree(fs_info->tree_root); 758eb60ceacSChris Mason return 0; 759eb60ceacSChris Mason } 760eb60ceacSChris Mason 7615f39d397SChris Mason int btrfs_buffer_uptodate(struct extent_buffer *buf) 762ccd467d6SChris Mason { 763810191ffSChris Mason struct inode *btree_inode = buf->first_page->mapping->host; 7645f39d397SChris Mason return extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, buf); 7655f39d397SChris Mason } 7666702ed49SChris Mason 7675f39d397SChris Mason int btrfs_set_buffer_uptodate(struct extent_buffer *buf) 7685f39d397SChris Mason { 769810191ffSChris Mason struct inode *btree_inode = buf->first_page->mapping->host; 7705f39d397SChris Mason return set_extent_buffer_uptodate(&BTRFS_I(btree_inode)->extent_tree, 7715f39d397SChris Mason buf); 7725f39d397SChris Mason } 7735f39d397SChris Mason 7745f39d397SChris Mason void btrfs_mark_buffer_dirty(struct extent_buffer *buf) 7755f39d397SChris Mason { 776810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 7775f39d397SChris Mason u64 transid = btrfs_header_generation(buf); 7785f39d397SChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 7796702ed49SChris Mason 780ccd467d6SChris Mason if (transid != root->fs_info->generation) { 781ccd467d6SChris Mason printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", 782db94535dSChris Mason (unsigned long long)buf->start, 783ccd467d6SChris Mason transid, root->fs_info->generation); 784ccd467d6SChris Mason WARN_ON(1); 785ccd467d6SChris Mason } 7865f39d397SChris Mason set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); 787eb60ceacSChris Mason } 788eb60ceacSChris Mason 789d3c2fdcfSChris Mason void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) 79035b7e476SChris Mason { 791d3c2fdcfSChris Mason balance_dirty_pages_ratelimited_nr( 792304fced6SChris Mason root->fs_info->btree_inode->i_mapping, 1); 79335b7e476SChris Mason } 7946b80053dSChris Mason 7956b80053dSChris Mason void btrfs_set_buffer_defrag(struct extent_buffer *buf) 7966b80053dSChris Mason { 797810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 7986b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 7996b80053dSChris Mason set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start, 8006b80053dSChris Mason buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS); 8016b80053dSChris Mason } 8026b80053dSChris Mason 8036b80053dSChris Mason void btrfs_set_buffer_defrag_done(struct extent_buffer *buf) 8046b80053dSChris Mason { 805810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8066b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8076b80053dSChris Mason set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start, 8086b80053dSChris Mason buf->start + buf->len - 1, EXTENT_DEFRAG_DONE, 8096b80053dSChris Mason GFP_NOFS); 8106b80053dSChris Mason } 8116b80053dSChris Mason 8126b80053dSChris Mason int btrfs_buffer_defrag(struct extent_buffer *buf) 8136b80053dSChris Mason { 814810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8156b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8166b80053dSChris Mason return test_range_bit(&BTRFS_I(btree_inode)->extent_tree, 8176b80053dSChris Mason buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0); 8186b80053dSChris Mason } 8196b80053dSChris Mason 8206b80053dSChris Mason int btrfs_buffer_defrag_done(struct extent_buffer *buf) 8216b80053dSChris Mason { 822810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8236b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8246b80053dSChris Mason return test_range_bit(&BTRFS_I(btree_inode)->extent_tree, 8256b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8266b80053dSChris Mason EXTENT_DEFRAG_DONE, 0); 8276b80053dSChris Mason } 8286b80053dSChris Mason 8296b80053dSChris Mason int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf) 8306b80053dSChris Mason { 831810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8326b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8336b80053dSChris Mason return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree, 8346b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8356b80053dSChris Mason EXTENT_DEFRAG_DONE, GFP_NOFS); 8366b80053dSChris Mason } 8376b80053dSChris Mason 8386b80053dSChris Mason int btrfs_clear_buffer_defrag(struct extent_buffer *buf) 8396b80053dSChris Mason { 840810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8416b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8426b80053dSChris Mason return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree, 8436b80053dSChris Mason buf->start, buf->start + buf->len - 1, 8446b80053dSChris Mason EXTENT_DEFRAG, GFP_NOFS); 8456b80053dSChris Mason } 8466b80053dSChris Mason 8476b80053dSChris Mason int btrfs_read_buffer(struct extent_buffer *buf) 8486b80053dSChris Mason { 849810191ffSChris Mason struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; 8506b80053dSChris Mason struct inode *btree_inode = root->fs_info->btree_inode; 8516b80053dSChris Mason return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree, 85219c00ddcSChris Mason buf, 0, 1); 8536b80053dSChris Mason } 8540da5468fSChris Mason 8550da5468fSChris Mason static struct extent_map_ops btree_extent_map_ops = { 8560da5468fSChris Mason .writepage_io_hook = btree_writepage_io_hook, 8570da5468fSChris Mason }; 858