Commit 22502ac2 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 184b1dc1
......@@ -1084,6 +1084,9 @@ struct bch_replicas_entry {
__u8 devs[];
} __attribute__((packed));
#define replicas_entry_bytes(_i) \
(offsetof(typeof(*(_i)), devs) + (_i)->nr_devs)
struct bch_sb_field_replicas {
struct bch_sb_field field;
struct bch_replicas_entry entries[];
......
......@@ -68,7 +68,8 @@ struct bch_ioctl_incremental {
#define BCH_IOCTL_DISK_OFFLINE _IOW(0xbc, 7, struct bch_ioctl_disk)
#define BCH_IOCTL_DISK_SET_STATE _IOW(0xbc, 8, struct bch_ioctl_disk_set_state)
#define BCH_IOCTL_DATA _IOW(0xbc, 10, struct bch_ioctl_data)
#define BCH_IOCTL_USAGE _IOWR(0xbc, 11, struct bch_ioctl_usage)
#define BCH_IOCTL_FS_USAGE _IOWR(0xbc, 11, struct bch_ioctl_fs_usage)
#define BCH_IOCTL_DEV_USAGE _IOWR(0xbc, 11, struct bch_ioctl_dev_usage)
#define BCH_IOCTL_READ_SUPER _IOW(0xbc, 12, struct bch_ioctl_read_super)
#define BCH_IOCTL_DISK_GET_IDX _IOW(0xbc, 13, struct bch_ioctl_disk_get_idx)
#define BCH_IOCTL_DISK_RESIZE _IOW(0xbc, 14, struct bch_ioctl_disk_resize)
......@@ -224,46 +225,59 @@ struct bch_ioctl_data_event {
};
} __attribute__((packed, aligned(8)));
struct bch_ioctl_dev_usage {
__u8 state;
__u8 alive;
__u8 pad[6];
__u32 dev;
struct bch_replicas_usage {
__u64 sectors;
struct bch_replicas_entry r;
} __attribute__((packed));
__u32 bucket_size;
__u64 nr_buckets;
__u64 buckets[BCH_DATA_NR];
__u64 sectors[BCH_DATA_NR];
};
static inline struct bch_replicas_usage *
replicas_usage_next(struct bch_replicas_usage *u)
{
return (void *) u + replicas_entry_bytes(&u->r) + 8;
}
/*
* BCH_IOCTL_FS_USAGE: query filesystem disk space usage
*
* Returns disk space usage broken out by data type, number of replicas, and
* by component device
*
* @replica_entries_bytes - size, in bytes, allocated for replica usage entries
*
* On success, @replica_entries_bytes will be changed to indicate the number of
* bytes actually used.
*
* Returns -ERANGE if @replica_entries_bytes was too small
*/
struct bch_ioctl_fs_usage {
__u64 capacity;
__u64 used;
__u64 online_reserved;
__u64 persistent_reserved[BCH_REPLICAS_MAX];
__u64 sectors[BCH_DATA_NR][BCH_REPLICAS_MAX];
__u32 replica_entries_bytes;
__u32 pad;
struct bch_replicas_usage replicas[0];
};
/*
* BCH_IOCTL_USAGE: query filesystem disk space usage
*
* Returns disk space usage broken out by data type, number of replicas, and
* by component device
* BCH_IOCTL_DEV_USAGE: query device disk space usage
*
* @nr_devices - number of devices userspace allocated space for in @devs
*
* On success, @fs and @devs will be filled out appropriately and devs[i].alive
* will indicate if a device was present in that slot
*
* Returns -ERANGE if @nr_devices was too small
* Returns disk space usage broken out by data type - both by buckets and
* sectors.
*/
struct bch_ioctl_usage {
__u16 nr_devices;
__u16 pad[3];
struct bch_ioctl_dev_usage {
__u64 dev;
__u32 flags;
__u8 state;
__u8 pad[7];
__u32 bucket_size;
__u64 nr_buckets;
struct bch_ioctl_fs_usage fs;
struct bch_ioctl_dev_usage devs[0];
__u64 buckets[BCH_DATA_NR];
__u64 sectors[BCH_DATA_NR];
};
/*
......
......@@ -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 @@ static long bch2_ioctl_data(struct bch_fs *c,
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))
......
......@@ -72,9 +72,6 @@ int bch2_replicas_set_usage(struct bch_fs *,
/* iterate over superblock replicas - used by userspace tools: */
#define replicas_entry_bytes(_i) \
(offsetof(typeof(*(_i)), devs) + (_i)->nr_devs)
#define replicas_entry_next(_i) \
((typeof(_i)) ((void *) (_i) + replicas_entry_bytes(_i)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment