Experimental patch to be able to compact only the metadata after
excessive block groups are created.  I guess it should be implemented
as a balance option rather than a separate ioctl, but this was good
enough for me to try it.

Signed-off-by: Alexandre Oliva <ol...@lsd.ic.unicamp.br>
---
 fs/btrfs/ioctl.c   |    2 ++
 fs/btrfs/ioctl.h   |    3 +++
 fs/btrfs/volumes.c |   33 ++++++++++++++++++++++++++++-----
 fs/btrfs/volumes.h |    1 +
 4 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index a90e749..6f53983 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3077,6 +3077,8 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_dev_info(root, argp);
        case BTRFS_IOC_BALANCE:
                return btrfs_balance(root->fs_info->dev_root);
+       case BTRFS_IOC_BALANCE_METADATA:
+               return btrfs_balance_metadata(root->fs_info->dev_root);
        case BTRFS_IOC_CLONE:
                return btrfs_ioctl_clone(file, arg, 0, 0, 0);
        case BTRFS_IOC_CLONE_RANGE:
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 252ae99..46bc428 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -277,4 +277,7 @@ struct btrfs_ioctl_logical_ino_args {
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
                                        struct btrfs_ioctl_ino_path_args)
 
+#define BTRFS_IOC_BALANCE_METADATA _IOW(BTRFS_IOCTL_MAGIC, 37, \
+                                       struct btrfs_ioctl_vol_args)
+
 #endif
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 7b348c2..db4397d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2084,7 +2084,7 @@ static u64 div_factor(u64 num, int factor)
        return num;
 }
 
-int btrfs_balance(struct btrfs_root *dev_root)
+static int btrfs_balance_skip(struct btrfs_root *dev_root, u64 skip_type)
 {
        int ret;
        struct list_head *devices = &dev_root->fs_info->fs_devices->devices;
@@ -2096,6 +2096,9 @@ int btrfs_balance(struct btrfs_root *dev_root)
        struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root;
        struct btrfs_trans_handle *trans;
        struct btrfs_key found_key;
+       struct btrfs_chunk *chunk;
+       u64 chunk_type;
+       bool skip;
 
        if (dev_root->fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
@@ -2165,11 +2168,21 @@ int btrfs_balance(struct btrfs_root *dev_root)
                if (found_key.offset == 0)
                        break;
 
+               if (skip_type) {
+                       chunk = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                              struct btrfs_chunk);
+                       chunk_type = btrfs_chunk_type(path->nodes[0], chunk);
+                       skip = (chunk_type & skip_type);
+               } else
+                       skip = false;
+
                btrfs_release_path(path);
-               ret = btrfs_relocate_chunk(chunk_root,
-                                          chunk_root->root_key.objectid,
-                                          found_key.objectid,
-                                          found_key.offset);
+
+               ret = (skip ? 0 :
+                      btrfs_relocate_chunk(chunk_root,
+                                           chunk_root->root_key.objectid,
+                                           found_key.objectid,
+                                           found_key.offset));
                if (ret && ret != -ENOSPC)
                        goto error;
                key.offset = found_key.offset - 1;
@@ -2181,6 +2194,16 @@ error:
        return ret;
 }
 
+int btrfs_balance(struct btrfs_root *dev_root)
+{
+       return btrfs_balance_skip(dev_root, 0);
+}
+
+int btrfs_balance_metadata(struct btrfs_root *dev_root)
+{
+       return btrfs_balance_skip(dev_root, BTRFS_BLOCK_GROUP_DATA);
+}
+
 /*
  * shrinking a device means finding all of the device extents past
  * the new size, and then following the back refs to the chunks.
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 78f2d4d..6844010 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -229,6 +229,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root 
*root, u64 devid,
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_balance(struct btrfs_root *dev_root);
+int btrfs_balance_metadata(struct btrfs_root *dev_root);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
 int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,
-- 
1.7.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to