Loading fs/btrfs/backref.c +1 −6 Original line number Diff line number Diff line Loading @@ -1342,12 +1342,6 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *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 *data; Loading Loading @@ -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) { kfree(ipath->fspath); kfree(ipath); } fs/btrfs/ctree.h +15 −18 Original line number Diff line number Diff line Loading @@ -851,6 +851,21 @@ struct btrfs_csum_item { */ #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 { __le64 used; __le64 chunk_objectid; Loading Loading @@ -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); } /** * 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 */ int btrfs_find_root_ref(struct btrfs_root *tree_root, Loading fs/btrfs/extent-tree.c +87 −76 Original line number Diff line number Diff line Loading @@ -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) { u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; /* chunk -> extended profile */ if (extra_flags == 0) extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; u64 extra_flags = chunk_to_extended(flags) & BTRFS_EXTENDED_PROFILE_MASK; if (flags & BTRFS_BLOCK_GROUP_DATA) fs_info->avail_data_alloc_bits |= extra_flags; Loading @@ -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; } /* * 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) * Loading @@ -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 + 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); if (root->fs_info->balance_ctl) { struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; u64 tgt = 0; 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) { target = get_restripe_target(root->fs_info, flags); if (target) { /* pick target profile only if it's already available */ if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) { spin_unlock(&root->fs_info->balance_lock); flags = tgt; goto out; return extended_to_chunk(target); } } spin_unlock(&root->fs_info->balance_lock); Loading Loading @@ -3220,10 +3234,7 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) flags &= ~BTRFS_BLOCK_GROUP_RAID0; } out: /* extended -> chunk profile */ flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; return flags; return extended_to_chunk(flags); } static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) Loading Loading @@ -3445,8 +3456,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, int wait_for_alloc = 0; int ret = 0; BUG_ON(!profile_is_valid(flags, 0)); space_info = __find_space_info(extent_root->fs_info, flags); if (!space_info) { ret = update_space_info(extent_root->fs_info, flags, Loading Loading @@ -5300,22 +5309,29 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache) return 0; } static int get_block_group_index(struct btrfs_block_group_cache *cache) static int __get_block_group_index(u64 flags) { int index; if (cache->flags & BTRFS_BLOCK_GROUP_RAID10) if (flags & BTRFS_BLOCK_GROUP_RAID10) index = 0; else if (cache->flags & BTRFS_BLOCK_GROUP_RAID1) else if (flags & BTRFS_BLOCK_GROUP_RAID1) index = 1; else if (cache->flags & BTRFS_BLOCK_GROUP_DUP) else if (flags & BTRFS_BLOCK_GROUP_DUP) index = 2; else if (cache->flags & BTRFS_BLOCK_GROUP_RAID0) else if (flags & BTRFS_BLOCK_GROUP_RAID0) index = 3; else index = 4; 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 { LOOP_CACHING_NOWAIT = 0, LOOP_CACHING_WAIT = 1, Loading Loading @@ -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) { u64 num_devices; u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; u64 stripped; if (root->fs_info->balance_ctl) { struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; u64 tgt = 0; /* pick restriper's target profile and return */ if (flags & BTRFS_BLOCK_GROUP_DATA && bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) { 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; } } /* * if restripe for this chunk_type is on pick target profile and * return, otherwise do the usual balance */ stripped = get_restripe_target(root->fs_info, flags); if (stripped) return extended_to_chunk(stripped); /* * we add in the count of missing devices because we want Loading @@ -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 + root->fs_info->fs_devices->missing_devices; stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; if (num_devices == 1) { stripped |= BTRFS_BLOCK_GROUP_DUP; stripped = flags & ~stripped; Loading @@ -7057,7 +7060,6 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) if (flags & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) return stripped | BTRFS_BLOCK_GROUP_DUP; return flags; } else { /* they already had raid on here, just return */ if (flags & stripped) Loading @@ -7070,9 +7072,9 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) if (flags & BTRFS_BLOCK_GROUP_DUP) return stripped | BTRFS_BLOCK_GROUP_RAID1; /* turn single device chunks into raid0 */ return stripped | BTRFS_BLOCK_GROUP_RAID0; /* this is drive concat, leave it alone */ } return flags; } Loading Loading @@ -7253,6 +7255,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) u64 min_free; u64 dev_min = 1; u64 dev_nr = 0; u64 target; int index; int full = 0; int ret = 0; Loading Loading @@ -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 * devices to allocate new chunks for relocation, so loop through our * alloc devices and guess if we have enough space. However, if we * were marked as full, then we know there aren't enough chunks, and we * can just return. * alloc devices and guess if we have enough space. if this block * group is going to be restriped, run checks against the target * profile instead of the current one. */ ret = -1; if (full) goto out; /* * index: Loading @@ -7309,7 +7310,20 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * 3: raid0 * 4: single */ 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) { dev_min = 4; /* Divide by 2 */ Loading Loading @@ -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) { u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; /* chunk -> extended profile */ if (extra_flags == 0) extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; u64 extra_flags = chunk_to_extended(flags) & BTRFS_EXTENDED_PROFILE_MASK; if (flags & BTRFS_BLOCK_GROUP_DATA) fs_info->avail_data_alloc_bits &= ~extra_flags; Loading fs/btrfs/volumes.c +54 −39 Original line number Diff line number Diff line Loading @@ -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 * (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) { chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; chunk_type = chunk_to_extended(chunk_type) & BTRFS_EXTENDED_PROFILE_MASK; if (chunk_profile == 0) chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; if (bargs->profiles & chunk_profile) if (bargs->profiles & chunk_type) return 0; return 1; Loading Loading @@ -2397,18 +2395,16 @@ static int chunk_vrange_filter(struct extent_buffer *leaf, 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) { if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT)) return 0; chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; if (chunk_profile == 0) chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; chunk_type = chunk_to_extended(chunk_type) & BTRFS_EXTENDED_PROFILE_MASK; if (bargs->target & chunk_profile) if (bargs->target == chunk_type) return 1; return 0; Loading Loading @@ -2634,6 +2630,30 @@ error: 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) { /* cancel requested || normal exit path */ Loading Loading @@ -2662,6 +2682,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, { struct btrfs_fs_info *fs_info = bctl->fs_info; u64 allowed; int mixed = 0; int ret; if (btrfs_fs_closing(fs_info) || Loading @@ -2671,13 +2692,16 @@ int btrfs_balance(struct btrfs_balance_control *bctl, 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, * and identical options should be given for both of them. */ allowed = btrfs_super_incompat_flags(fs_info->super_copy); if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) { allowed = BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA; if (mixed && (bctl->flags & allowed)) { if (!(bctl->flags & BTRFS_BALANCE_DATA) || !(bctl->flags & BTRFS_BALANCE_METADATA) || memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) { Loading @@ -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; if (fs_info->fs_devices->num_devices == 1) allowed |= BTRFS_BLOCK_GROUP_DUP; Loading @@ -2705,24 +2721,27 @@ int btrfs_balance(struct btrfs_balance_control *bctl, allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10); if (!profile_is_valid(bctl->data.target, 1) || bctl->data.target & ~allowed) { if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->data.target, 1) || (bctl->data.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "data profile %llu\n", (unsigned long long)bctl->data.target); ret = -EINVAL; goto out; } if (!profile_is_valid(bctl->meta.target, 1) || bctl->meta.target & ~allowed) { if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->meta.target, 1) || (bctl->meta.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "metadata profile %llu\n", (unsigned long long)bctl->meta.target); ret = -EINVAL; goto out; } if (!profile_is_valid(bctl->sys.target, 1) || bctl->sys.target & ~allowed) { if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->sys.target, 1) || (bctl->sys.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "system profile %llu\n", (unsigned long long)bctl->sys.target); Loading @@ -2730,7 +2749,9 @@ int btrfs_balance(struct btrfs_balance_control *bctl, 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"); ret = -EINVAL; goto out; Loading @@ -2756,7 +2777,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } } do_balance: ret = insert_balance_item(fs_info->tree_root, bctl); if (ret && ret != -EEXIST) goto out; Loading Loading @@ -2999,7 +3019,7 @@ again: key.offset = (u64)-1; key.type = BTRFS_DEV_EXTENT_KEY; while (1) { do { ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto done; Loading Loading @@ -3041,8 +3061,7 @@ again: goto done; if (ret == -ENOSPC) failed++; key.offset -= 1; } } while (key.offset-- > 0); if (failed && !retried) { failed = 0; Loading Loading @@ -3160,11 +3179,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, int i; int j; if ((type & BTRFS_BLOCK_GROUP_RAID1) && (type & BTRFS_BLOCK_GROUP_DUP)) { WARN_ON(1); type &= ~BTRFS_BLOCK_GROUP_DUP; } BUG_ON(!alloc_profile_is_valid(type, 0)); if (list_empty(&fs_devices->alloc_list)) return -ENOSPC; Loading Loading
fs/btrfs/backref.c +1 −6 Original line number Diff line number Diff line Loading @@ -1342,12 +1342,6 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *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 *data; Loading Loading @@ -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) { kfree(ipath->fspath); kfree(ipath); }
fs/btrfs/ctree.h +15 −18 Original line number Diff line number Diff line Loading @@ -851,6 +851,21 @@ struct btrfs_csum_item { */ #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 { __le64 used; __le64 chunk_objectid; Loading Loading @@ -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); } /** * 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 */ int btrfs_find_root_ref(struct btrfs_root *tree_root, Loading
fs/btrfs/extent-tree.c +87 −76 Original line number Diff line number Diff line Loading @@ -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) { u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; /* chunk -> extended profile */ if (extra_flags == 0) extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; u64 extra_flags = chunk_to_extended(flags) & BTRFS_EXTENDED_PROFILE_MASK; if (flags & BTRFS_BLOCK_GROUP_DATA) fs_info->avail_data_alloc_bits |= extra_flags; Loading @@ -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; } /* * 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) * Loading @@ -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 + 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); if (root->fs_info->balance_ctl) { struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; u64 tgt = 0; 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) { target = get_restripe_target(root->fs_info, flags); if (target) { /* pick target profile only if it's already available */ if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) { spin_unlock(&root->fs_info->balance_lock); flags = tgt; goto out; return extended_to_chunk(target); } } spin_unlock(&root->fs_info->balance_lock); Loading Loading @@ -3220,10 +3234,7 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) flags &= ~BTRFS_BLOCK_GROUP_RAID0; } out: /* extended -> chunk profile */ flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; return flags; return extended_to_chunk(flags); } static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) Loading Loading @@ -3445,8 +3456,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, int wait_for_alloc = 0; int ret = 0; BUG_ON(!profile_is_valid(flags, 0)); space_info = __find_space_info(extent_root->fs_info, flags); if (!space_info) { ret = update_space_info(extent_root->fs_info, flags, Loading Loading @@ -5300,22 +5309,29 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache) return 0; } static int get_block_group_index(struct btrfs_block_group_cache *cache) static int __get_block_group_index(u64 flags) { int index; if (cache->flags & BTRFS_BLOCK_GROUP_RAID10) if (flags & BTRFS_BLOCK_GROUP_RAID10) index = 0; else if (cache->flags & BTRFS_BLOCK_GROUP_RAID1) else if (flags & BTRFS_BLOCK_GROUP_RAID1) index = 1; else if (cache->flags & BTRFS_BLOCK_GROUP_DUP) else if (flags & BTRFS_BLOCK_GROUP_DUP) index = 2; else if (cache->flags & BTRFS_BLOCK_GROUP_RAID0) else if (flags & BTRFS_BLOCK_GROUP_RAID0) index = 3; else index = 4; 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 { LOOP_CACHING_NOWAIT = 0, LOOP_CACHING_WAIT = 1, Loading Loading @@ -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) { u64 num_devices; u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; u64 stripped; if (root->fs_info->balance_ctl) { struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; u64 tgt = 0; /* pick restriper's target profile and return */ if (flags & BTRFS_BLOCK_GROUP_DATA && bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) { 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; } } /* * if restripe for this chunk_type is on pick target profile and * return, otherwise do the usual balance */ stripped = get_restripe_target(root->fs_info, flags); if (stripped) return extended_to_chunk(stripped); /* * we add in the count of missing devices because we want Loading @@ -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 + root->fs_info->fs_devices->missing_devices; stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; if (num_devices == 1) { stripped |= BTRFS_BLOCK_GROUP_DUP; stripped = flags & ~stripped; Loading @@ -7057,7 +7060,6 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) if (flags & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) return stripped | BTRFS_BLOCK_GROUP_DUP; return flags; } else { /* they already had raid on here, just return */ if (flags & stripped) Loading @@ -7070,9 +7072,9 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) if (flags & BTRFS_BLOCK_GROUP_DUP) return stripped | BTRFS_BLOCK_GROUP_RAID1; /* turn single device chunks into raid0 */ return stripped | BTRFS_BLOCK_GROUP_RAID0; /* this is drive concat, leave it alone */ } return flags; } Loading Loading @@ -7253,6 +7255,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) u64 min_free; u64 dev_min = 1; u64 dev_nr = 0; u64 target; int index; int full = 0; int ret = 0; Loading Loading @@ -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 * devices to allocate new chunks for relocation, so loop through our * alloc devices and guess if we have enough space. However, if we * were marked as full, then we know there aren't enough chunks, and we * can just return. * alloc devices and guess if we have enough space. if this block * group is going to be restriped, run checks against the target * profile instead of the current one. */ ret = -1; if (full) goto out; /* * index: Loading @@ -7309,7 +7310,20 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * 3: raid0 * 4: single */ 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) { dev_min = 4; /* Divide by 2 */ Loading Loading @@ -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) { u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; /* chunk -> extended profile */ if (extra_flags == 0) extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; u64 extra_flags = chunk_to_extended(flags) & BTRFS_EXTENDED_PROFILE_MASK; if (flags & BTRFS_BLOCK_GROUP_DATA) fs_info->avail_data_alloc_bits &= ~extra_flags; Loading
fs/btrfs/volumes.c +54 −39 Original line number Diff line number Diff line Loading @@ -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 * (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) { chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; chunk_type = chunk_to_extended(chunk_type) & BTRFS_EXTENDED_PROFILE_MASK; if (chunk_profile == 0) chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; if (bargs->profiles & chunk_profile) if (bargs->profiles & chunk_type) return 0; return 1; Loading Loading @@ -2397,18 +2395,16 @@ static int chunk_vrange_filter(struct extent_buffer *leaf, 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) { if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT)) return 0; chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; if (chunk_profile == 0) chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; chunk_type = chunk_to_extended(chunk_type) & BTRFS_EXTENDED_PROFILE_MASK; if (bargs->target & chunk_profile) if (bargs->target == chunk_type) return 1; return 0; Loading Loading @@ -2634,6 +2630,30 @@ error: 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) { /* cancel requested || normal exit path */ Loading Loading @@ -2662,6 +2682,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, { struct btrfs_fs_info *fs_info = bctl->fs_info; u64 allowed; int mixed = 0; int ret; if (btrfs_fs_closing(fs_info) || Loading @@ -2671,13 +2692,16 @@ int btrfs_balance(struct btrfs_balance_control *bctl, 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, * and identical options should be given for both of them. */ allowed = btrfs_super_incompat_flags(fs_info->super_copy); if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) { allowed = BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA; if (mixed && (bctl->flags & allowed)) { if (!(bctl->flags & BTRFS_BALANCE_DATA) || !(bctl->flags & BTRFS_BALANCE_METADATA) || memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) { Loading @@ -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; if (fs_info->fs_devices->num_devices == 1) allowed |= BTRFS_BLOCK_GROUP_DUP; Loading @@ -2705,24 +2721,27 @@ int btrfs_balance(struct btrfs_balance_control *bctl, allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10); if (!profile_is_valid(bctl->data.target, 1) || bctl->data.target & ~allowed) { if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->data.target, 1) || (bctl->data.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "data profile %llu\n", (unsigned long long)bctl->data.target); ret = -EINVAL; goto out; } if (!profile_is_valid(bctl->meta.target, 1) || bctl->meta.target & ~allowed) { if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->meta.target, 1) || (bctl->meta.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "metadata profile %llu\n", (unsigned long long)bctl->meta.target); ret = -EINVAL; goto out; } if (!profile_is_valid(bctl->sys.target, 1) || bctl->sys.target & ~allowed) { if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && (!alloc_profile_is_valid(bctl->sys.target, 1) || (bctl->sys.target & ~allowed))) { printk(KERN_ERR "btrfs: unable to start balance with target " "system profile %llu\n", (unsigned long long)bctl->sys.target); Loading @@ -2730,7 +2749,9 @@ int btrfs_balance(struct btrfs_balance_control *bctl, 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"); ret = -EINVAL; goto out; Loading @@ -2756,7 +2777,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } } do_balance: ret = insert_balance_item(fs_info->tree_root, bctl); if (ret && ret != -EEXIST) goto out; Loading Loading @@ -2999,7 +3019,7 @@ again: key.offset = (u64)-1; key.type = BTRFS_DEV_EXTENT_KEY; while (1) { do { ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto done; Loading Loading @@ -3041,8 +3061,7 @@ again: goto done; if (ret == -ENOSPC) failed++; key.offset -= 1; } } while (key.offset-- > 0); if (failed && !retried) { failed = 0; Loading Loading @@ -3160,11 +3179,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, int i; int j; if ((type & BTRFS_BLOCK_GROUP_RAID1) && (type & BTRFS_BLOCK_GROUP_DUP)) { WARN_ON(1); type &= ~BTRFS_BLOCK_GROUP_DUP; } BUG_ON(!alloc_profile_is_valid(type, 0)); if (list_empty(&fs_devices->alloc_list)) return -ENOSPC; Loading