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; }
static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes, u64 hint_byte, struct btrfs_key *ins) { u64 start; u64 end; u64 last = hint_byte; int ret; int wrapped = 0; struct btrfs_block_group_cache *cache; while (1) { ret = find_first_extent_bit(&root->fs_info->free_space_cache, last, &start, &end, EXTENT_DIRTY); if (ret) { if (wrapped++ == 0) { last = 0; continue; } else { goto fail; } } start = max(last, start); last = end + 1; if (last - start < num_bytes) continue; last = start + num_bytes; if (test_range_bit(&root->fs_info->pinned_extents, start, last - 1, EXTENT_DIRTY, 0)) continue; cache = btrfs_lookup_block_group(root->fs_info, start); BUG_ON(!cache); if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM || last > cache->key.objectid + cache->key.offset) { last = cache->key.objectid + cache->key.offset; continue; } if (cache->flags & (BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) { last = cache->key.objectid + cache->key.offset; continue; } clear_extent_dirty(&root->fs_info->free_space_cache, start, start + num_bytes - 1, 0); ins->objectid = start; ins->offset = num_bytes; ins->type = BTRFS_EXTENT_ITEM_KEY; return 0; } fail: fprintf(stderr, "not enough free space\n"); return -ENOSPC; }