mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-23 00:00:02 +03:00
cmd_fs_usage: Use now BCH_IOCTL_QUERY_ACCOUNTING
We can now report on compression type/ratio, btree usage, and pending rebalance work. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
da5435b0cc
commit
0916d38664
239
c_src/cmd_fs.c
239
c_src/cmd_fs.c
@ -9,6 +9,7 @@
|
||||
|
||||
#include "libbcachefs/bcachefs_ioctl.h"
|
||||
#include "libbcachefs/buckets.h"
|
||||
#include "libbcachefs/disk_accounting.h"
|
||||
#include "libbcachefs/opts.h"
|
||||
#include "libbcachefs/super-io.h"
|
||||
|
||||
@ -151,11 +152,28 @@ static void devs_usage_to_text(struct printbuf *out,
|
||||
}
|
||||
}
|
||||
|
||||
static void persistent_reserved_to_text(struct printbuf *out,
|
||||
unsigned nr_replicas, s64 sectors)
|
||||
{
|
||||
if (!sectors)
|
||||
return;
|
||||
|
||||
prt_str(out, "reserved:");
|
||||
prt_tab(out);
|
||||
prt_printf(out, "%u/%u ", 1, nr_replicas);
|
||||
prt_tab(out);
|
||||
prt_str(out, "[] ");
|
||||
prt_units_u64(out, sectors << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
|
||||
static void replicas_usage_to_text(struct printbuf *out,
|
||||
const struct bch_replicas_usage *r,
|
||||
const struct bch_replicas_entry_v1 *r,
|
||||
s64 sectors,
|
||||
dev_names *dev_names)
|
||||
{
|
||||
if (!r->sectors)
|
||||
if (!sectors)
|
||||
return;
|
||||
|
||||
char devs[4096], *d = devs;
|
||||
@ -163,8 +181,8 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
|
||||
unsigned durability = 0;
|
||||
|
||||
for (unsigned i = 0; i < r->r.nr_devs; i++) {
|
||||
unsigned dev_idx = r->r.devs[i];
|
||||
for (unsigned i = 0; i < r->nr_devs; i++) {
|
||||
unsigned dev_idx = r->devs[i];
|
||||
struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
|
||||
|
||||
durability += dev->durability;
|
||||
@ -179,11 +197,11 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
*d++ = ']';
|
||||
*d++ = '\0';
|
||||
|
||||
bch2_prt_data_type(out, r->r.data_type);
|
||||
bch2_prt_data_type(out, r->data_type);
|
||||
prt_char(out, ':');
|
||||
prt_tab(out);
|
||||
|
||||
prt_printf(out, "%u/%u ", r->r.nr_required, r->r.nr_devs);
|
||||
prt_printf(out, "%u/%u ", r->nr_required, r->nr_devs);
|
||||
prt_tab(out);
|
||||
|
||||
prt_printf(out, "%u ", durability);
|
||||
@ -192,7 +210,7 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
prt_printf(out, "%s ", devs);
|
||||
prt_tab(out);
|
||||
|
||||
prt_units_u64(out, r->sectors << 9);
|
||||
prt_units_u64(out, sectors << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
@ -203,14 +221,178 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
_r = replicas_usage_next(_r), \
|
||||
BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
|
||||
|
||||
static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
typedef DARRAY(struct bkey_i_accounting *) darray_accounting_p;
|
||||
|
||||
static int accounting_p_cmp(const void *_l, const void *_r)
|
||||
{
|
||||
unsigned i;
|
||||
const struct bkey_i_accounting * const *l = _l;
|
||||
const struct bkey_i_accounting * const *r = _r;
|
||||
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
struct bpos lp = (*l)->k.p, rp = (*r)->k.p;
|
||||
|
||||
dev_names dev_names = bchu_fs_get_devices(fs);
|
||||
bch2_bpos_swab(&lp);
|
||||
bch2_bpos_swab(&rp);
|
||||
return bpos_cmp(lp, rp);
|
||||
}
|
||||
|
||||
static void accounting_sort(darray_accounting_p *sorted,
|
||||
struct bch_ioctl_query_accounting *in)
|
||||
{
|
||||
for (struct bkey_i_accounting *a = in->accounting;
|
||||
a < (struct bkey_i_accounting *) ((u64 *) in->accounting + in->accounting_u64s);
|
||||
a = bkey_i_to_accounting(bkey_next(&a->k_i)))
|
||||
if (darray_push(sorted, a))
|
||||
die("memory allocation failure");
|
||||
|
||||
sort(sorted->data, sorted->nr, sizeof(sorted->data[0]), accounting_p_cmp, NULL);
|
||||
}
|
||||
|
||||
static int fs_usage_v1_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
{
|
||||
struct bch_ioctl_query_accounting *a =
|
||||
bchu_fs_accounting(fs,
|
||||
BIT(BCH_DISK_ACCOUNTING_persistent_reserved)|
|
||||
BIT(BCH_DISK_ACCOUNTING_replicas)|
|
||||
BIT(BCH_DISK_ACCOUNTING_compression)|
|
||||
BIT(BCH_DISK_ACCOUNTING_btree)|
|
||||
BIT(BCH_DISK_ACCOUNTING_rebalance_work));
|
||||
if (!a)
|
||||
return -1;
|
||||
|
||||
darray_accounting_p a_sorted = {};
|
||||
|
||||
accounting_sort(&a_sorted, a);
|
||||
|
||||
prt_str(out, "Filesystem: ");
|
||||
pr_uuid(out, fs.uuid.b);
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 20);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
|
||||
prt_str(out, "Size:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->capacity << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_str(out, "Used:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->used << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_str(out, "Online reserved:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->online_reserved << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
|
||||
printbuf_tabstop_push(out, 16);
|
||||
prt_str(out, "Data type");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 16);
|
||||
prt_str(out, "Required/total");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
prt_str(out, "Durability");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
prt_str(out, "Devices");
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
|
||||
unsigned prev_type = 0;
|
||||
|
||||
darray_for_each(a_sorted, i) {
|
||||
struct bkey_i_accounting *a = *i;
|
||||
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, a->k.p);
|
||||
|
||||
bool new_type = acc_k.type != prev_type;
|
||||
prev_type = acc_k.type;
|
||||
|
||||
switch (acc_k.type) {
|
||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||
persistent_reserved_to_text(out,
|
||||
acc_k.persistent_reserved.nr_replicas,
|
||||
a->v.d[0]);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_replicas:
|
||||
replicas_usage_to_text(out, &acc_k.replicas, a->v.d[0], &dev_names);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_compression:
|
||||
if (new_type) {
|
||||
prt_printf(out, "\nCompression:\n");
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 12);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 24);
|
||||
prt_printf(out, "type\tcompressed\runcompressed\raverage extent size\r\n");
|
||||
}
|
||||
|
||||
u64 nr_extents = a->v.d[0];
|
||||
u64 sectors_uncompressed = a->v.d[1];
|
||||
u64 sectors_compressed = a->v.d[2];
|
||||
|
||||
bch2_prt_compression_type(out, acc_k.compression.type);
|
||||
prt_tab(out);
|
||||
|
||||
prt_human_readable_u64(out, sectors_compressed << 9);
|
||||
prt_tab_rjust(out);
|
||||
|
||||
prt_human_readable_u64(out, sectors_uncompressed << 9);
|
||||
prt_tab_rjust(out);
|
||||
|
||||
prt_human_readable_u64(out, nr_extents
|
||||
? div_u64(sectors_uncompressed << 9, nr_extents)
|
||||
: 0);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_btree:
|
||||
if (new_type) {
|
||||
prt_printf(out, "\nBtree usage:\n");
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 12);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
}
|
||||
prt_printf(out, "%s:\t", bch2_btree_id_str(acc_k.btree.id));
|
||||
prt_units_u64(out, a->v.d[0] << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_rebalance_work:
|
||||
if (new_type)
|
||||
prt_printf(out, "\nPending rebalance work:\n");
|
||||
prt_units_u64(out, a->v.d[0] << 9);
|
||||
prt_newline(out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
darray_exit(&a_sorted);
|
||||
free(a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fs_usage_v0_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
{
|
||||
struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
|
||||
|
||||
prt_str(out, "Filesystem: ");
|
||||
@ -261,42 +443,43 @@ static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
|
||||
for (i = 0; i < BCH_REPLICAS_MAX; i++) {
|
||||
if (!u->persistent_reserved[i])
|
||||
continue;
|
||||
|
||||
prt_str(out, "reserved:");
|
||||
prt_tab(out);
|
||||
prt_printf(out, "%u/%u ", 1, i);
|
||||
prt_tab(out);
|
||||
prt_str(out, "[] ");
|
||||
prt_units_u64(out, u->persistent_reserved[i] << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
for (unsigned i = 0; i < BCH_REPLICAS_MAX; i++)
|
||||
persistent_reserved_to_text(out, i, u->persistent_reserved[i]);
|
||||
|
||||
struct bch_replicas_usage *r;
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type < BCH_DATA_user)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type == BCH_DATA_user &&
|
||||
r->r.nr_required <= 1)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type == BCH_DATA_user &&
|
||||
r->r.nr_required > 1)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type > BCH_DATA_user)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
{
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
|
||||
dev_names dev_names = bchu_fs_get_devices(fs);
|
||||
|
||||
if (!fs_usage_v1_to_text(out, fs, dev_names))
|
||||
goto devs;
|
||||
|
||||
fs_usage_v0_to_text(out, fs, dev_names);
|
||||
devs:
|
||||
devs_usage_to_text(out, fs, dev_names);
|
||||
|
||||
darray_exit(&dev_names);
|
||||
|
@ -168,6 +168,35 @@ static inline struct bch_ioctl_fs_usage *bchu_fs_usage(struct bchfs_handle fs)
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct bch_ioctl_query_accounting *bchu_fs_accounting(struct bchfs_handle fs,
|
||||
unsigned typemask)
|
||||
{
|
||||
unsigned accounting_u64s = 128;
|
||||
struct bch_ioctl_query_accounting *ret = NULL;
|
||||
|
||||
while (1) {
|
||||
ret = xrealloc(ret, sizeof(*ret) + accounting_u64s * sizeof(u64));
|
||||
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
|
||||
ret->accounting_u64s = accounting_u64s;
|
||||
ret->accounting_types_mask = typemask;
|
||||
|
||||
if (!ioctl(fs.ioctl_fd, BCH_IOCTL_QUERY_ACCOUNTING, ret))
|
||||
return ret;
|
||||
|
||||
if (errno == ENOTTY)
|
||||
return NULL;
|
||||
|
||||
if (errno == ERANGE) {
|
||||
accounting_u64s *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
die("BCH_IOCTL_USAGE error: %m");
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct bch_ioctl_dev_usage_v2 *bchu_dev_usage(struct bchfs_handle fs,
|
||||
unsigned idx)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user