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 { ...@@ -1084,6 +1084,9 @@ struct bch_replicas_entry {
__u8 devs[]; __u8 devs[];
} __attribute__((packed)); } __attribute__((packed));
#define replicas_entry_bytes(_i) \
(offsetof(typeof(*(_i)), devs) + (_i)->nr_devs)
struct bch_sb_field_replicas { struct bch_sb_field_replicas {
struct bch_sb_field field; struct bch_sb_field field;
struct bch_replicas_entry entries[]; struct bch_replicas_entry entries[];
......
...@@ -68,7 +68,8 @@ struct bch_ioctl_incremental { ...@@ -68,7 +68,8 @@ struct bch_ioctl_incremental {
#define BCH_IOCTL_DISK_OFFLINE _IOW(0xbc, 7, struct bch_ioctl_disk) #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_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_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_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_GET_IDX _IOW(0xbc, 13, struct bch_ioctl_disk_get_idx)
#define BCH_IOCTL_DISK_RESIZE _IOW(0xbc, 14, struct bch_ioctl_disk_resize) #define BCH_IOCTL_DISK_RESIZE _IOW(0xbc, 14, struct bch_ioctl_disk_resize)
...@@ -224,46 +225,59 @@ struct bch_ioctl_data_event { ...@@ -224,46 +225,59 @@ struct bch_ioctl_data_event {
}; };
} __attribute__((packed, aligned(8))); } __attribute__((packed, aligned(8)));
struct bch_ioctl_dev_usage { struct bch_replicas_usage {
__u8 state; __u64 sectors;
__u8 alive; struct bch_replicas_entry r;
__u8 pad[6]; } __attribute__((packed));
__u32 dev;
__u32 bucket_size; static inline struct bch_replicas_usage *
__u64 nr_buckets; replicas_usage_next(struct bch_replicas_usage *u)
{
__u64 buckets[BCH_DATA_NR]; return (void *) u + replicas_entry_bytes(&u->r) + 8;
__u64 sectors[BCH_DATA_NR]; }
};
/*
* 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 { struct bch_ioctl_fs_usage {
__u64 capacity; __u64 capacity;
__u64 used; __u64 used;
__u64 online_reserved; __u64 online_reserved;
__u64 persistent_reserved[BCH_REPLICAS_MAX]; __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 * BCH_IOCTL_DEV_USAGE: query device disk space usage
*
* Returns disk space usage broken out by data type, number of replicas, and
* by component device
* *
* @nr_devices - number of devices userspace allocated space for in @devs * Returns disk space usage broken out by data type - both by buckets and
* * sectors.
* 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
*/ */
struct bch_ioctl_usage { struct bch_ioctl_dev_usage {
__u16 nr_devices; __u64 dev;
__u16 pad[3]; __u32 flags;
__u8 state;
__u8 pad[7];
__u32 bucket_size;
__u64 nr_buckets;
struct bch_ioctl_fs_usage fs; __u64 buckets[BCH_DATA_NR];
struct bch_ioctl_dev_usage devs[0]; __u64 sectors[BCH_DATA_NR];
}; };
/* /*
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "buckets.h" #include "buckets.h"
#include "chardev.h" #include "chardev.h"
#include "move.h" #include "move.h"
#include "replicas.h"
#include "super.h" #include "super.h"
#include "super-io.h" #include "super-io.h"
...@@ -371,89 +372,116 @@ static long bch2_ioctl_data(struct bch_fs *c, ...@@ -371,89 +372,116 @@ static long bch2_ioctl_data(struct bch_fs *c,
return ret; return ret;
} }
static long bch2_ioctl_usage(struct bch_fs *c, static long bch2_ioctl_fs_usage(struct bch_fs *c,
struct bch_ioctl_usage __user *user_arg) struct bch_ioctl_fs_usage __user *user_arg)
{ {
struct bch_ioctl_usage arg; struct bch_ioctl_fs_usage *arg = NULL;
struct bch_dev *ca; struct bch_replicas_usage *dst_e, *dst_end;
unsigned i, j; struct bch_fs_usage_online *src;
int ret; u32 replica_entries_bytes;
unsigned i;
int ret = 0;
if (!test_bit(BCH_FS_STARTED, &c->flags)) if (!test_bit(BCH_FS_STARTED, &c->flags))
return -EINVAL; return -EINVAL;
if (copy_from_user(&arg, user_arg, sizeof(arg))) if (get_user(replica_entries_bytes, &user_arg->replica_entries_bytes))
return -EFAULT; return -EFAULT;
for (i = 0; i < arg.nr_devices; i++) { arg = kzalloc(sizeof(*arg) + replica_entries_bytes, GFP_KERNEL);
struct bch_ioctl_dev_usage dst = { .alive = 0 }; if (!arg)
return -ENOMEM;
ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst)); src = bch2_fs_usage_read(c);
if (ret) if (!src) {
return ret; ret = -ENOMEM;
goto err;
} }
{ arg->capacity = c->capacity;
struct bch_fs_usage_online *src; arg->used = bch2_fs_sectors_used(c, src);
struct bch_ioctl_fs_usage dst = { arg->online_reserved = src->online_reserved;
.capacity = c->capacity,
};
src = bch2_fs_usage_read(c); for (i = 0; i < BCH_REPLICAS_MAX; i++)
if (!src) arg->persistent_reserved[i] = src->u.persistent_reserved[i];
return -ENOMEM;
dst.used = bch2_fs_sectors_used(c, src); dst_e = arg->replicas;
dst.online_reserved = src->online_reserved; 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++) { if (replicas_usage_next(dst_e) > dst_end) {
dst.persistent_reserved[i] = ret = -ERANGE;
src->u.persistent_reserved[i]; break;
#if 0
for (j = 0; j < BCH_DATA_NR; j++)
dst.sectors[j][i] = src.replicas[i].data[j];
#endif
} }
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)); memcpy(dst_e->r.devs, src_e->devs, src_e->nr_devs);
if (ret)
return ret; dst_e = replicas_usage_next(dst_e);
} }
for_each_member_device(ca, c, i) { arg->replica_entries_bytes = (void *) dst_e - (void *) arg->replicas;
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;
}
if (percpu_ref_tryget(&ca->io_ref)) { percpu_up_read(&c->mark_lock);
dst.dev = huge_encode_dev(ca->disk_sb.bdev->bd_dev); kfree(src);
percpu_ref_put(&ca->io_ref);
}
for (j = 0; j < BCH_DATA_NR; j++) { if (!ret)
dst.buckets[j] = src.buckets[j]; ret = copy_to_user(user_arg, arg,
dst.sectors[j] = src.sectors[j]; 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 (copy_from_user(&arg, user_arg, sizeof(arg)))
if (ret) return -EFAULT;
return ret;
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, 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) ...@@ -547,8 +575,10 @@ long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
switch (cmd) { switch (cmd) {
case BCH_IOCTL_QUERY_UUID: case BCH_IOCTL_QUERY_UUID:
return bch2_ioctl_query_uuid(c, arg); return bch2_ioctl_query_uuid(c, arg);
case BCH_IOCTL_USAGE: case BCH_IOCTL_FS_USAGE:
return bch2_ioctl_usage(c, arg); return bch2_ioctl_fs_usage(c, arg);
case BCH_IOCTL_DEV_USAGE:
return bch2_ioctl_dev_usage(c, arg);
} }
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
......
...@@ -72,9 +72,6 @@ int bch2_replicas_set_usage(struct bch_fs *, ...@@ -72,9 +72,6 @@ int bch2_replicas_set_usage(struct bch_fs *,
/* iterate over superblock replicas - used by userspace tools: */ /* 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) \ #define replicas_entry_next(_i) \
((typeof(_i)) ((void *) (_i) + replicas_entry_bytes(_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