diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-12-16 17:53:59 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:33 -0400 |
commit | 22502ac23a2eaa3714b77d4a9242df352a9cd0c0 (patch) | |
tree | bb4b1a751942623c49d507ef00d6ab28667d1695 /fs/bcachefs/chardev.c | |
parent | 184b1dc1a6bf4bc53a1c71bf14120498aad67ff5 (diff) |
bcachefs: Redo filesystem usage ioctls
When disk space accounting was changed to be tracked by replicas entry,
the ioctl interface was never update: this patch finally does that.
Aditionally, the BCH_IOCTL_USAGE ioctl is now broken out into separate
ioctls for filesystem and device usage.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/chardev.c')
-rw-r--r-- | fs/bcachefs/chardev.c | 152 |
1 files changed, 91 insertions, 61 deletions
diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c index 4d8331022648..084bef5e7997 100644 --- a/fs/bcachefs/chardev.c +++ b/fs/bcachefs/chardev.c @@ -6,6 +6,7 @@ #include "buckets.h" #include "chardev.h" #include "move.h" +#include "replicas.h" #include "super.h" #include "super-io.h" @@ -371,89 +372,116 @@ err: return ret; } -static long bch2_ioctl_usage(struct bch_fs *c, - struct bch_ioctl_usage __user *user_arg) +static long bch2_ioctl_fs_usage(struct bch_fs *c, + struct bch_ioctl_fs_usage __user *user_arg) { - struct bch_ioctl_usage arg; - struct bch_dev *ca; - unsigned i, j; - int ret; + struct bch_ioctl_fs_usage *arg = NULL; + struct bch_replicas_usage *dst_e, *dst_end; + struct bch_fs_usage_online *src; + u32 replica_entries_bytes; + unsigned i; + int ret = 0; if (!test_bit(BCH_FS_STARTED, &c->flags)) return -EINVAL; - if (copy_from_user(&arg, user_arg, sizeof(arg))) + if (get_user(replica_entries_bytes, &user_arg->replica_entries_bytes)) return -EFAULT; - for (i = 0; i < arg.nr_devices; i++) { - struct bch_ioctl_dev_usage dst = { .alive = 0 }; + arg = kzalloc(sizeof(*arg) + replica_entries_bytes, GFP_KERNEL); + if (!arg) + return -ENOMEM; - ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst)); - if (ret) - return ret; + src = bch2_fs_usage_read(c); + if (!src) { + ret = -ENOMEM; + goto err; } - { - struct bch_fs_usage_online *src; - struct bch_ioctl_fs_usage dst = { - .capacity = c->capacity, - }; + arg->capacity = c->capacity; + arg->used = bch2_fs_sectors_used(c, src); + arg->online_reserved = src->online_reserved; - src = bch2_fs_usage_read(c); - if (!src) - return -ENOMEM; + for (i = 0; i < BCH_REPLICAS_MAX; i++) + arg->persistent_reserved[i] = src->u.persistent_reserved[i]; - dst.used = bch2_fs_sectors_used(c, src); - dst.online_reserved = src->online_reserved; + dst_e = arg->replicas; + dst_end = (void *) arg->replicas + replica_entries_bytes; - percpu_up_read(&c->mark_lock); + for (i = 0; i < c->replicas.nr; i++) { + struct bch_replicas_entry *src_e = + cpu_replicas_entry(&c->replicas, i); - for (i = 0; i < BCH_REPLICAS_MAX; i++) { - dst.persistent_reserved[i] = - src->u.persistent_reserved[i]; -#if 0 - for (j = 0; j < BCH_DATA_NR; j++) - dst.sectors[j][i] = src.replicas[i].data[j]; -#endif + if (replicas_usage_next(dst_e) > dst_end) { + ret = -ERANGE; + break; } - kfree(src); + dst_e->sectors = src->u.replicas[i]; + dst_e->r = *src_e; + + /* recheck after setting nr_devs: */ + if (replicas_usage_next(dst_e) > dst_end) { + ret = -ERANGE; + break; + } - ret = copy_to_user(&user_arg->fs, &dst, sizeof(dst)); - if (ret) - return ret; + memcpy(dst_e->r.devs, src_e->devs, src_e->nr_devs); + + dst_e = replicas_usage_next(dst_e); } - for_each_member_device(ca, c, i) { - struct bch_dev_usage src = bch2_dev_usage_read(c, ca); - struct bch_ioctl_dev_usage dst = { - .alive = 1, - .state = ca->mi.state, - .bucket_size = ca->mi.bucket_size, - .nr_buckets = ca->mi.nbuckets - ca->mi.first_bucket, - }; - - if (ca->dev_idx >= arg.nr_devices) { - percpu_ref_put(&ca->ref); - return -ERANGE; - } + arg->replica_entries_bytes = (void *) dst_e - (void *) arg->replicas; - if (percpu_ref_tryget(&ca->io_ref)) { - dst.dev = huge_encode_dev(ca->disk_sb.bdev->bd_dev); - percpu_ref_put(&ca->io_ref); - } + percpu_up_read(&c->mark_lock); + kfree(src); - for (j = 0; j < BCH_DATA_NR; j++) { - dst.buckets[j] = src.buckets[j]; - dst.sectors[j] = src.sectors[j]; - } + if (!ret) + ret = copy_to_user(user_arg, arg, + sizeof(*arg) + arg->replica_entries_bytes); +err: + kfree(arg); + return ret; +} + +static long bch2_ioctl_dev_usage(struct bch_fs *c, + struct bch_ioctl_dev_usage __user *user_arg) +{ + struct bch_ioctl_dev_usage arg; + struct bch_dev_usage src; + struct bch_dev *ca; + unsigned i; + + if (!test_bit(BCH_FS_STARTED, &c->flags)) + return -EINVAL; - ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst)); - if (ret) - return ret; + if (copy_from_user(&arg, user_arg, sizeof(arg))) + return -EFAULT; + + if ((arg.flags & ~BCH_BY_INDEX) || + arg.pad[0] || + arg.pad[1] || + arg.pad[2]) + return -EINVAL; + + ca = bch2_device_lookup(c, arg.dev, arg.flags); + if (IS_ERR(ca)) + return PTR_ERR(ca); + + src = bch2_dev_usage_read(c, ca); + + arg.state = ca->mi.state; + arg.bucket_size = ca->mi.bucket_size; + arg.nr_buckets = ca->mi.nbuckets - ca->mi.first_bucket; + + for (i = 0; i < BCH_DATA_NR; i++) { + arg.buckets[i] = src.buckets[i]; + arg.sectors[i] = src.sectors[i]; } - return 0; + percpu_ref_put(&ca->ref); + + return copy_to_user(user_arg, &arg, sizeof(arg)); } static long bch2_ioctl_read_super(struct bch_fs *c, @@ -547,8 +575,10 @@ long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg) switch (cmd) { case BCH_IOCTL_QUERY_UUID: return bch2_ioctl_query_uuid(c, arg); - case BCH_IOCTL_USAGE: - return bch2_ioctl_usage(c, arg); + case BCH_IOCTL_FS_USAGE: + return bch2_ioctl_fs_usage(c, arg); + case BCH_IOCTL_DEV_USAGE: + return bch2_ioctl_dev_usage(c, arg); } if (!capable(CAP_SYS_ADMIN)) |