aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:47 -0500
committerIlya Dryomov <idryomov@gmail.com>2012-01-16 15:04:47 -0500
commitf43ffb60fd94e98be02780944e182ade6653b916 (patch)
tree50cab47a03c223d0641d8fe62805e71f5cffef1a /fs/btrfs/volumes.c
parentc9e9f97bdfb64d06e9520f8e4f37674ac21cc9bc (diff)
Btrfs: add basic infrastructure for selective balancing
This allows to have a separate set of filters for each chunk type (data,meta,sys). The code however is generic and switch on chunk type is only done once. This commit also adds a type filter: it allows to balance for example meta and system chunks w/o touching data ones. Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 9fc06e6bc51a..91bbf6e774c0 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2102,6 +2102,30 @@ static void unset_balance_control(struct btrfs_fs_info *fs_info)
2102 kfree(bctl); 2102 kfree(bctl);
2103} 2103}
2104 2104
2105static int should_balance_chunk(struct btrfs_root *root,
2106 struct extent_buffer *leaf,
2107 struct btrfs_chunk *chunk, u64 chunk_offset)
2108{
2109 struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
2110 struct btrfs_balance_args *bargs = NULL;
2111 u64 chunk_type = btrfs_chunk_type(leaf, chunk);
2112
2113 /* type filter */
2114 if (!((chunk_type & BTRFS_BLOCK_GROUP_TYPE_MASK) &
2115 (bctl->flags & BTRFS_BALANCE_TYPE_MASK))) {
2116 return 0;
2117 }
2118
2119 if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
2120 bargs = &bctl->data;
2121 else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM)
2122 bargs = &bctl->sys;
2123 else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA)
2124 bargs = &bctl->meta;
2125
2126 return 1;
2127}
2128
2105static u64 div_factor(u64 num, int factor) 2129static u64 div_factor(u64 num, int factor)
2106{ 2130{
2107 if (factor == 10) 2131 if (factor == 10)
@@ -2119,10 +2143,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2119 struct btrfs_device *device; 2143 struct btrfs_device *device;
2120 u64 old_size; 2144 u64 old_size;
2121 u64 size_to_free; 2145 u64 size_to_free;
2146 struct btrfs_chunk *chunk;
2122 struct btrfs_path *path; 2147 struct btrfs_path *path;
2123 struct btrfs_key key; 2148 struct btrfs_key key;
2124 struct btrfs_key found_key; 2149 struct btrfs_key found_key;
2125 struct btrfs_trans_handle *trans; 2150 struct btrfs_trans_handle *trans;
2151 struct extent_buffer *leaf;
2152 int slot;
2126 int ret; 2153 int ret;
2127 int enospc_errors = 0; 2154 int enospc_errors = 0;
2128 2155
@@ -2179,8 +2206,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2179 break; 2206 break;
2180 } 2207 }
2181 2208
2182 btrfs_item_key_to_cpu(path->nodes[0], &found_key, 2209 leaf = path->nodes[0];
2183 path->slots[0]); 2210 slot = path->slots[0];
2211 btrfs_item_key_to_cpu(leaf, &found_key, slot);
2212
2184 if (found_key.objectid != key.objectid) 2213 if (found_key.objectid != key.objectid)
2185 break; 2214 break;
2186 2215
@@ -2188,7 +2217,14 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2188 if (found_key.offset == 0) 2217 if (found_key.offset == 0)
2189 break; 2218 break;
2190 2219
2220 chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
2221
2222 ret = should_balance_chunk(chunk_root, leaf, chunk,
2223 found_key.offset);
2191 btrfs_release_path(path); 2224 btrfs_release_path(path);
2225 if (!ret)
2226 goto loop;
2227
2192 ret = btrfs_relocate_chunk(chunk_root, 2228 ret = btrfs_relocate_chunk(chunk_root,
2193 chunk_root->root_key.objectid, 2229 chunk_root->root_key.objectid,
2194 found_key.objectid, 2230 found_key.objectid,
@@ -2197,6 +2233,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2197 goto error; 2233 goto error;
2198 if (ret == -ENOSPC) 2234 if (ret == -ENOSPC)
2199 enospc_errors++; 2235 enospc_errors++;
2236loop:
2200 key.offset = found_key.offset - 1; 2237 key.offset = found_key.offset - 1;
2201 } 2238 }
2202 2239
@@ -2227,6 +2264,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
2227 struct btrfs_ioctl_balance_args *bargs) 2264 struct btrfs_ioctl_balance_args *bargs)
2228{ 2265{
2229 struct btrfs_fs_info *fs_info = bctl->fs_info; 2266 struct btrfs_fs_info *fs_info = bctl->fs_info;
2267 u64 allowed;
2230 int ret; 2268 int ret;
2231 2269
2232 if (btrfs_fs_closing(fs_info)) { 2270 if (btrfs_fs_closing(fs_info)) {
@@ -2234,6 +2272,23 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
2234 goto out; 2272 goto out;
2235 } 2273 }
2236 2274
2275 /*
2276 * In case of mixed groups both data and meta should be picked,
2277 * and identical options should be given for both of them.
2278 */
2279 allowed = btrfs_super_incompat_flags(fs_info->super_copy);
2280 if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
2281 (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) {
2282 if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
2283 !(bctl->flags & BTRFS_BALANCE_METADATA) ||
2284 memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
2285 printk(KERN_ERR "btrfs: with mixed groups data and "
2286 "metadata balance options must be the same\n");
2287 ret = -EINVAL;
2288 goto out;
2289 }
2290 }
2291
2237 set_balance_control(bctl); 2292 set_balance_control(bctl);
2238 2293
2239 mutex_unlock(&fs_info->balance_mutex); 2294 mutex_unlock(&fs_info->balance_mutex);