int add_block_group_free_space(struct btrfs_trans_handle *trans,
                               struct btrfs_fs_info *fs_info,
                               struct btrfs_block_group_cache *block_group)
{
    struct btrfs_path *path = NULL;
    int ret = 0;

    if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
        return 0;

    mutex_lock(&block_group->free_space_lock);
    if (!block_group->needs_free_space)
        goto out;

    path = btrfs_alloc_path();
    if (!path) {
        ret = -ENOMEM;
        goto out;
    }

    ret = __add_block_group_free_space(trans, fs_info, block_group, path);

out:
    btrfs_free_path(path);
    mutex_unlock(&block_group->free_space_lock);
    if (ret)
        btrfs_abort_transaction(trans, ret);
    return ret;
}
Beispiel #2
0
int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
				u64 start, u64 size)
{
	struct btrfs_block_group_cache *block_group;
	struct btrfs_path *path;
	int ret;

	if (!btrfs_fs_compat_ro(trans->fs_info, FREE_SPACE_TREE))
		return 0;

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto out;
	}

	block_group = btrfs_lookup_block_group(trans->fs_info, start);
	if (!block_group) {
		ASSERT(0);
		ret = -ENOENT;
		goto out;
	}

	mutex_lock(&block_group->free_space_lock);
	ret = __remove_from_free_space_tree(trans, block_group, path, start,
					    size);
	mutex_unlock(&block_group->free_space_lock);

	btrfs_put_block_group(block_group);
out:
	btrfs_free_path(path);
	if (ret)
		btrfs_abort_transaction(trans, ret);
	return ret;
}
int remove_block_group_free_space(struct btrfs_trans_handle *trans,
                                  struct btrfs_fs_info *fs_info,
                                  struct btrfs_block_group_cache *block_group)
{
    struct btrfs_root *root = fs_info->free_space_root;
    struct btrfs_path *path;
    struct btrfs_key key, found_key;
    struct extent_buffer *leaf;
    u64 start, end;
    int done = 0, nr;
    int ret;

    if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
        return 0;

    if (block_group->needs_free_space) {
        /* We never added this block group to the free space tree. */
        return 0;
    }

    path = btrfs_alloc_path();
    if (!path) {
        ret = -ENOMEM;
        goto out;
    }

    start = block_group->key.objectid;
    end = block_group->key.objectid + block_group->key.offset;

    key.objectid = end - 1;
    key.type = (u8)-1;
    key.offset = (u64)-1;

    while (!done) {
        ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1);
        if (ret)
            goto out;

        leaf = path->nodes[0];
        nr = 0;
        path->slots[0]++;
        while (path->slots[0] > 0) {
            btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1);

            if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
                ASSERT(found_key.objectid == block_group->key.objectid);
                ASSERT(found_key.offset == block_group->key.offset);
                done = 1;
                nr++;
                path->slots[0]--;
                break;
            } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY ||
                       found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
                ASSERT(found_key.objectid >= start);
                ASSERT(found_key.objectid < end);
                ASSERT(found_key.objectid + found_key.offset <= end);
                nr++;
                path->slots[0]--;
            } else {
                ASSERT(0);
            }
        }

        ret = btrfs_del_items(trans, root, path, path->slots[0], nr);
        if (ret)
            goto out;
        btrfs_release_path(path);
    }

    ret = 0;
out:
    btrfs_free_path(path);
    if (ret)
        btrfs_abort_transaction(trans, ret);
    return ret;
}