diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 128 | 
1 files changed, 61 insertions, 67 deletions
| diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index cabb558dbdaa..a6f5441e62d1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -213,7 +213,7 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,   *			structure for details.   */  int btrfs_read_extent_buffer(struct extent_buffer *eb, -			     struct btrfs_tree_parent_check *check) +			     const struct btrfs_tree_parent_check *check)  {  	struct btrfs_fs_info *fs_info = eb->fs_info;  	int failed = 0; @@ -358,7 +358,7 @@ static bool check_tree_block_fsid(struct extent_buffer *eb)  /* Do basic extent buffer checks at read time */  int btrfs_validate_extent_buffer(struct extent_buffer *eb, -				 struct btrfs_tree_parent_check *check) +				 const struct btrfs_tree_parent_check *check)  {  	struct btrfs_fs_info *fs_info = eb->fs_info;  	u64 found_start; @@ -367,6 +367,7 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,  	u8 result[BTRFS_CSUM_SIZE];  	const u8 *header_csum;  	int ret = 0; +	const bool ignore_csum = btrfs_test_opt(fs_info, IGNOREMETACSUMS);  	ASSERT(check); @@ -399,13 +400,16 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,  	if (memcmp(result, header_csum, csum_size) != 0) {  		btrfs_warn_rl(fs_info, -"checksum verify failed on logical %llu mirror %u wanted " CSUM_FMT " found " CSUM_FMT " level %d", +"checksum verify failed on logical %llu mirror %u wanted " CSUM_FMT " found " CSUM_FMT " level %d%s",  			      eb->start, eb->read_mirror,  			      CSUM_FMT_VALUE(csum_size, header_csum),  			      CSUM_FMT_VALUE(csum_size, result), -			      btrfs_header_level(eb)); -		ret = -EUCLEAN; -		goto out; +			      btrfs_header_level(eb), +			      ignore_csum ? ", ignored" : ""); +		if (!ignore_csum) { +			ret = -EUCLEAN; +			goto out; +		}  	}  	if (found_level != check->level) { @@ -425,7 +429,7 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,  		goto out;  	}  	if (check->has_first_key) { -		struct btrfs_key *expect_key = &check->first_key; +		const struct btrfs_key *expect_key = &check->first_key;  		struct btrfs_key found_key;  		if (found_level) @@ -635,10 +639,6 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,  		free_extent_buffer_stale(buf);  		return ERR_PTR(ret);  	} -	if (btrfs_check_eb_owner(buf, check->owner_root)) { -		free_extent_buffer_stale(buf); -		return ERR_PTR(-EUCLEAN); -	}  	return buf;  } @@ -658,11 +658,11 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,  	root->state = 0;  	RB_CLEAR_NODE(&root->rb_node); -	root->last_trans = 0; +	btrfs_set_root_last_trans(root, 0);  	root->free_objectid = 0;  	root->nr_delalloc_inodes = 0;  	root->nr_ordered_extents = 0; -	root->inode_tree = RB_ROOT; +	xa_init(&root->inodes);  	xa_init(&root->delayed_nodes);  	btrfs_init_root_block_rsv(root); @@ -674,7 +674,6 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,  	INIT_LIST_HEAD(&root->ordered_extents);  	INIT_LIST_HEAD(&root->ordered_root);  	INIT_LIST_HEAD(&root->reloc_dirty_list); -	spin_lock_init(&root->inode_lock);  	spin_lock_init(&root->delalloc_lock);  	spin_lock_init(&root->ordered_extent_lock);  	spin_lock_init(&root->accounting_lock); @@ -847,13 +846,6 @@ struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr)  	return btrfs_global_root(fs_info, &key);  } -struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info) -{ -	if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) -		return fs_info->block_group_root; -	return btrfs_extent_root(fs_info, 0); -} -  struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,  				     u64 objectid)  { @@ -1010,7 +1002,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,  		return ret;  	} -	log_root->last_trans = trans->transid; +	btrfs_set_root_last_trans(log_root, trans->transid);  	log_root->root_key.offset = btrfs_root_id(root);  	inode_item = &log_root->root_item.inode; @@ -1033,7 +1025,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,  static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root,  					      struct btrfs_path *path, -					      struct btrfs_key *key) +					      const struct btrfs_key *key)  {  	struct btrfs_root *root;  	struct btrfs_tree_parent_check check = { 0 }; @@ -1095,7 +1087,7 @@ fail:  }  struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, -					struct btrfs_key *key) +					const struct btrfs_key *key)  {  	struct btrfs_root *root;  	struct btrfs_path *path; @@ -1230,7 +1222,7 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,  	return ret;  } -void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info) +void btrfs_check_leaked_roots(const struct btrfs_fs_info *fs_info)  {  #ifdef CONFIG_BTRFS_DEBUG  	struct btrfs_root *root; @@ -1854,7 +1846,8 @@ void btrfs_put_root(struct btrfs_root *root)  		return;  	if (refcount_dec_and_test(&root->refs)) { -		WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); +		if (WARN_ON(!xa_empty(&root->inodes))) +			xa_destroy(&root->inodes);  		WARN_ON(test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state));  		if (root->anon_dev)  			free_anon_bdev(root->anon_dev); @@ -1928,7 +1921,7 @@ static int btrfs_init_btree_inode(struct super_block *sb)  	if (!inode)  		return -ENOMEM; -	inode->i_ino = BTRFS_BTREE_INODE_OBJECTID; +	btrfs_set_inode_number(BTRFS_I(inode), BTRFS_BTREE_INODE_OBJECTID);  	set_nlink(inode, 1);  	/*  	 * we set the i_size on the btree inode to the max possible int. @@ -1939,15 +1932,11 @@ static int btrfs_init_btree_inode(struct super_block *sb)  	inode->i_mapping->a_ops = &btree_aops;  	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); -	RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node);  	extent_io_tree_init(fs_info, &BTRFS_I(inode)->io_tree,  			    IO_TREE_BTREE_INODE_IO);  	extent_map_tree_init(&BTRFS_I(inode)->extent_tree);  	BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root); -	BTRFS_I(inode)->location.objectid = BTRFS_BTREE_INODE_OBJECTID; -	BTRFS_I(inode)->location.type = 0; -	BTRFS_I(inode)->location.offset = 0;  	set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags);  	__insert_inode_hash(inode, hash);  	fs_info->btree_inode = inode; @@ -2146,7 +2135,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,  	/* If we have IGNOREDATACSUMS skip loading these roots. */  	if (objectid == BTRFS_CSUM_TREE_OBJECTID &&  	    btrfs_test_opt(fs_info, IGNOREDATACSUMS)) { -		set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state); +		set_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state);  		return 0;  	} @@ -2199,7 +2188,7 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,  	if (!found || ret) {  		if (objectid == BTRFS_CSUM_TREE_OBJECTID) -			set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state); +			set_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state);  		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS))  			ret = ret ? ret : -ENOENT; @@ -2350,21 +2339,29 @@ out:   * 		1, 2	2nd and 3rd backup copy   * 	       -1	skip bytenr check   */ -int btrfs_validate_super(struct btrfs_fs_info *fs_info, -			 struct btrfs_super_block *sb, int mirror_num) +int btrfs_validate_super(const struct btrfs_fs_info *fs_info, +			 const struct btrfs_super_block *sb, int mirror_num)  {  	u64 nodesize = btrfs_super_nodesize(sb);  	u64 sectorsize = btrfs_super_sectorsize(sb);  	int ret = 0; +	const bool ignore_flags = btrfs_test_opt(fs_info, IGNORESUPERFLAGS);  	if (btrfs_super_magic(sb) != BTRFS_MAGIC) {  		btrfs_err(fs_info, "no valid FS found");  		ret = -EINVAL;  	} -	if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) { -		btrfs_err(fs_info, "unrecognized or unsupported super flag: %llu", -				btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); -		ret = -EINVAL; +	if ((btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP)) { +		if (!ignore_flags) { +			btrfs_err(fs_info, +			"unrecognized or unsupported super flag 0x%llx", +				  btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); +			ret = -EINVAL; +		} else { +			btrfs_info(fs_info, +			"unrecognized or unsupported super flags: 0x%llx, ignored", +				   btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); +		}  	}  	if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {  		btrfs_err(fs_info, "tree_root level too big: %d >= %d", @@ -2467,7 +2464,7 @@ int btrfs_validate_super(struct btrfs_fs_info *fs_info,  	    (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID) ||  	     !btrfs_fs_incompat(fs_info, NO_HOLES))) {  		btrfs_err(fs_info, -		"block-group-tree feature requires fres-space-tree and no-holes"); +		"block-group-tree feature requires free-space-tree and no-holes");  		ret = -EINVAL;  	} @@ -2882,6 +2879,8 @@ static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block  	if (sb_rdonly(sb))  		set_bit(BTRFS_FS_STATE_RO, &fs_info->fs_state); +	if (btrfs_test_opt(fs_info, IGNOREMETACSUMS)) +		set_bit(BTRFS_FS_STATE_SKIP_META_CSUMS, &fs_info->fs_state);  	return btrfs_alloc_stripe_hash_table(fs_info);  } @@ -2927,22 +2926,22 @@ static int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)  {  	u64 root_objectid = 0;  	struct btrfs_root *gang[8]; -	int i = 0; -	int err = 0; -	unsigned int ret = 0; +	int ret = 0;  	while (1) { +		unsigned int found; +  		spin_lock(&fs_info->fs_roots_radix_lock); -		ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, +		found = radix_tree_gang_lookup(&fs_info->fs_roots_radix,  					     (void **)gang, root_objectid,  					     ARRAY_SIZE(gang)); -		if (!ret) { +		if (!found) {  			spin_unlock(&fs_info->fs_roots_radix_lock);  			break;  		} -		root_objectid = btrfs_root_id(gang[ret - 1]) + 1; +		root_objectid = btrfs_root_id(gang[found - 1]) + 1; -		for (i = 0; i < ret; i++) { +		for (int i = 0; i < found; i++) {  			/* Avoid to grab roots in dead_roots. */  			if (btrfs_root_refs(&gang[i]->root_item) == 0) {  				gang[i] = NULL; @@ -2953,24 +2952,25 @@ static int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)  		}  		spin_unlock(&fs_info->fs_roots_radix_lock); -		for (i = 0; i < ret; i++) { +		for (int i = 0; i < found; i++) {  			if (!gang[i])  				continue;  			root_objectid = btrfs_root_id(gang[i]); -			err = btrfs_orphan_cleanup(gang[i]); -			if (err) -				goto out; +			/* +			 * Continue to release the remaining roots after the first +			 * error without cleanup and preserve the first error +			 * for the return. +			 */ +			if (!ret) +				ret = btrfs_orphan_cleanup(gang[i]);  			btrfs_put_root(gang[i]);  		} +		if (ret) +			break; +  		root_objectid++;  	} -out: -	/* Release the uncleaned roots due to error. */ -	for (; i < ret; i++) { -		if (gang[i]) -			btrfs_put_root(gang[i]); -	} -	return err; +	return ret;  }  /* @@ -3204,7 +3204,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)  }  int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices, -		      char *options) +		      const char *options)  {  	u32 sectorsize;  	u32 nodesize; @@ -4157,9 +4157,6 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,  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(&fs_info->cleaner_mutex);  	btrfs_run_delayed_iputs(fs_info);  	mutex_unlock(&fs_info->cleaner_mutex); @@ -4169,10 +4166,7 @@ int btrfs_commit_super(struct btrfs_fs_info *fs_info)  	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); +	return btrfs_commit_current_transaction(fs_info->tree_root);  }  static void warn_about_uncommitted_trans(struct btrfs_fs_info *fs_info) @@ -4533,7 +4527,7 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)  	 * extents that haven't had their dirty pages IO start writeout yet  	 * actually get run and error out properly.  	 */ -	btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); +	btrfs_wait_ordered_roots(fs_info, U64_MAX, NULL);  }  static void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, |