mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	btrfs: track the csum, extent, and free space trees in a rb tree
In the future we are going to have multiple copies of these trees. To facilitate this we need a way to lookup the different roots we are looking for. Handle this by adding a global root rb tree that is indexed on the root->root_key. Then instead of loading the roots at mount time with individually targeted keys, simply search the tree_root for anything with the specific objectid we want. This will make it straightforward to support both old style and new style file systems. Signed-off-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									7fcf8a0050
								
							
						
					
					
						commit
						abed4aaae4
					
				
					 9 changed files with 263 additions and 80 deletions
				
			
		|  | @ -623,20 +623,21 @@ enum btrfs_exclusive_operation { | ||||||
| struct btrfs_fs_info { | struct btrfs_fs_info { | ||||||
| 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; | 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	struct btrfs_root *_extent_root; |  | ||||||
| 	struct btrfs_root *tree_root; | 	struct btrfs_root *tree_root; | ||||||
| 	struct btrfs_root *chunk_root; | 	struct btrfs_root *chunk_root; | ||||||
| 	struct btrfs_root *dev_root; | 	struct btrfs_root *dev_root; | ||||||
| 	struct btrfs_root *fs_root; | 	struct btrfs_root *fs_root; | ||||||
| 	struct btrfs_root *_csum_root; |  | ||||||
| 	struct btrfs_root *quota_root; | 	struct btrfs_root *quota_root; | ||||||
| 	struct btrfs_root *uuid_root; | 	struct btrfs_root *uuid_root; | ||||||
| 	struct btrfs_root *_free_space_root; |  | ||||||
| 	struct btrfs_root *data_reloc_root; | 	struct btrfs_root *data_reloc_root; | ||||||
| 
 | 
 | ||||||
| 	/* the log root tree is a directory of all the other log roots */ | 	/* the log root tree is a directory of all the other log roots */ | ||||||
| 	struct btrfs_root *log_root_tree; | 	struct btrfs_root *log_root_tree; | ||||||
| 
 | 
 | ||||||
|  | 	/* The tree that holds the global roots (csum, extent, etc) */ | ||||||
|  | 	rwlock_t global_root_lock; | ||||||
|  | 	struct rb_root global_root_tree; | ||||||
|  | 
 | ||||||
| 	spinlock_t fs_roots_radix_lock; | 	spinlock_t fs_roots_radix_lock; | ||||||
| 	struct radix_tree_root fs_roots_radix; | 	struct radix_tree_root fs_roots_radix; | ||||||
| 
 | 
 | ||||||
|  | @ -1129,6 +1130,8 @@ struct btrfs_qgroup_swapped_blocks { | ||||||
|  * and for the extent tree extent_root root. |  * and for the extent tree extent_root root. | ||||||
|  */ |  */ | ||||||
| struct btrfs_root { | struct btrfs_root { | ||||||
|  | 	struct rb_node rb_node; | ||||||
|  | 
 | ||||||
| 	struct extent_buffer *node; | 	struct extent_buffer *node; | ||||||
| 
 | 
 | ||||||
| 	struct extent_buffer *commit_root; | 	struct extent_buffer *commit_root; | ||||||
|  |  | ||||||
|  | @ -1149,6 +1149,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, | ||||||
| 	root->node = NULL; | 	root->node = NULL; | ||||||
| 	root->commit_root = NULL; | 	root->commit_root = NULL; | ||||||
| 	root->state = 0; | 	root->state = 0; | ||||||
|  | 	RB_CLEAR_NODE(&root->rb_node); | ||||||
| 
 | 
 | ||||||
| 	root->last_trans = 0; | 	root->last_trans = 0; | ||||||
| 	root->free_objectid = 0; | 	root->free_objectid = 0; | ||||||
|  | @ -1242,6 +1243,81 @@ struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | static int global_root_cmp(struct rb_node *a_node, const struct rb_node *b_node) | ||||||
|  | { | ||||||
|  | 	const struct btrfs_root *a = rb_entry(a_node, struct btrfs_root, rb_node); | ||||||
|  | 	const struct btrfs_root *b = rb_entry(b_node, struct btrfs_root, rb_node); | ||||||
|  | 
 | ||||||
|  | 	return btrfs_comp_cpu_keys(&a->root_key, &b->root_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int global_root_key_cmp(const void *k, const struct rb_node *node) | ||||||
|  | { | ||||||
|  | 	const struct btrfs_key *key = k; | ||||||
|  | 	const struct btrfs_root *root = rb_entry(node, struct btrfs_root, rb_node); | ||||||
|  | 
 | ||||||
|  | 	return btrfs_comp_cpu_keys(key, &root->root_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int btrfs_global_root_insert(struct btrfs_root *root) | ||||||
|  | { | ||||||
|  | 	struct btrfs_fs_info *fs_info = root->fs_info; | ||||||
|  | 	struct rb_node *tmp; | ||||||
|  | 
 | ||||||
|  | 	write_lock(&fs_info->global_root_lock); | ||||||
|  | 	tmp = rb_find_add(&root->rb_node, &fs_info->global_root_tree, global_root_cmp); | ||||||
|  | 	write_unlock(&fs_info->global_root_lock); | ||||||
|  | 	ASSERT(!tmp); | ||||||
|  | 
 | ||||||
|  | 	return tmp ? -EEXIST : 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btrfs_global_root_delete(struct btrfs_root *root) | ||||||
|  | { | ||||||
|  | 	struct btrfs_fs_info *fs_info = root->fs_info; | ||||||
|  | 
 | ||||||
|  | 	write_lock(&fs_info->global_root_lock); | ||||||
|  | 	rb_erase(&root->rb_node, &fs_info->global_root_tree); | ||||||
|  | 	write_unlock(&fs_info->global_root_lock); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info, | ||||||
|  | 				     struct btrfs_key *key) | ||||||
|  | { | ||||||
|  | 	struct rb_node *node; | ||||||
|  | 	struct btrfs_root *root = NULL; | ||||||
|  | 
 | ||||||
|  | 	read_lock(&fs_info->global_root_lock); | ||||||
|  | 	node = rb_find(key, &fs_info->global_root_tree, global_root_key_cmp); | ||||||
|  | 	if (node) | ||||||
|  | 		root = container_of(node, struct btrfs_root, rb_node); | ||||||
|  | 	read_unlock(&fs_info->global_root_lock); | ||||||
|  | 
 | ||||||
|  | 	return root; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr) | ||||||
|  | { | ||||||
|  | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = BTRFS_CSUM_TREE_OBJECTID, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	return btrfs_global_root(fs_info, &key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr) | ||||||
|  | { | ||||||
|  | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = BTRFS_EXTENT_TREE_OBJECTID, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	return btrfs_global_root(fs_info, &key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, | struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, | ||||||
| 				     u64 objectid) | 				     u64 objectid) | ||||||
| { | { | ||||||
|  | @ -1554,25 +1630,33 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | ||||||
| static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info, | static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info, | ||||||
| 						u64 objectid) | 						u64 objectid) | ||||||
| { | { | ||||||
|  | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = objectid, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	if (objectid == BTRFS_ROOT_TREE_OBJECTID) | 	if (objectid == BTRFS_ROOT_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->tree_root); | 		return btrfs_grab_root(fs_info->tree_root); | ||||||
| 	if (objectid == BTRFS_EXTENT_TREE_OBJECTID) | 	if (objectid == BTRFS_EXTENT_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->_extent_root); | 		return btrfs_grab_root(btrfs_global_root(fs_info, &key)); | ||||||
| 	if (objectid == BTRFS_CHUNK_TREE_OBJECTID) | 	if (objectid == BTRFS_CHUNK_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->chunk_root); | 		return btrfs_grab_root(fs_info->chunk_root); | ||||||
| 	if (objectid == BTRFS_DEV_TREE_OBJECTID) | 	if (objectid == BTRFS_DEV_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->dev_root); | 		return btrfs_grab_root(fs_info->dev_root); | ||||||
| 	if (objectid == BTRFS_CSUM_TREE_OBJECTID) | 	if (objectid == BTRFS_CSUM_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->_csum_root); | 		return btrfs_grab_root(btrfs_global_root(fs_info, &key)); | ||||||
| 	if (objectid == BTRFS_QUOTA_TREE_OBJECTID) | 	if (objectid == BTRFS_QUOTA_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->quota_root) ? | 		return btrfs_grab_root(fs_info->quota_root) ? | ||||||
| 			fs_info->quota_root : ERR_PTR(-ENOENT); | 			fs_info->quota_root : ERR_PTR(-ENOENT); | ||||||
| 	if (objectid == BTRFS_UUID_TREE_OBJECTID) | 	if (objectid == BTRFS_UUID_TREE_OBJECTID) | ||||||
| 		return btrfs_grab_root(fs_info->uuid_root) ? | 		return btrfs_grab_root(fs_info->uuid_root) ? | ||||||
| 			fs_info->uuid_root : ERR_PTR(-ENOENT); | 			fs_info->uuid_root : ERR_PTR(-ENOENT); | ||||||
| 	if (objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) | 	if (objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) { | ||||||
| 		return btrfs_grab_root(fs_info->_free_space_root) ? | 		struct btrfs_root *root = btrfs_global_root(fs_info, &key); | ||||||
| 			fs_info->_free_space_root : ERR_PTR(-ENOENT); | 
 | ||||||
|  | 		return btrfs_grab_root(root) ? root : ERR_PTR(-ENOENT); | ||||||
|  | 	} | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1619,6 +1703,18 @@ void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info) | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void free_global_roots(struct btrfs_fs_info *fs_info) | ||||||
|  | { | ||||||
|  | 	struct btrfs_root *root; | ||||||
|  | 	struct rb_node *node; | ||||||
|  | 
 | ||||||
|  | 	while ((node = rb_first_postorder(&fs_info->global_root_tree)) != NULL) { | ||||||
|  | 		root = rb_entry(node, struct btrfs_root, rb_node); | ||||||
|  | 		rb_erase(&root->rb_node, &fs_info->global_root_tree); | ||||||
|  | 		btrfs_put_root(root); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) | void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) | ||||||
| { | { | ||||||
| 	percpu_counter_destroy(&fs_info->dirty_metadata_bytes); | 	percpu_counter_destroy(&fs_info->dirty_metadata_bytes); | ||||||
|  | @ -1630,14 +1726,12 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) | ||||||
| 	btrfs_free_ref_cache(fs_info); | 	btrfs_free_ref_cache(fs_info); | ||||||
| 	kfree(fs_info->balance_ctl); | 	kfree(fs_info->balance_ctl); | ||||||
| 	kfree(fs_info->delayed_root); | 	kfree(fs_info->delayed_root); | ||||||
| 	btrfs_put_root(fs_info->_extent_root); | 	free_global_roots(fs_info); | ||||||
| 	btrfs_put_root(fs_info->tree_root); | 	btrfs_put_root(fs_info->tree_root); | ||||||
| 	btrfs_put_root(fs_info->chunk_root); | 	btrfs_put_root(fs_info->chunk_root); | ||||||
| 	btrfs_put_root(fs_info->dev_root); | 	btrfs_put_root(fs_info->dev_root); | ||||||
| 	btrfs_put_root(fs_info->_csum_root); |  | ||||||
| 	btrfs_put_root(fs_info->quota_root); | 	btrfs_put_root(fs_info->quota_root); | ||||||
| 	btrfs_put_root(fs_info->uuid_root); | 	btrfs_put_root(fs_info->uuid_root); | ||||||
| 	btrfs_put_root(fs_info->_free_space_root); |  | ||||||
| 	btrfs_put_root(fs_info->fs_root); | 	btrfs_put_root(fs_info->fs_root); | ||||||
| 	btrfs_put_root(fs_info->data_reloc_root); | 	btrfs_put_root(fs_info->data_reloc_root); | ||||||
| 	btrfs_check_leaked_roots(fs_info); | 	btrfs_check_leaked_roots(fs_info); | ||||||
|  | @ -2162,21 +2256,29 @@ static void free_root_extent_buffers(struct btrfs_root *root) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void free_global_root_pointers(struct btrfs_fs_info *fs_info) | ||||||
|  | { | ||||||
|  | 	struct btrfs_root *root, *tmp; | ||||||
|  | 
 | ||||||
|  | 	rbtree_postorder_for_each_entry_safe(root, tmp, | ||||||
|  | 					     &fs_info->global_root_tree, | ||||||
|  | 					     rb_node) | ||||||
|  | 		free_root_extent_buffers(root); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* helper to cleanup tree roots */ | /* helper to cleanup tree roots */ | ||||||
| static void free_root_pointers(struct btrfs_fs_info *info, bool free_chunk_root) | static void free_root_pointers(struct btrfs_fs_info *info, bool free_chunk_root) | ||||||
| { | { | ||||||
| 	free_root_extent_buffers(info->tree_root); | 	free_root_extent_buffers(info->tree_root); | ||||||
| 
 | 
 | ||||||
|  | 	free_global_root_pointers(info); | ||||||
| 	free_root_extent_buffers(info->dev_root); | 	free_root_extent_buffers(info->dev_root); | ||||||
| 	free_root_extent_buffers(info->_extent_root); |  | ||||||
| 	free_root_extent_buffers(info->_csum_root); |  | ||||||
| 	free_root_extent_buffers(info->quota_root); | 	free_root_extent_buffers(info->quota_root); | ||||||
| 	free_root_extent_buffers(info->uuid_root); | 	free_root_extent_buffers(info->uuid_root); | ||||||
| 	free_root_extent_buffers(info->fs_root); | 	free_root_extent_buffers(info->fs_root); | ||||||
| 	free_root_extent_buffers(info->data_reloc_root); | 	free_root_extent_buffers(info->data_reloc_root); | ||||||
| 	if (free_chunk_root) | 	if (free_chunk_root) | ||||||
| 		free_root_extent_buffers(info->chunk_root); | 		free_root_extent_buffers(info->chunk_root); | ||||||
| 	free_root_extent_buffers(info->_free_space_root); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btrfs_put_root(struct btrfs_root *root) | void btrfs_put_root(struct btrfs_root *root) | ||||||
|  | @ -2437,6 +2539,104 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int load_global_roots_objectid(struct btrfs_root *tree_root, | ||||||
|  | 				      struct btrfs_path *path, u64 objectid, | ||||||
|  | 				      const char *name) | ||||||
|  | { | ||||||
|  | 	struct btrfs_fs_info *fs_info = tree_root->fs_info; | ||||||
|  | 	struct btrfs_root *root; | ||||||
|  | 	int ret; | ||||||
|  | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = objectid, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 	bool found = false; | ||||||
|  | 
 | ||||||
|  | 	/* 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); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	while (1) { | ||||||
|  | 		ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | ||||||
|  | 			ret = btrfs_next_leaf(tree_root, path); | ||||||
|  | 			if (ret) { | ||||||
|  | 				if (ret > 0) | ||||||
|  | 					ret = 0; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		ret = 0; | ||||||
|  | 
 | ||||||
|  | 		btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||||||
|  | 		if (key.objectid != objectid) | ||||||
|  | 			break; | ||||||
|  | 		btrfs_release_path(path); | ||||||
|  | 
 | ||||||
|  | 		found = true; | ||||||
|  | 		root = read_tree_root_path(tree_root, path, &key); | ||||||
|  | 		if (IS_ERR(root)) { | ||||||
|  | 			if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) | ||||||
|  | 				ret = PTR_ERR(root); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); | ||||||
|  | 		ret = btrfs_global_root_insert(root); | ||||||
|  | 		if (ret) { | ||||||
|  | 			btrfs_put_root(root); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		key.offset++; | ||||||
|  | 	} | ||||||
|  | 	btrfs_release_path(path); | ||||||
|  | 
 | ||||||
|  | 	if (!found || ret) { | ||||||
|  | 		if (objectid == BTRFS_CSUM_TREE_OBJECTID) | ||||||
|  | 			set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state); | ||||||
|  | 
 | ||||||
|  | 		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) | ||||||
|  | 			ret = ret ? ret : -ENOENT; | ||||||
|  | 		else | ||||||
|  | 			ret = 0; | ||||||
|  | 		btrfs_err(fs_info, "failed to load root %s", name); | ||||||
|  | 	} | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int load_global_roots(struct btrfs_root *tree_root) | ||||||
|  | { | ||||||
|  | 	struct btrfs_path *path; | ||||||
|  | 	int ret = 0; | ||||||
|  | 
 | ||||||
|  | 	path = btrfs_alloc_path(); | ||||||
|  | 	if (!path) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	ret = load_global_roots_objectid(tree_root, path, | ||||||
|  | 					 BTRFS_EXTENT_TREE_OBJECTID, "extent"); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 	ret = load_global_roots_objectid(tree_root, path, | ||||||
|  | 					 BTRFS_CSUM_TREE_OBJECTID, "csum"); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 	if (!btrfs_fs_compat_ro(tree_root->fs_info, FREE_SPACE_TREE)) | ||||||
|  | 		goto out; | ||||||
|  | 	ret = load_global_roots_objectid(tree_root, path, | ||||||
|  | 					 BTRFS_FREE_SPACE_TREE_OBJECTID, | ||||||
|  | 					 "free space"); | ||||||
|  | out: | ||||||
|  | 	btrfs_free_path(path); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int btrfs_read_roots(struct btrfs_fs_info *fs_info) | static int btrfs_read_roots(struct btrfs_fs_info *fs_info) | ||||||
| { | { | ||||||
| 	struct btrfs_root *tree_root = fs_info->tree_root; | 	struct btrfs_root *tree_root = fs_info->tree_root; | ||||||
|  | @ -2446,22 +2646,14 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!fs_info->tree_root); | 	BUG_ON(!fs_info->tree_root); | ||||||
| 
 | 
 | ||||||
| 	location.objectid = BTRFS_EXTENT_TREE_OBJECTID; | 	ret = load_global_roots(tree_root); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	location.objectid = BTRFS_DEV_TREE_OBJECTID; | ||||||
| 	location.type = BTRFS_ROOT_ITEM_KEY; | 	location.type = BTRFS_ROOT_ITEM_KEY; | ||||||
| 	location.offset = 0; | 	location.offset = 0; | ||||||
| 
 | 
 | ||||||
| 	root = btrfs_read_tree_root(tree_root, &location); |  | ||||||
| 	if (IS_ERR(root)) { |  | ||||||
| 		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) { |  | ||||||
| 			ret = PTR_ERR(root); |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); |  | ||||||
| 		fs_info->_extent_root = root; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	location.objectid = BTRFS_DEV_TREE_OBJECTID; |  | ||||||
| 	root = btrfs_read_tree_root(tree_root, &location); | 	root = btrfs_read_tree_root(tree_root, &location); | ||||||
| 	if (IS_ERR(root)) { | 	if (IS_ERR(root)) { | ||||||
| 		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) { | 		if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) { | ||||||
|  | @ -2475,26 +2667,6 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) | ||||||
| 	/* Initialize fs_info for all devices in any case */ | 	/* Initialize fs_info for all devices in any case */ | ||||||
| 	btrfs_init_devices_late(fs_info); | 	btrfs_init_devices_late(fs_info); | ||||||
| 
 | 
 | ||||||
| 	/* If IGNOREDATACSUMS is set don't bother reading the csum root. */ |  | ||||||
| 	if (!btrfs_test_opt(fs_info, IGNOREDATACSUMS)) { |  | ||||||
| 		location.objectid = BTRFS_CSUM_TREE_OBJECTID; |  | ||||||
| 		root = btrfs_read_tree_root(tree_root, &location); |  | ||||||
| 		if (IS_ERR(root)) { |  | ||||||
| 			if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) { |  | ||||||
| 				ret = PTR_ERR(root); |  | ||||||
| 				goto out; |  | ||||||
| 			} else { |  | ||||||
| 				set_bit(BTRFS_FS_STATE_NO_CSUMS, |  | ||||||
| 					&fs_info->fs_state); |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); |  | ||||||
| 			fs_info->_csum_root = root; |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		set_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * This tree can share blocks with some other fs tree during relocation | 	 * This tree can share blocks with some other fs tree during relocation | ||||||
| 	 * and we need a proper setup by btrfs_get_fs_root | 	 * and we need a proper setup by btrfs_get_fs_root | ||||||
|  | @ -2532,20 +2704,6 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) | ||||||
| 		fs_info->uuid_root = root; | 		fs_info->uuid_root = root; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { |  | ||||||
| 		location.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID; |  | ||||||
| 		root = btrfs_read_tree_root(tree_root, &location); |  | ||||||
| 		if (IS_ERR(root)) { |  | ||||||
| 			if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) { |  | ||||||
| 				ret = PTR_ERR(root); |  | ||||||
| 				goto out; |  | ||||||
| 			} |  | ||||||
| 		}  else { |  | ||||||
| 			set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); |  | ||||||
| 			fs_info->_free_space_root = root; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; | 	return 0; | ||||||
| out: | out: | ||||||
| 	btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d", | 	btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d", | ||||||
|  | @ -2900,6 +3058,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) | ||||||
| 	spin_lock_init(&fs_info->zone_active_bgs_lock); | 	spin_lock_init(&fs_info->zone_active_bgs_lock); | ||||||
| 	spin_lock_init(&fs_info->relocation_bg_lock); | 	spin_lock_init(&fs_info->relocation_bg_lock); | ||||||
| 	rwlock_init(&fs_info->tree_mod_log_lock); | 	rwlock_init(&fs_info->tree_mod_log_lock); | ||||||
|  | 	rwlock_init(&fs_info->global_root_lock); | ||||||
| 	mutex_init(&fs_info->unused_bg_unpin_mutex); | 	mutex_init(&fs_info->unused_bg_unpin_mutex); | ||||||
| 	mutex_init(&fs_info->reclaim_bgs_lock); | 	mutex_init(&fs_info->reclaim_bgs_lock); | ||||||
| 	mutex_init(&fs_info->reloc_mutex); | 	mutex_init(&fs_info->reloc_mutex); | ||||||
|  | @ -2934,6 +3093,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) | ||||||
| 	atomic_set(&fs_info->reada_works_cnt, 0); | 	atomic_set(&fs_info->reada_works_cnt, 0); | ||||||
| 	atomic_set(&fs_info->nr_delayed_iputs, 0); | 	atomic_set(&fs_info->nr_delayed_iputs, 0); | ||||||
| 	atomic64_set(&fs_info->tree_mod_seq, 0); | 	atomic64_set(&fs_info->tree_mod_seq, 0); | ||||||
|  | 	fs_info->global_root_tree = RB_ROOT; | ||||||
| 	fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; | 	fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; | ||||||
| 	fs_info->metadata_ratio = 0; | 	fs_info->metadata_ratio = 0; | ||||||
| 	fs_info->defrag_inodes = RB_ROOT; | 	fs_info->defrag_inodes = RB_ROOT; | ||||||
|  |  | ||||||
|  | @ -71,6 +71,12 @@ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info, | ||||||
| struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info, | struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info, | ||||||
| 						 struct btrfs_path *path, | 						 struct btrfs_path *path, | ||||||
| 						 u64 objectid); | 						 u64 objectid); | ||||||
|  | int btrfs_global_root_insert(struct btrfs_root *root); | ||||||
|  | void btrfs_global_root_delete(struct btrfs_root *root); | ||||||
|  | struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info, | ||||||
|  | 				     struct btrfs_key *key); | ||||||
|  | struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr); | ||||||
|  | struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr); | ||||||
| 
 | 
 | ||||||
| void btrfs_free_fs_info(struct btrfs_fs_info *fs_info); | void btrfs_free_fs_info(struct btrfs_fs_info *fs_info); | ||||||
| int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); | int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); | ||||||
|  | @ -103,18 +109,6 @@ static inline struct btrfs_root *btrfs_grab_root(struct btrfs_root *root) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, |  | ||||||
| 						   u64 bytenr) |  | ||||||
| { |  | ||||||
| 	return fs_info->_extent_root; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, |  | ||||||
| 						 u64 bytenr) |  | ||||||
| { |  | ||||||
| 	return fs_info->_csum_root; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info) | static inline struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info) | ||||||
| { | { | ||||||
| 	return btrfs_extent_root(fs_info, 0); | 	return btrfs_extent_root(fs_info, 0); | ||||||
|  |  | ||||||
|  | @ -2947,6 +2947,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, | ||||||
| 	bool skinny_metadata = btrfs_fs_incompat(info, SKINNY_METADATA); | 	bool skinny_metadata = btrfs_fs_incompat(info, SKINNY_METADATA); | ||||||
| 
 | 
 | ||||||
| 	extent_root = btrfs_extent_root(info, bytenr); | 	extent_root = btrfs_extent_root(info, bytenr); | ||||||
|  | 	ASSERT(extent_root); | ||||||
| 
 | 
 | ||||||
| 	path = btrfs_alloc_path(); | 	path = btrfs_alloc_path(); | ||||||
| 	if (!path) | 	if (!path) | ||||||
|  |  | ||||||
|  | @ -19,7 +19,13 @@ static int __add_block_group_free_space(struct btrfs_trans_handle *trans, | ||||||
| static struct btrfs_root *btrfs_free_space_root( | static struct btrfs_root *btrfs_free_space_root( | ||||||
| 				struct btrfs_block_group *block_group) | 				struct btrfs_block_group *block_group) | ||||||
| { | { | ||||||
| 	return block_group->fs_info->_free_space_root; | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	return btrfs_global_root(block_group->fs_info, &key); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void set_free_space_tree_thresholds(struct btrfs_block_group *cache) | void set_free_space_tree_thresholds(struct btrfs_block_group *cache) | ||||||
|  | @ -1164,7 +1170,11 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) | ||||||
| 		ret = PTR_ERR(free_space_root); | 		ret = PTR_ERR(free_space_root); | ||||||
| 		goto abort; | 		goto abort; | ||||||
| 	} | 	} | ||||||
| 	fs_info->_free_space_root = free_space_root; | 	ret = btrfs_global_root_insert(free_space_root); | ||||||
|  | 	if (ret) { | ||||||
|  | 		btrfs_put_root(free_space_root); | ||||||
|  | 		goto abort; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	node = rb_first(&fs_info->block_group_cache_tree); | 	node = rb_first(&fs_info->block_group_cache_tree); | ||||||
| 	while (node) { | 	while (node) { | ||||||
|  | @ -1239,7 +1249,12 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) | ||||||
| { | { | ||||||
| 	struct btrfs_trans_handle *trans; | 	struct btrfs_trans_handle *trans; | ||||||
| 	struct btrfs_root *tree_root = fs_info->tree_root; | 	struct btrfs_root *tree_root = fs_info->tree_root; | ||||||
| 	struct btrfs_root *free_space_root = fs_info->_free_space_root; | 	struct btrfs_key key = { | ||||||
|  | 		.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID, | ||||||
|  | 		.type = BTRFS_ROOT_ITEM_KEY, | ||||||
|  | 		.offset = 0, | ||||||
|  | 	}; | ||||||
|  | 	struct btrfs_root *free_space_root = btrfs_global_root(fs_info, &key); | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	trans = btrfs_start_transaction(tree_root, 0); | 	trans = btrfs_start_transaction(tree_root, 0); | ||||||
|  | @ -1248,7 +1263,6 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) | ||||||
| 
 | 
 | ||||||
| 	btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); | 	btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); | ||||||
| 	btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); | 	btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); | ||||||
| 	fs_info->_free_space_root = NULL; |  | ||||||
| 
 | 
 | ||||||
| 	ret = clear_free_space_tree(trans, free_space_root); | 	ret = clear_free_space_tree(trans, free_space_root); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -1258,6 +1272,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto abort; | 		goto abort; | ||||||
| 
 | 
 | ||||||
|  | 	btrfs_global_root_delete(free_space_root); | ||||||
| 	list_del(&free_space_root->dirty_list); | 	list_del(&free_space_root->dirty_list); | ||||||
| 
 | 
 | ||||||
| 	btrfs_tree_lock(free_space_root->node); | 	btrfs_tree_lock(free_space_root->node); | ||||||
|  |  | ||||||
|  | @ -204,6 +204,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root) | ||||||
| 	/* Will be freed by btrfs_free_fs_roots */ | 	/* Will be freed by btrfs_free_fs_roots */ | ||||||
| 	if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state))) | 	if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state))) | ||||||
| 		return; | 		return; | ||||||
|  | 	btrfs_global_root_delete(root); | ||||||
| 	btrfs_put_root(root); | 	btrfs_put_root(root); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1036,7 +1036,10 @@ int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize) | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	root->fs_info->_extent_root = root; | 	root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID; | ||||||
|  | 	root->root_key.type = BTRFS_ROOT_ITEM_KEY; | ||||||
|  | 	root->root_key.offset = 0; | ||||||
|  | 	btrfs_global_root_insert(root); | ||||||
| 
 | 
 | ||||||
| 	ret = test_extents(cache); | 	ret = test_extents(cache); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  |  | ||||||
|  | @ -446,7 +446,10 @@ static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, | ||||||
| 
 | 
 | ||||||
| 	btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, | 	btrfs_set_super_compat_ro_flags(root->fs_info->super_copy, | ||||||
| 					BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); | 					BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE); | ||||||
| 	root->fs_info->_free_space_root = root; | 	root->root_key.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID; | ||||||
|  | 	root->root_key.type = BTRFS_ROOT_ITEM_KEY; | ||||||
|  | 	root->root_key.offset = 0; | ||||||
|  | 	btrfs_global_root_insert(root); | ||||||
| 	root->fs_info->tree_root = root; | 	root->fs_info->tree_root = root; | ||||||
| 
 | 
 | ||||||
| 	root->node = alloc_test_extent_buffer(root->fs_info, nodesize); | 	root->node = alloc_test_extent_buffer(root->fs_info, nodesize); | ||||||
|  |  | ||||||
|  | @ -455,7 +455,10 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* We are using this root as our extent root */ | 	/* We are using this root as our extent root */ | ||||||
| 	root->fs_info->_extent_root = root; | 	root->root_key.objectid = BTRFS_EXTENT_TREE_OBJECTID; | ||||||
|  | 	root->root_key.type = BTRFS_ROOT_ITEM_KEY; | ||||||
|  | 	root->root_key.offset = 0; | ||||||
|  | 	btrfs_global_root_insert(root); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Some of the paths we test assume we have a filled out fs_info, so we | 	 * Some of the paths we test assume we have a filled out fs_info, so we | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Josef Bacik
						Josef Bacik