btrfs-progs: qgroup show: add json output

Support json for 'qgroup show' with values printed by "btrfs qgroup
-pcre", the accounted size and the limits.  It's implemented as a
separate call and not sharing the printing routines so any visible
changes need to by synchronized.

Formatter updates: don't print key name if .out_json is NULL.

Example output:

 # btrfs --format json qgroup show /mnt/path
{
  "__header": {
    "version": "1"
  },
  "qgroup-show": [
    {
      "qgroupid": "0/5",
      "referenced": "8831393792",
      "max_referenced": "none",
      "exclusive": "8224075776",
      "max_exclusive": "none",
      "path": "",
      "parents": [
      ],
      "children": [
      ]
    },
    {
      "qgroupid": "0/361",
      "referenced": "611459072",
      "max_referenced": "none",
      "exclusive": "65536",
      "max_exclusive": "none",
      "path": "subv1",
      "parents": [
        "1/1"
      ],
      "children": [
      ]
    },
    {
      "qgroupid": "0/362",
      "referenced": "611459072",
      "max_referenced": "none",
      "exclusive": "65536",
      "max_exclusive": "none",
      "path": "snap1-r",
      "parents": [
      ],
      "children": [
      ]
    },
    {
      "qgroupid": "1/1",
      "referenced": "611459072",
      "max_referenced": "none",
      "exclusive": "65536",
      "max_exclusive": "none",
      "path": "",
      "parents": [
      ],
      "children": [
        "0/361"
      ]
    }
  ]
}

Issue: #555
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2022-12-07 18:20:50 +01:00
parent 8cec98cb75
commit 6ecaa3ee4f
2 changed files with 84 additions and 3 deletions

View File

@ -35,6 +35,7 @@
#include "common/help.h"
#include "common/units.h"
#include "common/parse-utils.h"
#include "common/format-output.h"
#include "common/messages.h"
#include "cmds/commands.h"
#include "cmds/qgroup.h"
@ -1433,6 +1434,80 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
}
}
static const struct rowspec qgroup_show_rowspec[] = {
{ .key = "qgroupid", .fmt = "qgroupid", .out_json = "qgroupid" },
{ .key = "referenced", .fmt = "%llu", .out_json = "referenced" },
{ .key = "exclusive", .fmt = "%llu", .out_json = "exclusive" },
{ .key = "max_referenced", .fmt = "size", .out_json = "max_referenced" },
/* Special value if limits not set. */
{ .key = "max_referenced-none", .fmt = "%s", .out_json = "max_referenced" },
{ .key = "max_exclusive", .fmt = "size", .out_json = "max_exclusive" },
/* Special value if limits not set. */
{ .key = "max_exclusive-none", .fmt = "%s", .out_json = "max_exclusive" },
{ .key = "path", .fmt = "%s", .out_json = "path" },
{ .key = "parents", .fmt = "list", .out_json = "parents" },
{ .key = "children", .fmt = "list", .out_json = "children" },
/* Workaround for printing qgroupid in the list as a plain value */
{ .key = "qgroupid-list", .fmt = "qgroupid", .out_json = NULL },
ROWSPEC_END
};
static void print_all_qgroups_json(struct qgroup_lookup *qgroup_lookup)
{
struct rb_node *n;
struct btrfs_qgroup *qgroup;
struct format_ctx fctx;
fmt_start(&fctx, qgroup_show_rowspec, 24, 0);
fmt_print_start_group(&fctx, "qgroup-show", JSON_TYPE_ARRAY);
n = rb_first(&qgroup_lookup->root);
while (n) {
struct btrfs_qgroup_list *list = NULL;
qgroup = rb_entry(n, struct btrfs_qgroup, sort_node);
fmt_print_start_group(&fctx, NULL, JSON_TYPE_MAP);
fmt_print(&fctx, "qgroupid",
btrfs_qgroup_level(qgroup->qgroupid),
btrfs_qgroup_subvolid(qgroup->qgroupid));
fmt_print(&fctx, "referenced", qgroup->info.rfer);
if (qgroup->limit.flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
fmt_print(&fctx, "max_referenced", qgroup->limit.max_rfer);
else
fmt_print(&fctx, "max_referenced-none", "none");
fmt_print(&fctx, "exclusive", qgroup->info.excl);
if (qgroup->limit.flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
fmt_print(&fctx, "max_exclusive", qgroup->limit.max_excl);
else
fmt_print(&fctx, "max_exclusive-none", "none");
fmt_print(&fctx, "path", qgroup->path ?: "");
fmt_print_start_group(&fctx, "parents", JSON_TYPE_ARRAY);
list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
fmt_print(&fctx, "qgroupid-list",
btrfs_qgroup_level(list->qgroup->qgroupid),
btrfs_qgroup_subvolid(list->qgroup->qgroupid));
}
fmt_print_end_group(&fctx, "parents");
fmt_print_start_group(&fctx, "children", JSON_TYPE_ARRAY);
list_for_each_entry(list, &qgroup->members, next_member) {
fmt_print(&fctx, "qgroupid-list",
btrfs_qgroup_level(list->member->qgroupid),
btrfs_qgroup_subvolid(list->member->qgroupid));
}
fmt_print_end_group(&fctx, "children");
fmt_print_end_group(&fctx, NULL);
n = rb_next(n);
}
fmt_print_end_group(&fctx, "qgroup-show");
fmt_end(&fctx);
}
static int show_qgroups(int fd,
struct btrfs_qgroup_filter_set *filter_set,
struct btrfs_qgroup_comparer_set *comp_set)
@ -1447,7 +1522,10 @@ static int show_qgroups(int fd,
return ret;
__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
filter_set, comp_set);
print_all_qgroups(&sort_tree);
if (bconf.output_format == CMD_FORMAT_JSON)
print_all_qgroups_json(&sort_tree);
else
print_all_qgroups(&sort_tree);
__free_all_qgroups(&qgroup_lookup);
return ret;
@ -1855,6 +1933,8 @@ static const char * const cmd_qgroup_show_usage[] = {
" you can use '+' or '-' in front of each item.",
" (+:ascending, -:descending, ascending default)",
"--sync force sync of the filesystem before getting info",
HELPINFO_INSERT_GLOBALS,
HELPINFO_INSERT_FORMAT,
NULL
};
@ -1974,7 +2054,7 @@ static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
out:
return !!ret;
}
static DEFINE_SIMPLE_COMMAND(qgroup_show, "show");
static DEFINE_COMMAND_WITH_FLAGS(qgroup_show, "show", CMD_FORMAT_JSON);
static const char * const cmd_qgroup_limit_usage[] = {
"btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",

View File

@ -272,7 +272,8 @@ void fmt_print(struct format_ctx *fctx, const char* key, ...)
} else {
/* Simple key/values */
fmt_separator(fctx);
printf("\"%s\": ", row->out_json);
if (row->out_json)
printf("\"%s\": ", row->out_json);
}
}