static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
                                   struct btrfs_path *path,
                                   u32 expected_extent_count)
{
    struct btrfs_block_group_cache *block_group;
    struct btrfs_fs_info *fs_info;
    struct btrfs_root *root;
    struct btrfs_key key;
    int prev_bit = 0, bit;
    /* Initialize to silence GCC. */
    u64 extent_start = 0;
    u64 end, offset;
    u64 total_found = 0;
    u32 extent_count = 0;
    int ret;

    block_group = caching_ctl->block_group;
    fs_info = block_group->fs_info;
    root = fs_info->free_space_root;

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

    while (1) {
        ret = btrfs_next_item(root, path);
        if (ret < 0)
            goto out;
        if (ret)
            break;

        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);

        if (key.type == BTRFS_FREE_SPACE_INFO_KEY)
            break;

        ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);
        ASSERT(key.objectid < end && key.objectid + key.offset <= end);

        caching_ctl->progress = key.objectid;

        offset = key.objectid;
        while (offset < key.objectid + key.offset) {
            bit = free_space_test_bit(block_group, path, offset);
            if (prev_bit == 0 && bit == 1) {
                extent_start = offset;
            } else if (prev_bit == 1 && bit == 0) {
                total_found += add_new_free_space(block_group,
                                                  fs_info,
                                                  extent_start,
                                                  offset);
                if (total_found > CACHING_CTL_WAKE_UP) {
                    total_found = 0;
                    wake_up(&caching_ctl->wait);
                }
                extent_count++;
            }
            prev_bit = bit;
            offset += block_group->sectorsize;
        }
    }
    if (prev_bit == 1) {
        total_found += add_new_free_space(block_group, fs_info,
                                          extent_start, end);
        extent_count++;
    }

    if (extent_count != expected_extent_count) {
        btrfs_err(fs_info, "incorrect extent count for %llu; counted %u, expected %u",
                  block_group->key.objectid, extent_count,
                  expected_extent_count);
        ASSERT(0);
        ret = -EIO;
        goto out;
    }

    caching_ctl->progress = (u64)-1;

    ret = 0;
out:
    return ret;
}
/*
 * If remove is 1, then we are removing free space, thus clearing bits in the
 * bitmap. If remove is 0, then we are adding free space, thus setting bits in
 * the bitmap.
 */
static int modify_free_space_bitmap(struct btrfs_trans_handle *trans,
                                    struct btrfs_fs_info *fs_info,
                                    struct btrfs_block_group_cache *block_group,
                                    struct btrfs_path *path,
                                    u64 start, u64 size, int remove)
{
    struct btrfs_root *root = fs_info->free_space_root;
    struct btrfs_key key;
    u64 end = start + size;
    u64 cur_start, cur_size;
    int prev_bit, next_bit;
    int new_extents;
    int ret;

    /*
     * Read the bit for the block immediately before the extent of space if
     * that block is within the block group.
     */
    if (start > block_group->key.objectid) {
        u64 prev_block = start - block_group->sectorsize;

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

        ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1);
        if (ret)
            goto out;

        prev_bit = free_space_test_bit(block_group, path, prev_block);

        /* The previous block may have been in the previous bitmap. */
        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
        if (start >= key.objectid + key.offset) {
            ret = free_space_next_bitmap(trans, root, path);
            if (ret)
                goto out;
        }
    } else {
        key.objectid = start;
        key.type = (u8)-1;
        key.offset = (u64)-1;

        ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1);
        if (ret)
            goto out;

        prev_bit = -1;
    }

    /*
     * Iterate over all of the bitmaps overlapped by the extent of space,
     * clearing/setting bits as required.
     */
    cur_start = start;
    cur_size = size;
    while (1) {
        free_space_set_bits(block_group, path, &cur_start, &cur_size,
                            !remove);
        if (cur_size == 0)
            break;
        ret = free_space_next_bitmap(trans, root, path);
        if (ret)
            goto out;
    }

    /*
     * Read the bit for the block immediately after the extent of space if
     * that block is within the block group.
     */
    if (end < block_group->key.objectid + block_group->key.offset) {
        /* The next block may be in the next bitmap. */
        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
        if (end >= key.objectid + key.offset) {
            ret = free_space_next_bitmap(trans, root, path);
            if (ret)
                goto out;
        }

        next_bit = free_space_test_bit(block_group, path, end);
    } else {
        next_bit = -1;
    }

    if (remove) {
        new_extents = -1;
        if (prev_bit == 1) {
            /* Leftover on the left. */
            new_extents++;
        }
        if (next_bit == 1) {
            /* Leftover on the right. */
            new_extents++;
        }
    } else {
        new_extents = 1;
        if (prev_bit == 1) {
            /* Merging with neighbor on the left. */
            new_extents--;
        }
        if (next_bit == 1) {
            /* Merging with neighbor on the right. */
            new_extents--;
        }
    }

    btrfs_release_path(path);
    ret = update_free_space_extent_count(trans, fs_info, block_group, path,
                                         new_extents);

out:
    return ret;
}
static int __check_free_space_extents(struct btrfs_trans_handle *trans,
				      struct btrfs_fs_info *fs_info,
				      struct btrfs_block_group_cache *cache,
				      struct btrfs_path *path,
				      struct free_space_extent *extents,
				      unsigned int num_extents)
{
	struct btrfs_free_space_info *info;
	struct btrfs_key key;
	int prev_bit = 0, bit;
	u64 extent_start = 0, offset, end;
	u32 flags, extent_count;
	unsigned int i;
	int ret;

	info = search_free_space_info(trans, fs_info, cache, path, 0);
	if (IS_ERR(info)) {
		test_msg("Could not find free space info\n");
		ret = PTR_ERR(info);
		goto out;
	}
	flags = btrfs_free_space_flags(path->nodes[0], info);
	extent_count = btrfs_free_space_extent_count(path->nodes[0], info);

	if (extent_count != num_extents) {
		test_msg("Extent count is wrong\n");
		ret = -EINVAL;
		goto out;
	}
	if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
		if (path->slots[0] != 0)
			goto invalid;
		end = cache->key.objectid + cache->key.offset;
		i = 0;
		while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
			btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
			if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY)
				goto invalid;
			offset = key.objectid;
			while (offset < key.objectid + key.offset) {
				bit = free_space_test_bit(cache, path, offset);
				if (prev_bit == 0 && bit == 1) {
					extent_start = offset;
				} else if (prev_bit == 1 && bit == 0) {
					if (i >= num_extents)
						goto invalid;
					if (i >= num_extents ||
					    extent_start != extents[i].start ||
					    offset - extent_start != extents[i].length)
						goto invalid;
					i++;
				}
				prev_bit = bit;
				offset += cache->sectorsize;
			}
		}
		if (prev_bit == 1) {
			if (i >= num_extents ||
			    extent_start != extents[i].start ||
			    end - extent_start != extents[i].length)
				goto invalid;
			i++;
		}
		if (i != num_extents)
			goto invalid;
	} else {
		if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 ||
		    path->slots[0] != 0)
			goto invalid;
		for (i = 0; i < num_extents; i++) {
			path->slots[0]++;
			btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
			if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY ||
			    key.objectid != extents[i].start ||
			    key.offset != extents[i].length)
				goto invalid;
		}
	}

	ret = 0;
out:
	btrfs_release_path(path);
	return ret;
invalid:
	test_msg("Free space tree is invalid\n");
	ret = -EINVAL;
	goto out;
}