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/bcachefs_ioctl.h"
|
||||||
#include "libbcachefs/buckets.h"
|
#include "libbcachefs/buckets.h"
|
||||||
|
#include "libbcachefs/disk_accounting.h"
|
||||||
#include "libbcachefs/opts.h"
|
#include "libbcachefs/opts.h"
|
||||||
#include "libbcachefs/super-io.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,
|
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)
|
dev_names *dev_names)
|
||||||
{
|
{
|
||||||
if (!r->sectors)
|
if (!sectors)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char devs[4096], *d = devs;
|
char devs[4096], *d = devs;
|
||||||
@ -163,8 +181,8 @@ static void replicas_usage_to_text(struct printbuf *out,
|
|||||||
|
|
||||||
unsigned durability = 0;
|
unsigned durability = 0;
|
||||||
|
|
||||||
for (unsigned i = 0; i < r->r.nr_devs; i++) {
|
for (unsigned i = 0; i < r->nr_devs; i++) {
|
||||||
unsigned dev_idx = r->r.devs[i];
|
unsigned dev_idx = r->devs[i];
|
||||||
struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
|
struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
|
||||||
|
|
||||||
durability += dev->durability;
|
durability += dev->durability;
|
||||||
@ -179,11 +197,11 @@ static void replicas_usage_to_text(struct printbuf *out,
|
|||||||
*d++ = ']';
|
*d++ = ']';
|
||||||
*d++ = '\0';
|
*d++ = '\0';
|
||||||
|
|
||||||
bch2_prt_data_type(out, r->r.data_type);
|
bch2_prt_data_type(out, r->data_type);
|
||||||
prt_char(out, ':');
|
prt_char(out, ':');
|
||||||
prt_tab(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_tab(out);
|
||||||
|
|
||||||
prt_printf(out, "%u ", durability);
|
prt_printf(out, "%u ", durability);
|
||||||
@ -192,7 +210,7 @@ static void replicas_usage_to_text(struct printbuf *out,
|
|||||||
prt_printf(out, "%s ", devs);
|
prt_printf(out, "%s ", devs);
|
||||||
prt_tab(out);
|
prt_tab(out);
|
||||||
|
|
||||||
prt_units_u64(out, r->sectors << 9);
|
prt_units_u64(out, sectors << 9);
|
||||||
prt_tab_rjust(out);
|
prt_tab_rjust(out);
|
||||||
prt_newline(out);
|
prt_newline(out);
|
||||||
}
|
}
|
||||||
@ -203,14 +221,178 @@ static void replicas_usage_to_text(struct printbuf *out,
|
|||||||
_r = replicas_usage_next(_r), \
|
_r = replicas_usage_next(_r), \
|
||||||
BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
|
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);
|
struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
|
||||||
|
|
||||||
prt_str(out, "Filesystem: ");
|
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);
|
printbuf_tabstop_push(out, 14);
|
||||||
|
|
||||||
for (i = 0; i < BCH_REPLICAS_MAX; i++) {
|
for (unsigned i = 0; i < BCH_REPLICAS_MAX; i++)
|
||||||
if (!u->persistent_reserved[i])
|
persistent_reserved_to_text(out, i, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bch_replicas_usage *r;
|
struct bch_replicas_usage *r;
|
||||||
|
|
||||||
for_each_usage_replica(u, r)
|
for_each_usage_replica(u, r)
|
||||||
if (r->r.data_type < BCH_DATA_user)
|
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)
|
for_each_usage_replica(u, r)
|
||||||
if (r->r.data_type == BCH_DATA_user &&
|
if (r->r.data_type == BCH_DATA_user &&
|
||||||
r->r.nr_required <= 1)
|
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)
|
for_each_usage_replica(u, r)
|
||||||
if (r->r.data_type == BCH_DATA_user &&
|
if (r->r.data_type == BCH_DATA_user &&
|
||||||
r->r.nr_required > 1)
|
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)
|
for_each_usage_replica(u, r)
|
||||||
if (r->r.data_type > BCH_DATA_user)
|
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);
|
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);
|
devs_usage_to_text(out, fs, dev_names);
|
||||||
|
|
||||||
darray_exit(&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,
|
static inline struct bch_ioctl_dev_usage_v2 *bchu_dev_usage(struct bchfs_handle fs,
|
||||||
unsigned idx)
|
unsigned idx)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user