Btrfs: add balance progress reporting - kernel/git/torvalds/linux.git (original) (raw)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 85e546ffe3c791..1e7a9bac31ab9f 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c

@@ -3065,7 +3065,7 @@ out:

return ret;

}

-void update_ioctl_balance_args(struct btrfs_fs_info *fs_info,

+void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,

struct btrfs_ioctl_balance_args *bargs)

{

struct btrfs_balance_control *bctl = fs_info->balance_ctl;

@@ -3082,6 +3082,14 @@ void update_ioctl_balance_args(struct btrfs_fs_info *fs_info,

memcpy(&bargs->data, &bctl->data, sizeof(bargs->data));

memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta));

memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys));

+ if (lock) {

+ spin_lock(&fs_info->balance_lock);

+ memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat));

+ spin_unlock(&fs_info->balance_lock);

+ } else {

+ memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat));

+ }

}

static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg)

@@ -3181,6 +3189,39 @@ static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd)

return -EINVAL;

}

+static long btrfs_ioctl_balance_progress(struct btrfs_root *root,

+ void __user *arg)

+{

+ struct btrfs_fs_info *fs_info = root->fs_info;

+ struct btrfs_ioctl_balance_args *bargs;

+ int ret = 0;

+ if (!capable(CAP_SYS_ADMIN))

+ return -EPERM;

+ mutex_lock(&fs_info->balance_mutex);

+ if (!fs_info->balance_ctl) {

+ ret = -ENOTCONN;

+ goto out;

+ }

+ bargs = kzalloc(sizeof(*bargs), GFP_NOFS);

+ if (!bargs) {

+ ret = -ENOMEM;

+ goto out;

+ }

+ update_ioctl_balance_args(fs_info, 1, bargs);

+ if (copy_to_user(arg, bargs, sizeof(*bargs)))

+ ret = -EFAULT;

+ kfree(bargs);

+out:

+ mutex_unlock(&fs_info->balance_mutex);

+ return ret;

+}

long btrfs_ioctl(struct file *file, unsigned int

cmd, unsigned long arg)

{

@@ -3261,6 +3302,8 @@ long btrfs_ioctl(struct file *file, unsigned int

return btrfs_ioctl_balance(root, argp);

case BTRFS_IOC_BALANCE_CTL:

return btrfs_ioctl_balance_ctl(root, arg);

+ case BTRFS_IOC_BALANCE_PROGRESS:

+ return btrfs_ioctl_balance_progress(root, argp);

}

return -ENOTTY;

diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index cd19d10794b94f..4f69028a68c486 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h

@@ -324,6 +324,8 @@ struct btrfs_ioctl_logical_ino_args {

#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \

struct btrfs_ioctl_balance_args)

#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)

+#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \

+ struct btrfs_ioctl_balance_args)

#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \

struct btrfs_ioctl_ino_path_args)

#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \

@@ -2441,6 +2441,7 @@ static u64 div_factor(u64 num, int factor)

static int __btrfs_balance(struct btrfs_fs_info *fs_info)

{

+ struct btrfs_balance_control *bctl = fs_info->balance_ctl;

struct btrfs_root *chunk_root = fs_info->chunk_root;

struct btrfs_root *dev_root = fs_info->dev_root;

struct list_head *devices;

@@ -2456,6 +2457,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)

int slot;

int ret;

int enospc_errors = 0;

+ bool counting = true;

/* step one make some room on all the devices */

devices = &fs_info->fs_devices->devices;

@@ -2487,12 +2489,18 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)

ret = -ENOMEM;

goto error;

}

+ /* zero out stat counters */

+ spin_lock(&fs_info->balance_lock);

+ memset(&bctl->stat, 0, sizeof(bctl->stat));

+ spin_unlock(&fs_info->balance_lock);

+again:

key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;

key.offset = (u64)-1;

key.type = BTRFS_CHUNK_ITEM_KEY;

while (1) {

- if (atomic_read(&fs_info->balance_pause_req) ||

+ if ((!counting && atomic_read(&fs_info->balance_pause_req)) ||

atomic_read(&fs_info->balance_cancel_req)) {

ret = -ECANCELED;

goto error;

@@ -2529,24 +2537,47 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)

chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);

+ if (!counting) {

+ spin_lock(&fs_info->balance_lock);

+ bctl->stat.considered++;

+ spin_unlock(&fs_info->balance_lock);

+ }

ret = should_balance_chunk(chunk_root, leaf, chunk,

found_key.offset);

btrfs_release_path(path);

if (!ret)

goto loop;

+ if (counting) {

+ spin_lock(&fs_info->balance_lock);

+ bctl->stat.expected++;

+ spin_unlock(&fs_info->balance_lock);

+ goto loop;

+ }

ret = btrfs_relocate_chunk(chunk_root,

chunk_root->root_key.objectid,

found_key.objectid,

found_key.offset);

if (ret && ret != -ENOSPC)

goto error;

- if (ret == -ENOSPC)

+ if (ret == -ENOSPC) {

enospc_errors++;

+ } else {

+ spin_lock(&fs_info->balance_lock);

+ bctl->stat.completed++;

+ spin_unlock(&fs_info->balance_lock);

+ }

loop:

key.offset = found_key.offset - 1;

}

+ if (counting) {

+ btrfs_release_path(path);

+ counting = false;

+ goto again;

+ }

error:

btrfs_free_path(path);

if (enospc_errors) {

@@ -2576,7 +2607,7 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)

BUG_ON(ret);

}

-void update_ioctl_balance_args(struct btrfs_fs_info *fs_info,

+void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,

struct btrfs_ioctl_balance_args *bargs);

/*

@@ -2706,7 +2737,7 @@ do_balance:

if (bargs) {

memset(bargs, 0, sizeof(*bargs));

- update_ioctl_balance_args(fs_info, bargs);

+ update_ioctl_balance_args(fs_info, 0, bargs);

}

if ((ret && ret != -ECANCELED && ret != -ENOSPC) ||

@@ -218,6 +218,7 @@ struct map_lookup {

#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9)

struct btrfs_balance_args;

+struct btrfs_balance_progress;

struct btrfs_balance_control {

struct btrfs_fs_info *fs_info;

@@ -226,6 +227,8 @@ struct btrfs_balance_control {

struct btrfs_balance_args sys;

u64 flags;

+ struct btrfs_balance_progress stat;

};

int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,