summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2024-06-03 19:33:03 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2024-06-03 20:08:06 -0400
commit0916d3866454cc6f67cf4ea52cb79e9455138f7a (patch)
tree408caf3571a44a22b07ba5575d3d0dc9116ea38d
parentda5435b0ccdc9ac5c1933f3a36e7556e77c0bf1a (diff)
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>
-rw-r--r--c_src/cmd_fs.c239
-rw-r--r--c_src/libbcachefs.h29
2 files changed, 240 insertions, 28 deletions
diff --git a/c_src/cmd_fs.c b/c_src/cmd_fs.c
index dba0dd2e..b792cb85 100644
--- a/c_src/cmd_fs.c
+++ b/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);
diff --git a/c_src/libbcachefs.h b/c_src/libbcachefs.h
index 05720573..5c7ef6c7 100644
--- a/c_src/libbcachefs.h
+++ b/c_src/libbcachefs.h
@@ -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)
{