Signed-off-by: Chris Mason <chris.mason@oracle.com>
#define BTRFS_BLOCK_GROUP_DATA 1
#define BTRFS_BLOCK_GROUP_DATA 1
+#define BTRFS_BLOCK_GROUP_MIXED 2
+
struct btrfs_block_group_item {
__le64 used;
u8 flags;
struct btrfs_block_group_item {
__le64 used;
u8 flags;
u64 last;
u64 start = 0;
u64 end = 0;
u64 last;
u64 start = 0;
u64 end = 0;
again:
ret = cache_block_group(root, cache);
if (ret)
goto out;
again:
ret = cache_block_group(root, cache);
if (ret)
goto out;
last = max(search_start, cache->key.objectid);
while(1) {
last = max(search_start, cache->key.objectid);
while(1) {
new_group:
last = cache->key.objectid + cache->key.offset;
new_group:
last = cache->key.objectid + cache->key.offset;
cache = btrfs_lookup_block_group(root->fs_info, last);
if (!cache) {
cache = btrfs_lookup_block_group(root->fs_info, last);
if (!cache) {
+ if (!wrapped) {
+ wrapped = 1;
+ last = search_start;
+ data = BTRFS_BLOCK_GROUP_MIXED;
+ goto wrapped;
+ }
return search_start;
}
cache = btrfs_find_block_group(root, cache, last, data, 0);
return search_start;
}
cache = btrfs_find_block_group(root, cache, last, data, 0);
block_group_cache = &info->block_group_cache;
if (!owner)
block_group_cache = &info->block_group_cache;
if (!owner)
+ if (data == BTRFS_BLOCK_GROUP_MIXED)
+ bit = BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA;
+ else if (data)
bit = BLOCK_GROUP_DATA;
else
bit = BLOCK_GROUP_METADATA;
bit = BLOCK_GROUP_DATA;
else
bit = BLOCK_GROUP_METADATA;
if (search_start) {
struct btrfs_block_group_cache *shint;
shint = btrfs_lookup_block_group(info, search_start);
if (search_start) {
struct btrfs_block_group_cache *shint;
shint = btrfs_lookup_block_group(info, search_start);
- if (shint && shint->data == data) {
+ if (shint && (shint->data == data ||
+ shint->data == BTRFS_BLOCK_GROUP_MIXED)) {
used = btrfs_block_group_used(&shint->item);
if (used < div_factor(shint->key.offset, factor)) {
return shint;
}
}
}
used = btrfs_block_group_used(&shint->item);
if (used < div_factor(shint->key.offset, factor)) {
return shint;
}
}
}
- if (hint && hint->data == data) {
+ if (hint && (hint->data == data ||
+ hint->data == BTRFS_BLOCK_GROUP_MIXED)) {
used = btrfs_block_group_used(&hint->item);
if (used < div_factor(hint->key.offset, factor)) {
return hint;
used = btrfs_block_group_used(&hint->item);
if (used < div_factor(hint->key.offset, factor)) {
return hint;
if (data) {
bit_to_clear = BLOCK_GROUP_METADATA;
bit_to_set = BLOCK_GROUP_DATA;
if (data) {
bit_to_clear = BLOCK_GROUP_METADATA;
bit_to_set = BLOCK_GROUP_DATA;
+ cache->item.flags &=
+ ~BTRFS_BLOCK_GROUP_MIXED;
cache->item.flags |=
BTRFS_BLOCK_GROUP_DATA;
} else {
bit_to_clear = BLOCK_GROUP_DATA;
bit_to_set = BLOCK_GROUP_METADATA;
cache->item.flags |=
BTRFS_BLOCK_GROUP_DATA;
} else {
bit_to_clear = BLOCK_GROUP_DATA;
bit_to_set = BLOCK_GROUP_METADATA;
+ cache->item.flags &=
+ ~BTRFS_BLOCK_GROUP_MIXED;
cache->item.flags &=
~BTRFS_BLOCK_GROUP_DATA;
}
cache->item.flags &=
~BTRFS_BLOCK_GROUP_DATA;
}
set_extent_bits(&info->block_group_cache,
start, end, bit_to_set,
GFP_NOFS);
set_extent_bits(&info->block_group_cache,
start, end, bit_to_set,
GFP_NOFS);
+ } else if (cache->data != data &&
+ cache->data != BTRFS_BLOCK_GROUP_MIXED) {
+ cache->data = BTRFS_BLOCK_GROUP_MIXED;
+ set_extent_bits(&info->block_group_cache,
+ start, end,
+ BLOCK_GROUP_DATA |
+ BLOCK_GROUP_METADATA,
+ GFP_NOFS);
}
old_val += num_bytes;
} else {
}
old_val += num_bytes;
} else {
struct btrfs_block_group_cache *block_group;
int full_scan = 0;
int wrapped = 0;
struct btrfs_block_group_cache *block_group;
int full_scan = 0;
int wrapped = 0;
WARN_ON(num_bytes < root->sectorsize);
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
WARN_ON(num_bytes < root->sectorsize);
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
check_failed:
search_start = find_search_start(root, &block_group,
search_start, total_needed, data);
check_failed:
search_start = find_search_start(root, &block_group,
search_start, total_needed, data);
+ cached_start = search_start;
btrfs_init_path(path);
ins->objectid = search_start;
ins->offset = 0;
btrfs_init_path(path);
ins->objectid = search_start;
ins->offset = 0;
key.objectid = found_key.objectid + found_key.offset;
btrfs_release_path(root, path);
key.objectid = found_key.objectid + found_key.offset;
btrfs_release_path(root, path);
- if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) {
+ if (cache->item.flags & BTRFS_BLOCK_GROUP_MIXED) {
+ bit = BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA;
+ cache->data = BTRFS_BLOCK_GROUP_MIXED;
+ } else if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) {
+ cache->data = BTRFS_BLOCK_GROUP_DATA;
} else {
bit = BLOCK_GROUP_METADATA;
cache->data = 0;
} else {
bit = BLOCK_GROUP_METADATA;
cache->data = 0;
if (root->fs_info->extent_root == root)
is_extent = 1;
if (root->fs_info->extent_root == root)
is_extent = 1;
+ if (*level == 1 && cache_only && path->nodes[1] &&
+ !btrfs_buffer_defrag(path->nodes[1])) {
+ goto out;
+ }
while(*level > 0) {
WARN_ON(*level < 0);
WARN_ON(*level >= BTRFS_MAX_LEVEL);
while(*level > 0) {
WARN_ON(*level < 0);
WARN_ON(*level >= BTRFS_MAX_LEVEL);
WARN_ON(*level >= BTRFS_MAX_LEVEL);
btrfs_clear_buffer_defrag(path->nodes[*level]);
WARN_ON(*level >= BTRFS_MAX_LEVEL);
btrfs_clear_buffer_defrag(path->nodes[*level]);
free_extent_buffer(path->nodes[*level]);
path->nodes[*level] = NULL;
*level += 1;
free_extent_buffer(path->nodes[*level]);
path->nodes[*level] = NULL;
*level += 1;