diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 139 | 
1 files changed, 99 insertions, 40 deletions
| diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8e3438672a82..af97ddcc6b3e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1281,32 +1281,26 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,  	return 0;  } -struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, -					struct btrfs_key *key) +static struct btrfs_root *read_tree_root_path(struct btrfs_root *tree_root, +					      struct btrfs_path *path, +					      struct btrfs_key *key)  {  	struct btrfs_root *root;  	struct btrfs_fs_info *fs_info = tree_root->fs_info; -	struct btrfs_path *path;  	u64 generation;  	int ret;  	int level; -	path = btrfs_alloc_path(); -	if (!path) -		return ERR_PTR(-ENOMEM); -  	root = btrfs_alloc_root(fs_info, key->objectid, GFP_NOFS); -	if (!root) { -		ret = -ENOMEM; -		goto alloc_fail; -	} +	if (!root) +		return ERR_PTR(-ENOMEM);  	ret = btrfs_find_root(tree_root, key, path,  			      &root->root_item, &root->root_key);  	if (ret) {  		if (ret > 0)  			ret = -ENOENT; -		goto find_fail; +		goto fail;  	}  	generation = btrfs_root_generation(&root->root_item); @@ -1317,21 +1311,31 @@ struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,  	if (IS_ERR(root->node)) {  		ret = PTR_ERR(root->node);  		root->node = NULL; -		goto find_fail; +		goto fail;  	} else if (!btrfs_buffer_uptodate(root->node, generation, 0)) {  		ret = -EIO; -		goto find_fail; +		goto fail;  	}  	root->commit_root = btrfs_root_node(root); -out: -	btrfs_free_path(path);  	return root; - -find_fail: +fail:  	btrfs_put_root(root); -alloc_fail: -	root = ERR_PTR(ret); -	goto out; +	return ERR_PTR(ret); +} + +struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, +					struct btrfs_key *key) +{ +	struct btrfs_root *root; +	struct btrfs_path *path; + +	path = btrfs_alloc_path(); +	if (!path) +		return ERR_PTR(-ENOMEM); +	root = read_tree_root_path(tree_root, path, key); +	btrfs_free_path(path); + +	return root;  }  /* @@ -1419,6 +1423,31 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,  	return root;  } +static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info, +						u64 objectid) +{ +	if (objectid == BTRFS_ROOT_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->tree_root); +	if (objectid == BTRFS_EXTENT_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->extent_root); +	if (objectid == BTRFS_CHUNK_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->chunk_root); +	if (objectid == BTRFS_DEV_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->dev_root); +	if (objectid == BTRFS_CSUM_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->csum_root); +	if (objectid == BTRFS_QUOTA_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->quota_root) ? +			fs_info->quota_root : ERR_PTR(-ENOENT); +	if (objectid == BTRFS_UUID_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->uuid_root) ? +			fs_info->uuid_root : ERR_PTR(-ENOENT); +	if (objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) +		return btrfs_grab_root(fs_info->free_space_root) ? +			fs_info->free_space_root : ERR_PTR(-ENOENT); +	return NULL; +} +  int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,  			 struct btrfs_root *root)  { @@ -1518,25 +1547,9 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,  	struct btrfs_key key;  	int ret; -	if (objectid == BTRFS_ROOT_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->tree_root); -	if (objectid == BTRFS_EXTENT_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->extent_root); -	if (objectid == BTRFS_CHUNK_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->chunk_root); -	if (objectid == BTRFS_DEV_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->dev_root); -	if (objectid == BTRFS_CSUM_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->csum_root); -	if (objectid == BTRFS_QUOTA_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->quota_root) ? -			fs_info->quota_root : ERR_PTR(-ENOENT); -	if (objectid == BTRFS_UUID_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->uuid_root) ? -			fs_info->uuid_root : ERR_PTR(-ENOENT); -	if (objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) -		return btrfs_grab_root(fs_info->free_space_root) ? -			fs_info->free_space_root : ERR_PTR(-ENOENT); +	root = btrfs_get_global_root(fs_info, objectid); +	if (root) +		return root;  again:  	root = btrfs_lookup_fs_root(fs_info, objectid);  	if (root) { @@ -1622,6 +1635,52 @@ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,  }  /* + * btrfs_get_fs_root_commit_root - return a root for the given objectid + * @fs_info:	the fs_info + * @objectid:	the objectid we need to lookup + * + * This is exclusively used for backref walking, and exists specifically because + * of how qgroups does lookups.  Qgroups will do a backref lookup at delayed ref + * creation time, which means we may have to read the tree_root in order to look + * up a fs root that is not in memory.  If the root is not in memory we will + * read the tree root commit root and look up the fs root from there.  This is a + * temporary root, it will not be inserted into the radix tree as it doesn't + * have the most uptodate information, it'll simply be discarded once the + * backref code is finished using the root. + */ +struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info, +						 struct btrfs_path *path, +						 u64 objectid) +{ +	struct btrfs_root *root; +	struct btrfs_key key; + +	ASSERT(path->search_commit_root && path->skip_locking); + +	/* +	 * This can return -ENOENT if we ask for a root that doesn't exist, but +	 * since this is called via the backref walking code we won't be looking +	 * up a root that doesn't exist, unless there's corruption.  So if root +	 * != NULL just return it. +	 */ +	root = btrfs_get_global_root(fs_info, objectid); +	if (root) +		return root; + +	root = btrfs_lookup_fs_root(fs_info, objectid); +	if (root) +		return root; + +	key.objectid = objectid; +	key.type = BTRFS_ROOT_ITEM_KEY; +	key.offset = (u64)-1; +	root = read_tree_root_path(fs_info->tree_root, path, &key); +	btrfs_release_path(path); + +	return root; +} + +/*   * called by the kthread helper functions to finally call the bio end_io   * functions.  This is where read checksum verification actually happens   */ |