diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 603 |
1 files changed, 305 insertions, 298 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3a57f99d96aa..18004169552c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -68,15 +68,15 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, int read_only); static void btrfs_destroy_ordered_extents(struct btrfs_root *root); static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root); + struct btrfs_fs_info *fs_info); static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root); -static int btrfs_destroy_marked_extents(struct btrfs_root *root, +static int btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info, struct extent_io_tree *dirty_pages, int mark); -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, +static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, struct extent_io_tree *pinned_extents); -static int btrfs_cleanup_transaction(struct btrfs_root *root); -static void btrfs_error_commit_super(struct btrfs_root *root); +static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info); +static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info); /* * btrfs_end_io_wq structs are used to do processing in task context when an IO @@ -224,6 +224,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, struct page *page, size_t pg_offset, u64 start, u64 len, int create) { + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct extent_map *em; int ret; @@ -231,8 +232,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, start, len); if (em) { - em->bdev = - BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; + em->bdev = fs_info->fs_devices->latest_bdev; read_unlock(&em_tree->lock); goto out; } @@ -247,7 +247,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, em->len = (u64)-1; em->block_len = (u64)-1; em->block_start = 0; - em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; + em->bdev = fs_info->fs_devices->latest_bdev; write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em, 0); @@ -271,7 +271,7 @@ u32 btrfs_csum_data(char *data, u32 seed, size_t len) return btrfs_crc32c(seed, data, len); } -void btrfs_csum_final(u32 crc, char *result) +void btrfs_csum_final(u32 crc, u8 *result) { put_unaligned_le32(~crc, result); } @@ -440,7 +440,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info, * helper to read a given tree block, doing retries as required when * the checksums don't match and we have alternate mirrors to try. */ -static int btree_read_extent_buffer_pages(struct btrfs_root *root, +static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, u64 parent_transid) { @@ -452,7 +452,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, int failed_mirror = 0; clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); - io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; + io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree; while (1) { ret = read_extent_buffer_pages(io_tree, eb, WAIT_COMPLETE, btree_get_extent, mirror_num); @@ -472,7 +472,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) break; - num_copies = btrfs_num_copies(root->fs_info, + num_copies = btrfs_num_copies(fs_info, eb->start, eb->len); if (num_copies == 1) break; @@ -491,7 +491,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, } if (failed && !ret && failed_mirror) - repair_eb_io_failure(root, eb, failed_mirror); + repair_eb_io_failure(fs_info, eb, failed_mirror); return ret; } @@ -545,47 +545,63 @@ static int check_tree_block_fsid(struct btrfs_fs_info *fs_info, return ret; } -#define CORRUPT(reason, eb, root, slot) \ - btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \ - " root=%llu, slot=%d", \ - btrfs_header_level(eb) == 0 ? "leaf" : "node",\ +#define CORRUPT(reason, eb, root, slot) \ + btrfs_crit(root->fs_info, \ + "corrupt %s, %s: block=%llu, root=%llu, slot=%d", \ + btrfs_header_level(eb) == 0 ? "leaf" : "node", \ reason, btrfs_header_bytenr(eb), root->objectid, slot) static noinline int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) { + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_key key; struct btrfs_key leaf_key; u32 nritems = btrfs_header_nritems(leaf); int slot; - if (nritems == 0) { + /* + * Extent buffers from a relocation tree have a owner field that + * corresponds to the subvolume tree they are based on. So just from an + * extent buffer alone we can not find out what is the id of the + * corresponding subvolume tree, so we can not figure out if the extent + * buffer corresponds to the root of the relocation tree or not. So skip + * this check for relocation trees. + */ + if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { struct btrfs_root *check_root; key.objectid = btrfs_header_owner(leaf); key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; - check_root = btrfs_get_fs_root(root->fs_info, &key, false); + check_root = btrfs_get_fs_root(fs_info, &key, false); /* * The only reason we also check NULL here is that during * open_ctree() some roots has not yet been set up. */ if (!IS_ERR_OR_NULL(check_root)) { + struct extent_buffer *eb; + + eb = btrfs_root_node(check_root); /* if leaf is the root, then it's fine */ - if (leaf->start != - btrfs_root_bytenr(&check_root->root_item)) { + if (leaf != eb) { CORRUPT("non-root leaf's nritems is 0", - leaf, root, 0); + leaf, check_root, 0); + free_extent_buffer(eb); return -EIO; } + free_extent_buffer(eb); } return 0; } + if (nritems == 0) + return 0; + /* Check the 0 item */ if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != - BTRFS_LEAF_DATA_SIZE(root)) { + BTRFS_LEAF_DATA_SIZE(fs_info)) { CORRUPT("invalid item offset size pair", leaf, root, 0); return -EIO; } @@ -624,7 +640,7 @@ static noinline int check_leaf(struct btrfs_root *root, * all point outside of the leaf. */ if (btrfs_item_end_nr(leaf, slot) > - BTRFS_LEAF_DATA_SIZE(root)) { + BTRFS_LEAF_DATA_SIZE(fs_info)) { CORRUPT("slot end outside of leaf", leaf, root, slot); return -EIO; } @@ -641,7 +657,7 @@ static int check_node(struct btrfs_root *root, struct extent_buffer *node) u64 bytenr; int ret = 0; - if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { + if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) { btrfs_crit(root->fs_info, "corrupt node: block %llu root %llu nritems %lu", node->start, root->objectid, nr); @@ -747,7 +763,7 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, err: if (reads_done && test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(fs_info, eb, eb->start, ret); + btree_readahead_hook(fs_info, eb, ret); if (ret) { /* @@ -772,7 +788,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) eb->read_mirror = failed_mirror; atomic_dec(&eb->io_pages); if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(eb->fs_info, eb, eb->start, -EIO); + btree_readahead_hook(eb->fs_info, eb, -EIO); return -EIO; /* we fixed nothing */ } @@ -930,7 +946,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, atomic_inc(&fs_info->nr_async_submits); - if (bio->bi_opf & REQ_SYNC) + if (op_is_sync(bio->bi_opf)) btrfs_set_work_high_priority(&async->work); btrfs_queue_work(fs_info->workers, &async->work); @@ -981,7 +997,7 @@ static int __btree_submit_bio_done(struct inode *inode, struct bio *bio, * when we're called for a write, we're already in the async * submission context. Just jump into btrfs_map_bio */ - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 1); + ret = btrfs_map_bio(btrfs_sb(inode->i_sb), bio, mirror_num, 1); if (ret) { bio->bi_error = ret; bio_endio(bio); @@ -1004,6 +1020,7 @@ static int btree_submit_bio_hook(struct inode *inode, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset) { + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); int async = check_async_write(inode, bio_flags); int ret; @@ -1012,23 +1029,22 @@ static int btree_submit_bio_hook(struct inode *inode, struct bio *bio, * called for a read, do the setup so that checksum validation * can happen in the async kernel threads */ - ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, - bio, BTRFS_WQ_ENDIO_METADATA); + ret = btrfs_bio_wq_end_io(fs_info, bio, + BTRFS_WQ_ENDIO_METADATA); if (ret) goto out_w_error; - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 0); + ret = btrfs_map_bio(fs_info, bio, mirror_num, 0); } else if (!async) { ret = btree_csum_one_bio(bio); if (ret) goto out_w_error; - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 0); + ret = btrfs_map_bio(fs_info, bio, mirror_num, 0); } else { /* * kthread helpers are used to submit writes so that * checksumming can happen in parallel across all CPUs */ - ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, - inode, bio, mirror_num, 0, + ret = btrfs_wq_submit_bio(fs_info, inode, bio, mirror_num, 0, bio_offset, __btree_submit_bio_start, __btree_submit_bio_done); @@ -1146,12 +1162,12 @@ static const struct address_space_operations btree_aops = { .set_page_dirty = btree_set_page_dirty, }; -void readahead_tree_block(struct btrfs_root *root, u64 bytenr) +void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr) { struct extent_buffer *buf = NULL; - struct inode *btree_inode = root->fs_info->btree_inode; + struct inode *btree_inode = fs_info->btree_inode; - buf = btrfs_find_create_tree_block(root, bytenr); + buf = btrfs_find_create_tree_block(fs_info, bytenr); if (IS_ERR(buf)) return; read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, @@ -1159,15 +1175,15 @@ void readahead_tree_block(struct btrfs_root *root, u64 bytenr) free_extent_buffer(buf); } -int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, +int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr, int mirror_num, struct extent_buffer **eb) { struct extent_buffer *buf = NULL; - struct inode *btree_inode = root->fs_info->btree_inode; + struct inode *btree_inode = fs_info->btree_inode; struct extent_io_tree *io_tree = &BTRFS_I(btree_inode)->io_tree; int ret; - buf = btrfs_find_create_tree_block(root, bytenr); + buf = btrfs_find_create_tree_block(fs_info, bytenr); if (IS_ERR(buf)) return 0; @@ -1191,19 +1207,13 @@ int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, return 0; } -struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info, - u64 bytenr) -{ - return find_extent_buffer(fs_info, bytenr); -} - -struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, - u64 bytenr) +struct extent_buffer *btrfs_find_create_tree_block( + struct btrfs_fs_info *fs_info, + u64 bytenr) { - if (btrfs_is_testing(root->fs_info)) - return alloc_test_extent_buffer(root->fs_info, bytenr, - root->nodesize); - return alloc_extent_buffer(root->fs_info, bytenr); + if (btrfs_is_testing(fs_info)) + return alloc_test_extent_buffer(fs_info, bytenr); + return alloc_extent_buffer(fs_info, bytenr); } @@ -1219,17 +1229,17 @@ int btrfs_wait_tree_block_writeback(struct extent_buffer *buf) buf->start, buf->start + buf->len - 1); } -struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, +struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr, u64 parent_transid) { struct extent_buffer *buf = NULL; int ret; - buf = btrfs_find_create_tree_block(root, bytenr); + buf = btrfs_find_create_tree_block(fs_info, bytenr); if (IS_ERR(buf)) return buf; - ret = btree_read_extent_buffer_pages(root, buf, parent_transid); + ret = btree_read_extent_buffer_pages(fs_info, buf, parent_transid); if (ret) { free_extent_buffer(buf); return ERR_PTR(ret); @@ -1283,16 +1293,12 @@ btrfs_free_subvolume_writers(struct btrfs_subvolume_writers *writers) kfree(writers); } -static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize, - struct btrfs_root *root, struct btrfs_fs_info *fs_info, +static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid) { bool dummy = test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); root->node = NULL; root->commit_root = NULL; - root->sectorsize = sectorsize; - root->nodesize = nodesize; - root->stripesize = stripesize; root->state = 0; root->orphan_cleanup_state = 0; @@ -1370,8 +1376,7 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info, #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS /* Should only be used by the testing infrastructure */ -struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info, - u32 sectorsize, u32 nodesize) +struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info) { struct btrfs_root *root; @@ -1381,9 +1386,9 @@ struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info, root = btrfs_alloc_root(fs_info, GFP_KERNEL); if (!root) return ERR_PTR(-ENOMEM); + /* We don't use the stripesize in selftest, set it as sectorsize */ - __setup_root(nodesize, sectorsize, sectorsize, root, fs_info, - BTRFS_ROOT_TREE_OBJECTID); + __setup_root(root, fs_info, BTRFS_ROOT_TREE_OBJECTID); root->alloc_bytenr = 0; return root; @@ -1405,8 +1410,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, if (!root) return ERR_PTR(-ENOMEM); - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, objectid); + __setup_root(root, fs_info, objectid); root->root_key.objectid = objectid; root->root_key.type = BTRFS_ROOT_ITEM_KEY; root->root_key.offset = 0; @@ -1418,18 +1422,15 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, goto fail; } - memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); + memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_generation(leaf, trans->transid); btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(leaf, objectid); root->node = leaf; - write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - write_extent_buffer(leaf, fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(leaf), - BTRFS_UUID_SIZE); + write_extent_buffer_fsid(leaf, fs_info->fsid); + write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid); btrfs_mark_buffer_dirty(leaf); root->commit_root = btrfs_root_node(root); @@ -1474,16 +1475,13 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; - struct btrfs_root *tree_root = fs_info->tree_root; struct extent_buffer *leaf; root = btrfs_alloc_root(fs_info, GFP_NOFS); if (!root) return ERR_PTR(-ENOMEM); - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, - BTRFS_TREE_LOG_OBJECTID); + __setup_root(root, fs_info, BTRFS_TREE_LOG_OBJECTID); root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID; root->root_key.type = BTRFS_ROOT_ITEM_KEY; @@ -1505,15 +1503,14 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, return ERR_CAST(leaf); } - memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); + memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_generation(leaf, trans->transid); btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(leaf, BTRFS_TREE_LOG_OBJECTID); root->node = leaf; - write_extent_buffer(root->node, root->fs_info->fsid, - btrfs_header_fsid(), BTRFS_FSID_SIZE); + write_extent_buffer_fsid(root->node, fs_info->fsid); btrfs_mark_buffer_dirty(root->node); btrfs_tree_unlock(root->node); return root; @@ -1535,10 +1532,11 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, int btrfs_add_log_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root) { + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_root *log_root; struct btrfs_inode_item *inode_item; - log_root = alloc_log_tree(trans, root->fs_info); + log_root = alloc_log_tree(trans, fs_info); if (IS_ERR(log_root)) return PTR_ERR(log_root); @@ -1549,7 +1547,8 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans, btrfs_set_stack_inode_generation(inode_item, 1); btrfs_set_stack_inode_size(inode_item, 3); btrfs_set_stack_inode_nlink(inode_item, 1); - btrfs_set_stack_inode_nbytes(inode_item, root->nodesize); + btrfs_set_stack_inode_nbytes(inode_item, + fs_info->nodesize); btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); btrfs_set_root_node(&log_root->root_item, log_root->node); @@ -1581,8 +1580,7 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, goto alloc_fail; } - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, key->objectid); + __setup_root(root, fs_info, key->objectid); ret = btrfs_find_root(tree_root, key, path, &root->root_item, &root->root_key); @@ -1593,7 +1591,8 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, } generation = btrfs_root_generation(&root->root_item); - root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), + root->node = read_tree_block(fs_info, + btrfs_root_bytenr(&root->root_item), generation); if (IS_ERR(root->node)) { ret = PTR_ERR(root->node); @@ -1848,6 +1847,7 @@ static void end_workqueue_fn(struct btrfs_work *work) static int cleaner_kthread(void *arg) { struct btrfs_root *root = arg; + struct btrfs_fs_info *fs_info = root->fs_info; int again; struct btrfs_trans_handle *trans; @@ -1855,40 +1855,40 @@ static int cleaner_kthread(void *arg) again = 0; /* Make the cleaner go to sleep early. */ - if (btrfs_need_cleaner_sleep(root)) + if (btrfs_need_cleaner_sleep(fs_info)) goto sleep; /* * Do not do anything if we might cause open_ctree() to block * before we have finished mounting the filesystem. */ - if (!test_bit(BTRFS_FS_OPEN, &root->fs_info->flags)) + if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) goto sleep; - if (!mutex_trylock(&root->fs_info->cleaner_mutex)) + if (!mutex_trylock(&fs_info->cleaner_mutex)) goto sleep; /* * Avoid the problem that we change the status of the fs * during the above check and trylock. */ - if (btrfs_need_cleaner_sleep(root)) { - mutex_unlock(&root->fs_info->cleaner_mutex); + if (btrfs_need_cleaner_sleep(fs_info)) { + mutex_unlock(&fs_info->cleaner_mutex); goto sleep; } - mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); + mutex_lock(&fs_info->cleaner_delayed_iput_mutex); + btrfs_run_delayed_iputs(fs_info); + mutex_unlock(&fs_info->cleaner_delayed_iput_mutex); again = btrfs_clean_one_deleted_snapshot(root); - mutex_unlock(&root->fs_info->cleaner_mutex); + mutex_unlock(&fs_info->cleaner_mutex); /* * The defragger has dealt with the R/O remount and umount, * needn't do anything special here. */ - btrfs_run_defrag_inodes(root->fs_info); + btrfs_run_defrag_inodes(fs_info); /* * Acquires fs_info->delete_unused_bgs_mutex to avoid racing @@ -1898,7 +1898,7 @@ static int cleaner_kthread(void *arg) * can't hold, nor need to, fs_info->cleaner_mutex when deleting * unused block groups. */ - btrfs_delete_unused_bgs(root->fs_info); + btrfs_delete_unused_bgs(fs_info); sleep: if (!again) { set_current_state(TASK_INTERRUPTIBLE); @@ -1922,15 +1922,15 @@ sleep: trans = btrfs_attach_transaction(root); if (IS_ERR(trans)) { if (PTR_ERR(trans) != -ENOENT) - btrfs_err(root->fs_info, + btrfs_err(fs_info, "cleaner transaction attach returned %ld", PTR_ERR(trans)); } else { int ret; - ret = btrfs_commit_transaction(trans, root); + ret = btrfs_commit_transaction(trans); if (ret) - btrfs_err(root->fs_info, + btrfs_err(fs_info, "cleaner open transaction commit returned %d", ret); } @@ -1941,6 +1941,7 @@ sleep: static int transaction_kthread(void *arg) { struct btrfs_root *root = arg; + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *trans; struct btrfs_transaction *cur; u64 transid; @@ -1950,26 +1951,26 @@ static int transaction_kthread(void *arg) do { cannot_commit = false; - delay = HZ * root->fs_info->commit_interval; - mutex_lock(&root->fs_info->transaction_kthread_mutex); + delay = HZ * fs_info->commit_interval; + mutex_lock(&fs_info->transaction_kthread_mutex); - spin_lock(&root->fs_info->trans_lock); - cur = root->fs_info->running_transaction; + spin_lock(&fs_info->trans_lock); + cur = fs_info->running_transaction; if (!cur) { - spin_unlock(&root->fs_info->trans_lock); + spin_unlock(&fs_info->trans_lock); goto sleep; } now = get_seconds(); if (cur->state < TRANS_STATE_BLOCKED && (now < cur->start_time || - now - cur->start_time < root->fs_info->commit_interval)) { - spin_unlock(&root->fs_info->trans_lock); + now - cur->start_time < fs_info->commit_interval)) { + spin_unlock(&fs_info->trans_lock); delay = HZ * 5; goto sleep; } transid = cur->transid; - spin_unlock(&root->fs_info->trans_lock); + spin_unlock(&fs_info->trans_lock); /* If the file system is aborted, this will always fail. */ trans = btrfs_attach_transaction(root); @@ -1979,20 +1980,20 @@ static int transaction_kthread(void *arg) goto sleep; } if (transid == trans->transid) { - btrfs_commit_transaction(trans, root); + btrfs_commit_transaction(trans); } else { - btrfs_end_transaction(trans, root); + btrfs_end_transaction(trans); } sleep: - wake_up_process(root->fs_info->cleaner_kthread); - mutex_unlock(&root->fs_info->transaction_kthread_mutex); + wake_up_process(fs_info->cleaner_kthread); + mutex_unlock(&fs_info->transaction_kthread_mutex); if (unlikely(test_bit(BTRFS_FS_STATE_ERROR, - &root->fs_info->fs_state))) - btrfs_cleanup_transaction(root); + &fs_info->fs_state))) + btrfs_cleanup_transaction(fs_info); set_current_state(TASK_INTERRUPTIBLE); if (!kthread_should_stop() && - (!btrfs_transaction_blocked(root->fs_info) || + (!btrfs_transaction_blocked(fs_info) || cannot_commit)) schedule_timeout(delay); __set_current_state(TASK_RUNNING); @@ -2279,8 +2280,7 @@ void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info) if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { btrfs_free_log_root_tree(NULL, fs_info); - btrfs_destroy_pinned_extent(fs_info->tree_root, - fs_info->pinned_extents); + btrfs_destroy_pinned_extent(fs_info, fs_info->pinned_extents); } } @@ -2306,33 +2306,31 @@ static void btrfs_init_balance(struct btrfs_fs_info *fs_info) init_waitqueue_head(&fs_info->balance_wait_q); } -static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info, - struct btrfs_root *tree_root) +static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info) { - fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID; - set_nlink(fs_info->btree_inode, 1); + struct inode *inode = fs_info->btree_inode; + + inode->i_ino = BTRFS_BTREE_INODE_OBJECTID; + set_nlink(inode, 1); /* * we set the i_size on the btree inode to the max possible int. * the real end of the address space is determined by all of * the devices in the system */ - fs_info->btree_inode->i_size = OFFSET_MAX; - fs_info->btree_inode->i_mapping->a_ops = &btree_aops; + inode->i_size = OFFSET_MAX; + inode->i_mapping->a_ops = &btree_aops; - RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node); - extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree, - fs_info->btree_inode->i_mapping); - BTRFS_I(fs_info->btree_inode)->io_tree.track_uptodate = 0; - extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree); + RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); + extent_io_tree_init(&BTRFS_I(inode)->io_tree, inode->i_mapping); + BTRFS_I(inode)->io_tree.track_uptodate = 0; + extent_map_tree_init(&BTRFS_I(inode)->extent_tree); - BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops; + BTRFS_I(inode)->io_tree.ops = &btree_extent_io_ops; - BTRFS_I(fs_info->btree_inode)->root = tree_root; - memset(&BTRFS_I(fs_info->btree_inode)->location, 0, - sizeof(struct btrfs_key)); - set_bit(BTRFS_INODE_DUMMY, - &BTRFS_I(fs_info->btree_inode)->runtime_flags); - btrfs_insert_inode_hash(fs_info->btree_inode); + BTRFS_I(inode)->root = fs_info->tree_root; + memset(&BTRFS_I(inode)->location, 0, sizeof(struct btrfs_key)); + set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags); + btrfs_insert_inode_hash(inode); } static void btrfs_init_dev_replace_locks(struct btrfs_fs_info *fs_info) @@ -2453,7 +2451,6 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices) { int ret; - struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *log_tree_root; struct btrfs_super_block *disk_super = fs_info->super_copy; u64 bytenr = btrfs_super_log_root(disk_super); @@ -2467,12 +2464,10 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, if (!log_tree_root) return -ENOMEM; - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, log_tree_root, fs_info, - BTRFS_TREE_LOG_OBJECTID); + __setup_root(log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID); - log_tree_root->node = read_tree_block(tree_root, bytenr, - fs_info->generation + 1); + log_tree_root->node = read_tree_block(fs_info, bytenr, + fs_info->generation + 1); if (IS_ERR(log_tree_root->node)) { btrfs_warn(fs_info, "failed to read log tree"); ret = PTR_ERR(log_tree_root->node); @@ -2487,15 +2482,15 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, /* returns with log_tree_root freed on success */ ret = btrfs_recover_log_trees(log_tree_root); if (ret) { - btrfs_handle_fs_error(tree_root->fs_info, ret, - "Failed to recover log tree"); + btrfs_handle_fs_error(fs_info, ret, + "Failed to recover log tree"); free_extent_buffer(log_tree_root->node); kfree(log_tree_root); return ret; } if (fs_info->sb->s_flags & MS_RDONLY) { - ret = btrfs_commit_super(tree_root); + ret = btrfs_commit_super(fs_info); if (ret) return ret; } @@ -2503,13 +2498,15 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, return 0; } -static int btrfs_read_roots(struct btrfs_fs_info *fs_info, - struct btrfs_root *tree_root) +static int btrfs_read_roots(struct btrfs_fs_info *fs_info) { + struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *root; struct btrfs_key location; int ret; + BUG_ON(!fs_info->tree_root); + location.objectid = BTRFS_EXTENT_TREE_OBJECTID; location.type = BTRFS_ROOT_ITEM_KEY; location.offset = 0; @@ -2720,7 +2717,7 @@ int open_ctree(struct super_block *sb, sb->s_blocksize_bits = blksize_bits(4096); sb->s_bdi = &fs_info->bdi; - btrfs_init_btree_inode(fs_info, tree_root); + btrfs_init_btree_inode(fs_info); spin_lock_init(&fs_info->block_group_cache_lock); fs_info->block_group_cache_tree = RB_ROOT; @@ -2758,14 +2755,18 @@ int open_ctree(struct super_block *sb, INIT_LIST_HEAD(&fs_info->pinned_chunks); + /* Usable values until the real ones are cached from the superblock */ + fs_info->nodesize = 4096; + fs_info->sectorsize = 4096; + fs_info->stripesize = 4096; + ret = btrfs_alloc_stripe_hash_table(fs_info); if (ret) { err = ret; goto fail_alloc; } - __setup_root(4096, 4096, 4096, tree_root, - fs_info, BTRFS_ROOT_TREE_OBJECTID); + __setup_root(tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID); invalidate_bdev(fs_devices->latest_bdev); @@ -2829,7 +2830,7 @@ int open_ctree(struct super_block *sb, */ fs_info->compress_type = BTRFS_COMPRESS_ZLIB; - ret = btrfs_parse_options(tree_root, options, sb->s_flags); + ret = btrfs_parse_options(fs_info, options, sb->s_flags); if (ret) { err = ret; goto fail_alloc; @@ -2847,7 +2848,7 @@ int open_ctree(struct super_block *sb, features = btrfs_super_incompat_flags(disk_super); features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; - if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO) + if (fs_info->compress_type == BTRFS_COMPRESS_LZO) features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA) @@ -2870,6 +2871,11 @@ int open_ctree(struct super_block *sb, fs_info->dirty_metadata_batch = nodesize * (1 + ilog2(nr_cpu_ids)); fs_info->delalloc_batch = sectorsize * 512 * (1 + ilog2(nr_cpu_ids)); + /* Cache block sizes */ + fs_info->nodesize = nodesize; + fs_info->sectorsize = sectorsize; + fs_info->stripesize = stripesize; + /* * mixed block groups end up with duplicate but slightly offset * extent buffers for the same range. It leads to corruptions @@ -2910,15 +2916,11 @@ int open_ctree(struct super_block *sb, fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, SZ_4M / PAGE_SIZE); - tree_root->nodesize = nodesize; - tree_root->sectorsize = sectorsize; - tree_root->stripesize = stripesize; - sb->s_blocksize = sectorsize; sb->s_blocksize_bits = blksize_bits(sectorsize); mutex_lock(&fs_info->chunk_mutex); - ret = btrfs_read_sys_array(tree_root); + ret = btrfs_read_sys_array(fs_info); mutex_unlock(&fs_info->chunk_mutex); if (ret) { btrfs_err(fs_info, "failed to read the system array: %d", ret); @@ -2927,10 +2929,9 @@ int open_ctree(struct super_block *sb, generation = btrfs_super_chunk_root_generation(disk_super); - __setup_root(nodesize, sectorsize, stripesize, chunk_root, - fs_info, BTRFS_CHUNK_TREE_OBJECTID); + __setup_root(chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID); - chunk_root->node = read_tree_block(chunk_root, + chunk_root->node = read_tree_block(fs_info, btrfs_super_chunk_root(disk_super), generation); if (IS_ERR(chunk_root->node) || @@ -2947,7 +2948,7 @@ int open_ctree(struct super_block *sb, read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE); - ret = btrfs_read_chunk_tree(chunk_root); + ret = btrfs_read_chunk_tree(fs_info); if (ret) { btrfs_err(fs_info, "failed to read chunk tree: %d", ret); goto fail_tree_roots; @@ -2967,7 +2968,7 @@ int open_ctree(struct super_block *sb, retry_root_backup: generation = btrfs_super_generation(disk_super); - tree_root->node = read_tree_block(tree_root, + tree_root->node = read_tree_block(fs_info, btrfs_super_root(disk_super), generation); if (IS_ERR(tree_root->node) || @@ -2995,7 +2996,7 @@ retry_root_backup: mutex_unlock(&tree_root->objectid_mutex); - ret = btrfs_read_roots(fs_info, tree_root); + ret = btrfs_read_roots(fs_info); if (ret) goto recovery_tree_root; @@ -3048,7 +3049,7 @@ retry_root_backup: goto fail_sysfs; } - ret = btrfs_read_block_groups(fs_info->extent_root); + ret = btrfs_read_block_groups(fs_info); if (ret) { btrfs_err(fs_info, "failed to read block groups: %d", ret); goto fail_sysfs; @@ -3076,8 +3077,8 @@ retry_root_backup: if (IS_ERR(fs_info->transaction_kthread)) goto fail_cleaner; - if (!btrfs_test_opt(tree_root->fs_info, SSD) && - !btrfs_test_opt(tree_root->fs_info, NOSSD) && + if (!btrfs_test_opt(fs_info, SSD) && + !btrfs_test_opt(fs_info, NOSSD) && !fs_info->fs_devices->rotating) { btrfs_info(fs_info, "detected SSD devices, enabling SSD mode"); btrfs_set_opt(fs_info->mount_opt, SSD); @@ -3090,9 +3091,9 @@ retry_root_backup: btrfs_apply_pending_changes(fs_info); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_test_opt(tree_root->fs_info, CHECK_INTEGRITY)) { - ret = btrfsic_mount(tree_root, fs_devices, - btrfs_test_opt(tree_root->fs_info, + if (btrfs_test_opt(fs_info, CHECK_INTEGRITY)) { + ret = btrfsic_mount(fs_info, fs_devices, + btrfs_test_opt(fs_info, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ? 1 : 0, fs_info->check_integrity_print_mask); @@ -3108,7 +3109,7 @@ retry_root_backup: /* do not make disk changes in broken FS or nologreplay is given */ if (btrfs_super_log_root(disk_super) != 0 && - !btrfs_test_opt(tree_root->fs_info, NOLOGREPLAY)) { + !btrfs_test_opt(fs_info, NOLOGREPLAY)) { ret = btrfs_replay_log(fs_info, fs_devices); if (ret) { err = ret; @@ -3116,7 +3117,7 @@ retry_root_backup: } } - ret = btrfs_find_orphan_roots(tree_root); + ret = btrfs_find_orphan_roots(fs_info); if (ret) goto fail_qgroup; @@ -3164,19 +3165,19 @@ retry_root_backup: if (ret) { btrfs_warn(fs_info, "failed to clear free space tree: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } } - if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) && + if (btrfs_test_opt(fs_info, FREE_SPACE_TREE) && !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { btrfs_info(fs_info, "creating free space tree"); ret = btrfs_create_free_space_tree(fs_info); if (ret) { btrfs_warn(fs_info, "failed to create free space tree: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } } @@ -3185,7 +3186,7 @@ retry_root_backup: if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) || (ret = btrfs_orphan_cleanup(fs_info->tree_root))) { up_read(&fs_info->cleanup_work_sem); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } up_read(&fs_info->cleanup_work_sem); @@ -3193,14 +3194,14 @@ retry_root_backup: ret = btrfs_resume_balance_async(fs_info); if (ret) { btrfs_warn(fs_info, "failed to resume balance: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } ret = btrfs_resume_dev_replace_async(fs_info); if (ret) { btrfs_warn(fs_info, "failed to resume device replace: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } @@ -3212,10 +3213,10 @@ retry_root_backup: if (ret) { btrfs_warn(fs_info, "failed to create the UUID tree: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } - } else if (btrfs_test_opt(tree_root->fs_info, RESCAN_UUID_TREE) || + } else if (btrfs_test_opt(fs_info, RESCAN_UUID_TREE) || fs_info->generation != btrfs_super_uuid_tree_generation(disk_super)) { btrfs_info(fs_info, "checking UUID tree"); @@ -3223,7 +3224,7 @@ retry_root_backup: if (ret) { btrfs_warn(fs_info, "failed to check the UUID tree: %d", ret); - close_ctree(tree_root); + close_ctree(fs_info); return ret; } } else { @@ -3243,7 +3244,7 @@ fail_qgroup: btrfs_free_qgroup_config(fs_info); fail_trans_kthread: kthread_stop(fs_info->transaction_kthread); - btrfs_cleanup_transaction(fs_info->tree_root); + btrfs_cleanup_transaction(fs_info); btrfs_free_fs_roots(fs_info); fail_cleaner: kthread_stop(fs_info->cleaner_kthread); @@ -3291,7 +3292,7 @@ fail: return err; recovery_tree_root: - if (!btrfs_test_opt(tree_root->fs_info, USEBACKUPROOT)) + if (!btrfs_test_opt(fs_info, USEBACKUPROOT)) goto fail_tree_roots; free_root_pointers(fs_info, 0); @@ -3317,7 +3318,7 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) struct btrfs_device *device = (struct btrfs_device *) bh->b_private; - btrfs_warn_rl_in_rcu(device->dev_root->fs_info, + btrfs_warn_rl_in_rcu(device->fs_info, "lost page write due to IO error on %s", rcu_str_deref(device->name)); /* note, we don't set_buffer_write_io_error because we have @@ -3462,7 +3463,7 @@ static int write_dev_supers(struct btrfs_device *device, bh = __getblk(device->bdev, bytenr / 4096, BTRFS_SUPER_INFO_SIZE); if (!bh) { - btrfs_err(device->dev_root->fs_info, + btrfs_err(device->fs_info, "couldn't get super buffer head for bytenr %llu", bytenr); errors++; @@ -3485,9 +3486,9 @@ static int write_dev_supers(struct btrfs_device *device, * to go down lazy. */ if (i == 0) - ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_FUA, bh); + ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_FUA, bh); else - ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); + ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh); if (ret) errors++; } @@ -3551,7 +3552,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait) bio->bi_end_io = btrfs_end_empty_barrier; bio->bi_bdev = device->bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); + bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; init_completion(&device->flush_wait); bio->bi_private = &device->flush_wait; device->flush_bio = bio; @@ -3695,7 +3696,7 @@ int btrfs_calc_num_tolerated_disk_barrier_failures( return num_tolerated_disk_barrier_failures; } -static int write_all_supers(struct btrfs_root *root, int max_mirrors) +static int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors) { struct list_head *head; struct btrfs_device *dev; @@ -3707,23 +3708,23 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors) int total_errors = 0; u64 flags; - do_barriers = !btrfs_test_opt(root->fs_info, NOBARRIER); - backup_super_roots(root->fs_info); + do_barriers = !btrfs_test_opt(fs_info, NOBARRIER); + backup_super_roots(fs_info); - sb = root->fs_info->super_for_commit; + sb = fs_info->super_for_commit; dev_item = &sb->dev_item; - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - head = &root->fs_info->fs_devices->devices; - max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; + mutex_lock(&fs_info->fs_devices->device_list_mutex); + head = &fs_info->fs_devices->devices; + max_errors = btrfs_super_num_devices(fs_info->super_copy) - 1; if (do_barriers) { - ret = barrier_all_devices(root->fs_info); + ret = barrier_all_devices(fs_info); if (ret) { mutex_unlock( - &root->fs_info->fs_devices->device_list_mutex); - btrfs_handle_fs_error(root->fs_info, ret, - "errors while submitting device barriers."); + &fs_info->fs_devices->device_list_mutex); + btrfs_handle_fs_error(fs_info, ret, + "errors while submitting device barriers."); return ret; } } @@ -3757,13 +3758,14 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors) total_errors++; } if (total_errors > max_errors) { - btrfs_err(root->fs_info, "%d errors while writing supers", - total_errors); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + btrfs_err(fs_info, "%d errors while writing supers", + total_errors); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); /* FUA is masked off if unsupported and can't be the reason */ - btrfs_handle_fs_error(root->fs_info, -EIO, - "%d errors while writing supers", total_errors); + btrfs_handle_fs_error(fs_info, -EIO, + "%d errors while writing supers", + total_errors); return -EIO; } @@ -3778,19 +3780,20 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors) if (ret) total_errors++; } - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); if (total_errors > max_errors) { - btrfs_handle_fs_error(root->fs_info, -EIO, - "%d errors while writing supers", total_errors); + btrfs_handle_fs_error(fs_info, -EIO, + "%d errors while writing supers", + total_errors); return -EIO; } return 0; } int write_ctree_super(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int max_mirrors) + struct btrfs_fs_info *fs_info, int max_mirrors) { - return write_all_supers(root, max_mirrors); + return write_all_supers(fs_info, max_mirrors); } /* Drop a fs root from the radix tree and free it. */ @@ -3826,7 +3829,7 @@ static void free_fs_root(struct btrfs_root *root) { iput(root->ino_cache_inode); WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); - btrfs_free_block_rsv(root, root->orphan_block_rsv); + btrfs_free_block_rsv(root->fs_info, root->orphan_block_rsv); root->orphan_block_rsv = NULL; if (root->anon_dev) free_anon_bdev(root->anon_dev); @@ -3896,28 +3899,29 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) return err; } -int btrfs_commit_super(struct btrfs_root *root) +int btrfs_commit_super(struct btrfs_fs_info *fs_info) { + struct btrfs_root *root = fs_info->tree_root; struct btrfs_trans_handle *trans; - mutex_lock(&root->fs_info->cleaner_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_mutex); - wake_up_process(root->fs_info->cleaner_kthread); + mutex_lock(&fs_info->cleaner_mutex); + btrfs_run_delayed_iputs(fs_info); + mutex_unlock(&fs_info->cleaner_mutex); + wake_up_process(fs_info->cleaner_kthread); /* wait until ongoing cleanup work done */ - down_write(&root->fs_info->cleanup_work_sem); - up_write(&root->fs_info->cleanup_work_sem); + down_write(&fs_info->cleanup_work_sem); + up_write(&fs_info->cleanup_work_sem); trans = btrfs_join_transaction(root); if (IS_ERR(trans)) return PTR_ERR(trans); - return btrfs_commit_transaction(trans, root); + return btrfs_commit_transaction(trans); } -void close_ctree(struct btrfs_root *root) +void close_ctree(struct btrfs_fs_info *fs_info) { - struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_root *root = fs_info->tree_root; int ret; set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags); @@ -3952,15 +3956,15 @@ void close_ctree(struct btrfs_root *root) * block groups queued for removal, the deletion will be * skipped when we quit the cleaner thread. */ - btrfs_delete_unused_bgs(root->fs_info); + btrfs_delete_unused_bgs(fs_info); - ret = btrfs_commit_super(root); + ret = btrfs_commit_super(fs_info); if (ret) btrfs_err(fs_info, "commit super ret %d", ret); } if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) - btrfs_error_commit_super(root); + btrfs_error_commit_super(fs_info); kthread_stop(fs_info->transaction_kthread); kthread_stop(fs_info->cleaner_kthread); @@ -3996,8 +4000,8 @@ void close_ctree(struct btrfs_root *root) iput(fs_info->btree_inode); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_test_opt(root->fs_info, CHECK_INTEGRITY)) - btrfsic_unmount(root, fs_info->fs_devices); + if (btrfs_test_opt(fs_info, CHECK_INTEGRITY)) + btrfsic_unmount(fs_info->fs_devices); #endif btrfs_close_devices(fs_info->fs_devices); @@ -4014,7 +4018,7 @@ void close_ctree(struct btrfs_root *root) __btrfs_free_block_rsv(root->orphan_block_rsv); root->orphan_block_rsv = NULL; - lock_chunks(root); + mutex_lock(&fs_info->chunk_mutex); while (!list_empty(&fs_info->pinned_chunks)) { struct extent_map *em; @@ -4023,7 +4027,7 @@ void close_ctree(struct btrfs_root *root) list_del_init(&em->list); free_extent_map(em); } - unlock_chunks(root); + mutex_unlock(&fs_info->chunk_mutex); } int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, @@ -4045,6 +4049,7 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, void btrfs_mark_buffer_dirty(struct extent_buffer *buf) { + struct btrfs_fs_info *fs_info; struct btrfs_root *root; u64 transid = btrfs_header_generation(buf); int was_dirty; @@ -4059,24 +4064,25 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) return; #endif root = BTRFS_I(buf->pages[0]->mapping->host)->root; + fs_info = root->fs_info; btrfs_assert_tree_locked(buf); - if (transid != root->fs_info->generation) + if (transid != fs_info->generation) WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, found %llu running %llu\n", - buf->start, transid, root->fs_info->generation); + buf->start, transid, fs_info->generation); was_dirty = set_extent_buffer_dirty(buf); if (!was_dirty) - __percpu_counter_add(&root->fs_info->dirty_metadata_bytes, + __percpu_counter_add(&fs_info->dirty_metadata_bytes, buf->len, - root->fs_info->dirty_metadata_batch); + fs_info->dirty_metadata_batch); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) { - btrfs_print_leaf(root, buf); + btrfs_print_leaf(fs_info, buf); ASSERT(0); } #endif } -static void __btrfs_btree_balance_dirty(struct btrfs_root *root, +static void __btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info, int flush_delayed) { /* @@ -4089,30 +4095,31 @@ static void __btrfs_btree_balance_dirty(struct btrfs_root *root, return; if (flush_delayed) - btrfs_balance_delayed_items(root); + btrfs_balance_delayed_items(fs_info); - ret = percpu_counter_compare(&root->fs_info->dirty_metadata_bytes, + ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes, BTRFS_DIRTY_METADATA_THRESH); if (ret > 0) { - balance_dirty_pages_ratelimited( - root->fs_info->btree_inode->i_mapping); + balance_dirty_pages_ratelimited(fs_info->btree_inode->i_mapping); } } -void btrfs_btree_balance_dirty(struct btrfs_root *root) +void btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info) { - __btrfs_btree_balance_dirty(root, 1); + __btrfs_btree_balance_dirty(fs_info, 1); } -void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root) +void btrfs_btree_balance_dirty_nodelay(struct btrfs_fs_info *fs_info) { - __btrfs_btree_balance_dirty(root, 0); + __btrfs_btree_balance_dirty(fs_info, 0); } int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) { struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root; - return btree_read_extent_buffer_pages(root, buf, parent_transid); + struct btrfs_fs_info *fs_info = root->fs_info; + + return btree_read_extent_buffer_pages(fs_info, buf, parent_transid); } static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, @@ -4263,17 +4270,17 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, return ret; } -static void btrfs_error_commit_super(struct btrfs_root *root) +static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info) { - mutex_lock(&root->fs_info->cleaner_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_mutex); + mutex_lock(&fs_info->cleaner_mutex); + btrfs_run_delayed_iputs(fs_info); + mutex_unlock(&fs_info->cleaner_mutex); - down_write(&root->fs_info->cleanup_work_sem); - up_write(&root->fs_info->cleanup_work_sem); + down_write(&fs_info->cleanup_work_sem); + up_write(&fs_info->cleanup_work_sem); /* cleanup FS via transaction */ - btrfs_cleanup_transaction(root); + btrfs_cleanup_transaction(fs_info); } static void btrfs_destroy_ordered_extents(struct btrfs_root *root) @@ -4316,7 +4323,7 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info) } static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root) + struct btrfs_fs_info *fs_info) { struct rb_node *node; struct btrfs_delayed_ref_root *delayed_refs; @@ -4328,7 +4335,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, spin_lock(&delayed_refs->lock); if (atomic_read(&delayed_refs->num_entries) == 0) { spin_unlock(&delayed_refs->lock); - btrfs_info(root->fs_info, "delayed_refs has NO entry"); + btrfs_info(fs_info, "delayed_refs has NO entry"); return ret; } @@ -4354,6 +4361,8 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, list) { ref->in_tree = 0; list_del(&ref->list); + if (!list_empty(&ref->add_list)) + list_del(&ref->add_list); atomic_dec(&delayed_refs->num_entries); btrfs_put_delayed_ref(ref); } @@ -4371,7 +4380,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, mutex_unlock(&head->mutex); if (pin_bytes) - btrfs_pin_extent(root, head->node.bytenr, + btrfs_pin_extent(fs_info, head->node.bytenr, head->node.num_bytes, 1); btrfs_put_delayed_ref(&head->node); cond_resched(); @@ -4435,7 +4444,7 @@ static void btrfs_destroy_all_delalloc_inodes(struct btrfs_fs_info *fs_info) spin_unlock(&fs_info->delalloc_root_lock); } -static int btrfs_destroy_marked_extents(struct btrfs_root *root, +static int btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info, struct extent_io_tree *dirty_pages, int mark) { @@ -4452,8 +4461,8 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root, clear_extent_bits(dirty_pages, start, end, mark); while (start <= end) { - eb = btrfs_find_tree_block(root->fs_info, start); - start += root->nodesize; + eb = find_extent_buffer(fs_info, start); + start += fs_info->nodesize; if (!eb) continue; wait_on_extent_buffer_writeback(eb); @@ -4468,7 +4477,7 @@ static int btrfs_destroy_marked_extents(struct btrfs_root *root, return ret; } -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, +static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, struct extent_io_tree *pinned_extents) { struct extent_io_tree *unpin; @@ -4486,15 +4495,15 @@ again: break; clear_extent_dirty(unpin, start, end); - btrfs_error_unpin_extent_range(root, start, end); + btrfs_error_unpin_extent_range(fs_info, start, end); cond_resched(); } if (loop) { - if (unpin == &root->fs_info->freed_extents[0]) - unpin = &root->fs_info->freed_extents[1]; + if (unpin == &fs_info->freed_extents[0]) + unpin = &fs_info->freed_extents[1]; else - unpin = &root->fs_info->freed_extents[0]; + unpin = &fs_info->freed_extents[0]; loop = false; goto again; } @@ -4517,7 +4526,7 @@ static void btrfs_cleanup_bg_io(struct btrfs_block_group_cache *cache) } void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans, - struct btrfs_root *root) + struct btrfs_fs_info *fs_info) { struct btrfs_block_group_cache *cache; @@ -4527,8 +4536,7 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans, struct btrfs_block_group_cache, dirty_list); if (!cache) { - btrfs_err(root->fs_info, - "orphan block group dirty_bgs list"); + btrfs_err(fs_info, "orphan block group dirty_bgs list"); spin_unlock(&cur_trans->dirty_bgs_lock); return; } @@ -4556,8 +4564,7 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans, struct btrfs_block_group_cache, io_list); if (!cache) { - btrfs_err(root->fs_info, - "orphan block group on io_bgs list"); + btrfs_err(fs_info, "orphan block group on io_bgs list"); return; } @@ -4570,27 +4577,27 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans, } void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, - struct btrfs_root *root) + struct btrfs_fs_info *fs_info) { - btrfs_cleanup_dirty_bgs(cur_trans, root); + btrfs_cleanup_dirty_bgs(cur_trans, fs_info); ASSERT(list_empty(&cur_trans->dirty_bgs)); ASSERT(list_empty(&cur_trans->io_bgs)); - btrfs_destroy_delayed_refs(cur_trans, root); + btrfs_destroy_delayed_refs(cur_trans, fs_info); cur_trans->state = TRANS_STATE_COMMIT_START; - wake_up(&root->fs_info->transaction_blocked_wait); + wake_up(&fs_info->transaction_blocked_wait); cur_trans->state = TRANS_STATE_UNBLOCKED; - wake_up(&root->fs_info->transaction_wait); + wake_up(&fs_info->transaction_wait); - btrfs_destroy_delayed_inodes(root); - btrfs_assert_delayed_root_empty(root); + btrfs_destroy_delayed_inodes(fs_info); + btrfs_assert_delayed_root_empty(fs_info); - btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages, + btrfs_destroy_marked_extents(fs_info, &cur_trans->dirty_pages, EXTENT_DIRTY); - btrfs_destroy_pinned_extent(root, - root->fs_info->pinned_extents); + btrfs_destroy_pinned_extent(fs_info, + fs_info->pinned_extents); cur_trans->state =TRANS_STATE_COMPLETED; wake_up(&cur_trans->commit_wait); @@ -4601,27 +4608,27 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, */ } -static int btrfs_cleanup_transaction(struct btrfs_root *root) +static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info) { struct btrfs_transaction *t; - mutex_lock(&root->fs_info->transaction_kthread_mutex); + mutex_lock(&fs_info->transaction_kthread_mutex); - spin_lock(&root->fs_info->trans_lock); - while (!list_empty(&root->fs_info->trans_list)) { - t = list_first_entry(&root->fs_info->trans_list, + spin_lock(&fs_info->trans_lock); + while (!list_empty(&fs_info->trans_list)) { + t = list_first_entry(&fs_info->trans_list, struct btrfs_transaction, list); if (t->state >= TRANS_STATE_COMMIT_START) { atomic_inc(&t->use_count); - spin_unlock(&root->fs_info->trans_lock); - btrfs_wait_for_commit(root, t->transid); + spin_unlock(&fs_info->trans_lock); + btrfs_wait_for_commit(fs_info, t->transid); btrfs_put_transaction(t); - spin_lock(&root->fs_info->trans_lock); + spin_lock(&fs_info->trans_lock); continue; } - if (t == root->fs_info->running_transaction) { + if (t == fs_info->running_transaction) { t->state = TRANS_STATE_COMMIT_DOING; - spin_unlock(&root->fs_info->trans_lock); + spin_unlock(&fs_info->trans_lock); /* * We wait for 0 num_writers since we don't hold a trans * handle open currently for this transaction. @@ -4629,27 +4636,27 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) wait_event(t->writer_wait, atomic_read(&t->num_writers) == 0); } else { - spin_unlock(&root->fs_info->trans_lock); + spin_unlock(&fs_info->trans_lock); } - btrfs_cleanup_one_transaction(t, root); + btrfs_cleanup_one_transaction(t, fs_info); - spin_lock(&root->fs_info->trans_lock); - if (t == root->fs_info->running_transaction) - root->fs_info->running_transaction = NULL; + spin_lock(&fs_info->trans_lock); + if (t == fs_info->running_transaction) + fs_info->running_transaction = NULL; list_del_init(&t->list); - spin_unlock(&root->fs_info->trans_lock); + spin_unlock(&fs_info->trans_lock); btrfs_put_transaction(t); - trace_btrfs_transaction_commit(root); - spin_lock(&root->fs_info->trans_lock); - } - spin_unlock(&root->fs_info->trans_lock); - btrfs_destroy_all_ordered_extents(root->fs_info); - btrfs_destroy_delayed_inodes(root); - btrfs_assert_delayed_root_empty(root); - btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents); - btrfs_destroy_all_delalloc_inodes(root->fs_info); - mutex_unlock(&root->fs_info->transaction_kthread_mutex); + trace_btrfs_transaction_commit(fs_info->tree_root); + spin_lock(&fs_info->trans_lock); + } + spin_unlock(&fs_info->trans_lock); + btrfs_destroy_all_ordered_extents(fs_info); + btrfs_destroy_delayed_inodes(fs_info); + btrfs_assert_delayed_root_empty(fs_info); + btrfs_destroy_pinned_extent(fs_info, fs_info->pinned_extents); + btrfs_destroy_all_delalloc_inodes(fs_info); + mutex_unlock(&fs_info->transaction_kthread_mutex); return 0; } |