dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'for-chris' of git://github.com/idryomov/btrfs-unstable into for-linus

This commit is contained in:
Chris Mason 2012-03-28 20:32:46 -04:00
commit 1c691b330a
4 changed files with 157 additions and 139 deletions

View File

@ -1342,12 +1342,6 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath)
inode_to_path, ipath); inode_to_path, ipath);
} }
/*
* allocates space to return multiple file system paths for an inode.
* total_bytes to allocate are passed, note that space usable for actual path
* information will be total_bytes - sizeof(struct inode_fs_paths).
* the returned pointer must be freed with free_ipath() in the end.
*/
struct btrfs_data_container *init_data_container(u32 total_bytes) struct btrfs_data_container *init_data_container(u32 total_bytes)
{ {
struct btrfs_data_container *data; struct btrfs_data_container *data;
@ -1403,5 +1397,6 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
void free_ipath(struct inode_fs_paths *ipath) void free_ipath(struct inode_fs_paths *ipath)
{ {
kfree(ipath->fspath);
kfree(ipath); kfree(ipath);
} }

View File

@ -851,6 +851,21 @@ struct btrfs_csum_item {
*/ */
#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) #define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48)
#define BTRFS_EXTENDED_PROFILE_MASK (BTRFS_BLOCK_GROUP_PROFILE_MASK | \
BTRFS_AVAIL_ALLOC_BIT_SINGLE)
static inline u64 chunk_to_extended(u64 flags)
{
if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0)
flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE;
return flags;
}
static inline u64 extended_to_chunk(u64 flags)
{
return flags & ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
}
struct btrfs_block_group_item { struct btrfs_block_group_item {
__le64 used; __le64 used;
__le64 chunk_objectid; __le64 chunk_objectid;
@ -2723,24 +2738,6 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
kfree(fs_info->super_for_commit); kfree(fs_info->super_for_commit);
kfree(fs_info); kfree(fs_info);
} }
/**
* profile_is_valid - tests whether a given profile is valid and reduced
* @flags: profile to validate
* @extended: if true @flags is treated as an extended profile
*/
static inline int profile_is_valid(u64 flags, int extended)
{
u64 mask = ~BTRFS_BLOCK_GROUP_PROFILE_MASK;
flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
if (extended)
mask &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (flags & mask)
return 0;
/* true if zero or exactly one bit set */
return (flags & (~flags + 1)) == flags;
}
/* root-item.c */ /* root-item.c */
int btrfs_find_root_ref(struct btrfs_root *tree_root, int btrfs_find_root_ref(struct btrfs_root *tree_root,

View File

@ -3138,11 +3138,8 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
{ {
u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; u64 extra_flags = chunk_to_extended(flags) &
BTRFS_EXTENDED_PROFILE_MASK;
/* chunk -> extended profile */
if (extra_flags == 0)
extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (flags & BTRFS_BLOCK_GROUP_DATA) if (flags & BTRFS_BLOCK_GROUP_DATA)
fs_info->avail_data_alloc_bits |= extra_flags; fs_info->avail_data_alloc_bits |= extra_flags;
@ -3152,6 +3149,35 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
fs_info->avail_system_alloc_bits |= extra_flags; fs_info->avail_system_alloc_bits |= extra_flags;
} }
/*
* returns target flags in extended format or 0 if restripe for this
* chunk_type is not in progress
*/
static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)
{
struct btrfs_balance_control *bctl = fs_info->balance_ctl;
u64 target = 0;
BUG_ON(!mutex_is_locked(&fs_info->volume_mutex) &&
!spin_is_locked(&fs_info->balance_lock));
if (!bctl)
return 0;
if (flags & BTRFS_BLOCK_GROUP_DATA &&
bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {
target = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
target = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
} else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
target = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
}
return target;
}
/* /*
* @flags: available profiles in extended format (see ctree.h) * @flags: available profiles in extended format (see ctree.h)
* *
@ -3168,31 +3194,19 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
*/ */
u64 num_devices = root->fs_info->fs_devices->rw_devices + u64 num_devices = root->fs_info->fs_devices->rw_devices +
root->fs_info->fs_devices->missing_devices; root->fs_info->fs_devices->missing_devices;
u64 target;
/* pick restriper's target profile if it's available */ /*
* see if restripe for this chunk_type is in progress, if so
* try to reduce to the target profile
*/
spin_lock(&root->fs_info->balance_lock); spin_lock(&root->fs_info->balance_lock);
if (root->fs_info->balance_ctl) { target = get_restripe_target(root->fs_info, flags);
struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; if (target) {
u64 tgt = 0; /* pick target profile only if it's already available */
if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) {
if ((flags & BTRFS_BLOCK_GROUP_DATA) &&
(bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
(flags & bctl->data.target)) {
tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
} else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
(bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
(flags & bctl->sys.target)) {
tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
} else if ((flags & BTRFS_BLOCK_GROUP_METADATA) &&
(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
(flags & bctl->meta.target)) {
tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
}
if (tgt) {
spin_unlock(&root->fs_info->balance_lock); spin_unlock(&root->fs_info->balance_lock);
flags = tgt; return extended_to_chunk(target);
goto out;
} }
} }
spin_unlock(&root->fs_info->balance_lock); spin_unlock(&root->fs_info->balance_lock);
@ -3220,10 +3234,7 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
flags &= ~BTRFS_BLOCK_GROUP_RAID0; flags &= ~BTRFS_BLOCK_GROUP_RAID0;
} }
out: return extended_to_chunk(flags);
/* extended -> chunk profile */
flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
return flags;
} }
static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) static u64 get_alloc_profile(struct btrfs_root *root, u64 flags)
@ -3445,8 +3456,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
int wait_for_alloc = 0; int wait_for_alloc = 0;
int ret = 0; int ret = 0;
BUG_ON(!profile_is_valid(flags, 0));
space_info = __find_space_info(extent_root->fs_info, flags); space_info = __find_space_info(extent_root->fs_info, flags);
if (!space_info) { if (!space_info) {
ret = update_space_info(extent_root->fs_info, flags, ret = update_space_info(extent_root->fs_info, flags,
@ -5300,22 +5309,29 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
return 0; return 0;
} }
static int get_block_group_index(struct btrfs_block_group_cache *cache) static int __get_block_group_index(u64 flags)
{ {
int index; int index;
if (cache->flags & BTRFS_BLOCK_GROUP_RAID10)
if (flags & BTRFS_BLOCK_GROUP_RAID10)
index = 0; index = 0;
else if (cache->flags & BTRFS_BLOCK_GROUP_RAID1) else if (flags & BTRFS_BLOCK_GROUP_RAID1)
index = 1; index = 1;
else if (cache->flags & BTRFS_BLOCK_GROUP_DUP) else if (flags & BTRFS_BLOCK_GROUP_DUP)
index = 2; index = 2;
else if (cache->flags & BTRFS_BLOCK_GROUP_RAID0) else if (flags & BTRFS_BLOCK_GROUP_RAID0)
index = 3; index = 3;
else else
index = 4; index = 4;
return index; return index;
} }
static int get_block_group_index(struct btrfs_block_group_cache *cache)
{
return __get_block_group_index(cache->flags);
}
enum btrfs_loop_type { enum btrfs_loop_type {
LOOP_CACHING_NOWAIT = 0, LOOP_CACHING_NOWAIT = 0,
LOOP_CACHING_WAIT = 1, LOOP_CACHING_WAIT = 1,
@ -7011,31 +7027,15 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
{ {
u64 num_devices; u64 num_devices;
u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | u64 stripped;
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
if (root->fs_info->balance_ctl) { /*
struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; * if restripe for this chunk_type is on pick target profile and
u64 tgt = 0; * return, otherwise do the usual balance
*/
/* pick restriper's target profile and return */ stripped = get_restripe_target(root->fs_info, flags);
if (flags & BTRFS_BLOCK_GROUP_DATA && if (stripped)
bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) { return extended_to_chunk(stripped);
tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
} else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
}
if (tgt) {
/* extended -> chunk profile */
tgt &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
return tgt;
}
}
/* /*
* we add in the count of missing devices because we want * we add in the count of missing devices because we want
@ -7045,6 +7045,9 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
num_devices = root->fs_info->fs_devices->rw_devices + num_devices = root->fs_info->fs_devices->rw_devices +
root->fs_info->fs_devices->missing_devices; root->fs_info->fs_devices->missing_devices;
stripped = BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
if (num_devices == 1) { if (num_devices == 1) {
stripped |= BTRFS_BLOCK_GROUP_DUP; stripped |= BTRFS_BLOCK_GROUP_DUP;
stripped = flags & ~stripped; stripped = flags & ~stripped;
@ -7057,7 +7060,6 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
if (flags & (BTRFS_BLOCK_GROUP_RAID1 | if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10)) BTRFS_BLOCK_GROUP_RAID10))
return stripped | BTRFS_BLOCK_GROUP_DUP; return stripped | BTRFS_BLOCK_GROUP_DUP;
return flags;
} else { } else {
/* they already had raid on here, just return */ /* they already had raid on here, just return */
if (flags & stripped) if (flags & stripped)
@ -7070,9 +7072,9 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
if (flags & BTRFS_BLOCK_GROUP_DUP) if (flags & BTRFS_BLOCK_GROUP_DUP)
return stripped | BTRFS_BLOCK_GROUP_RAID1; return stripped | BTRFS_BLOCK_GROUP_RAID1;
/* turn single device chunks into raid0 */ /* this is drive concat, leave it alone */
return stripped | BTRFS_BLOCK_GROUP_RAID0;
} }
return flags; return flags;
} }
@ -7253,6 +7255,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
u64 min_free; u64 min_free;
u64 dev_min = 1; u64 dev_min = 1;
u64 dev_nr = 0; u64 dev_nr = 0;
u64 target;
int index; int index;
int full = 0; int full = 0;
int ret = 0; int ret = 0;
@ -7293,13 +7296,11 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
/* /*
* ok we don't have enough space, but maybe we have free space on our * ok we don't have enough space, but maybe we have free space on our
* devices to allocate new chunks for relocation, so loop through our * devices to allocate new chunks for relocation, so loop through our
* alloc devices and guess if we have enough space. However, if we * alloc devices and guess if we have enough space. if this block
* were marked as full, then we know there aren't enough chunks, and we * group is going to be restriped, run checks against the target
* can just return. * profile instead of the current one.
*/ */
ret = -1; ret = -1;
if (full)
goto out;
/* /*
* index: * index:
@ -7309,7 +7310,20 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
* 3: raid0 * 3: raid0
* 4: single * 4: single
*/ */
index = get_block_group_index(block_group); target = get_restripe_target(root->fs_info, block_group->flags);
if (target) {
index = __get_block_group_index(extended_to_chunk(target));
} else {
/*
* this is just a balance, so if we were marked as full
* we know there is no space for a new chunk
*/
if (full)
goto out;
index = get_block_group_index(block_group);
}
if (index == 0) { if (index == 0) {
dev_min = 4; dev_min = 4;
/* Divide by 2 */ /* Divide by 2 */
@ -7720,11 +7734,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
{ {
u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; u64 extra_flags = chunk_to_extended(flags) &
BTRFS_EXTENDED_PROFILE_MASK;
/* chunk -> extended profile */
if (extra_flags == 0)
extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (flags & BTRFS_BLOCK_GROUP_DATA) if (flags & BTRFS_BLOCK_GROUP_DATA)
fs_info->avail_data_alloc_bits &= ~extra_flags; fs_info->avail_data_alloc_bits &= ~extra_flags;

View File

@ -2282,15 +2282,13 @@ static void unset_balance_control(struct btrfs_fs_info *fs_info)
* Balance filters. Return 1 if chunk should be filtered out * Balance filters. Return 1 if chunk should be filtered out
* (should not be balanced). * (should not be balanced).
*/ */
static int chunk_profiles_filter(u64 chunk_profile, static int chunk_profiles_filter(u64 chunk_type,
struct btrfs_balance_args *bargs) struct btrfs_balance_args *bargs)
{ {
chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; chunk_type = chunk_to_extended(chunk_type) &
BTRFS_EXTENDED_PROFILE_MASK;
if (chunk_profile == 0) if (bargs->profiles & chunk_type)
chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (bargs->profiles & chunk_profile)
return 0; return 0;
return 1; return 1;
@ -2397,18 +2395,16 @@ static int chunk_vrange_filter(struct extent_buffer *leaf,
return 1; return 1;
} }
static int chunk_soft_convert_filter(u64 chunk_profile, static int chunk_soft_convert_filter(u64 chunk_type,
struct btrfs_balance_args *bargs) struct btrfs_balance_args *bargs)
{ {
if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT)) if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT))
return 0; return 0;
chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; chunk_type = chunk_to_extended(chunk_type) &
BTRFS_EXTENDED_PROFILE_MASK;
if (chunk_profile == 0) if (bargs->target == chunk_type)
chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (bargs->target & chunk_profile)
return 1; return 1;
return 0; return 0;
@ -2634,6 +2630,30 @@ error:
return ret; return ret;
} }
/**
* alloc_profile_is_valid - see if a given profile is valid and reduced
* @flags: profile to validate
* @extended: if true @flags is treated as an extended profile
*/
static int alloc_profile_is_valid(u64 flags, int extended)
{
u64 mask = (extended ? BTRFS_EXTENDED_PROFILE_MASK :
BTRFS_BLOCK_GROUP_PROFILE_MASK);
flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
/* 1) check that all other bits are zeroed */
if (flags & ~mask)
return 0;
/* 2) see if profile is reduced */
if (flags == 0)
return !extended; /* "0" is valid for usual profiles */
/* true if exactly one bit set */
return (flags & (flags - 1)) == 0;
}
static inline int balance_need_close(struct btrfs_fs_info *fs_info) static inline int balance_need_close(struct btrfs_fs_info *fs_info)
{ {
/* cancel requested || normal exit path */ /* cancel requested || normal exit path */
@ -2662,6 +2682,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
{ {
struct btrfs_fs_info *fs_info = bctl->fs_info; struct btrfs_fs_info *fs_info = bctl->fs_info;
u64 allowed; u64 allowed;
int mixed = 0;
int ret; int ret;
if (btrfs_fs_closing(fs_info) || if (btrfs_fs_closing(fs_info) ||
@ -2671,13 +2692,16 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
goto out; goto out;
} }
allowed = btrfs_super_incompat_flags(fs_info->super_copy);
if (allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
mixed = 1;
/* /*
* In case of mixed groups both data and meta should be picked, * In case of mixed groups both data and meta should be picked,
* and identical options should be given for both of them. * and identical options should be given for both of them.
*/ */
allowed = btrfs_super_incompat_flags(fs_info->super_copy); allowed = BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA;
if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && if (mixed && (bctl->flags & allowed)) {
(bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) {
if (!(bctl->flags & BTRFS_BALANCE_DATA) || if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
!(bctl->flags & BTRFS_BALANCE_METADATA) || !(bctl->flags & BTRFS_BALANCE_METADATA) ||
memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) { memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
@ -2688,14 +2712,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
} }
} }
/*
* Profile changing sanity checks. Skip them if a simple
* balance is requested.
*/
if (!((bctl->data.flags | bctl->sys.flags | bctl->meta.flags) &
BTRFS_BALANCE_ARGS_CONVERT))
goto do_balance;
allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
if (fs_info->fs_devices->num_devices == 1) if (fs_info->fs_devices->num_devices == 1)
allowed |= BTRFS_BLOCK_GROUP_DUP; allowed |= BTRFS_BLOCK_GROUP_DUP;
@ -2705,24 +2721,27 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10); BTRFS_BLOCK_GROUP_RAID10);
if (!profile_is_valid(bctl->data.target, 1) || if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
bctl->data.target & ~allowed) { (!alloc_profile_is_valid(bctl->data.target, 1) ||
(bctl->data.target & ~allowed))) {
printk(KERN_ERR "btrfs: unable to start balance with target " printk(KERN_ERR "btrfs: unable to start balance with target "
"data profile %llu\n", "data profile %llu\n",
(unsigned long long)bctl->data.target); (unsigned long long)bctl->data.target);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (!profile_is_valid(bctl->meta.target, 1) || if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
bctl->meta.target & ~allowed) { (!alloc_profile_is_valid(bctl->meta.target, 1) ||
(bctl->meta.target & ~allowed))) {
printk(KERN_ERR "btrfs: unable to start balance with target " printk(KERN_ERR "btrfs: unable to start balance with target "
"metadata profile %llu\n", "metadata profile %llu\n",
(unsigned long long)bctl->meta.target); (unsigned long long)bctl->meta.target);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (!profile_is_valid(bctl->sys.target, 1) || if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
bctl->sys.target & ~allowed) { (!alloc_profile_is_valid(bctl->sys.target, 1) ||
(bctl->sys.target & ~allowed))) {
printk(KERN_ERR "btrfs: unable to start balance with target " printk(KERN_ERR "btrfs: unable to start balance with target "
"system profile %llu\n", "system profile %llu\n",
(unsigned long long)bctl->sys.target); (unsigned long long)bctl->sys.target);
@ -2730,7 +2749,9 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
goto out; goto out;
} }
if (bctl->data.target & BTRFS_BLOCK_GROUP_DUP) { /* allow dup'ed data chunks only in mixed mode */
if (!mixed && (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
(bctl->data.target & BTRFS_BLOCK_GROUP_DUP)) {
printk(KERN_ERR "btrfs: dup for data is not allowed\n"); printk(KERN_ERR "btrfs: dup for data is not allowed\n");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
@ -2756,7 +2777,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
} }
} }
do_balance:
ret = insert_balance_item(fs_info->tree_root, bctl); ret = insert_balance_item(fs_info->tree_root, bctl);
if (ret && ret != -EEXIST) if (ret && ret != -EEXIST)
goto out; goto out;
@ -2999,7 +3019,7 @@ again:
key.offset = (u64)-1; key.offset = (u64)-1;
key.type = BTRFS_DEV_EXTENT_KEY; key.type = BTRFS_DEV_EXTENT_KEY;
while (1) { do {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto done; goto done;
@ -3041,8 +3061,7 @@ again:
goto done; goto done;
if (ret == -ENOSPC) if (ret == -ENOSPC)
failed++; failed++;
key.offset -= 1; } while (key.offset-- > 0);
}
if (failed && !retried) { if (failed && !retried) {
failed = 0; failed = 0;
@ -3160,11 +3179,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
int i; int i;
int j; int j;
if ((type & BTRFS_BLOCK_GROUP_RAID1) && BUG_ON(!alloc_profile_is_valid(type, 0));
(type & BTRFS_BLOCK_GROUP_DUP)) {
WARN_ON(1);
type &= ~BTRFS_BLOCK_GROUP_DUP;
}
if (list_empty(&fs_devices->alloc_list)) if (list_empty(&fs_devices->alloc_list))
return -ENOSPC; return -ENOSPC;