All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/18] btrfs-progs: qgroups-usability
@ 2018-05-16 21:38 jeffm
  2018-05-16 21:38 ` [PATCH 01/18] btrfs-progs: quota: Add -W option to rescan to wait without starting rescan jeffm
                   ` (17 more replies)
  0 siblings, 18 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

Changes since v2:
- Updated Reviewed-by tags were provided.
- Fixed the typoed commands that I commented on in the previous posting.
- Dropped the btrfs_cleanup_root_info since it's unnecessary with the
  switch to libbtrfsutil.
- Updated the qgroups pathname patch to use libbtrfsutil
- Added a mini-filter to skip dead qgroups in 'qgroup show' output
  unless -v is specified.

The most notable change is that this posting doesn't include the JSON
format patches since there was still some open discussion there.  The
plumbing for passing global options around to commands is there, so we
really just need to decide on how we want to handle alternative formats.
For some commands, the formatting library that coreutils uses will
probably work but for qgroups show to represent nested groups, it's
unsuitable.

I've also posted this as a pull request to the devel branch:

https://github.com/kdave/btrfs-progs/pull/139

Jeff Mahoney (18):
  btrfs-progs: quota: Add -W option to rescan to wait without starting
    rescan
  btrfs-progs: qgroups: fix misleading index check
  btrfs-progs: constify pathnames passed as arguments
  btrfs-progs: btrfs-list: add rb_entry helpers for root_info
  btrfs-progs: qgroups: add pathname to show output
  btrfs-progs: qgroups: introduce and use info and limit structures
  btrfs-progs: qgroups: introduce btrfs_qgroup_query
  btrfs-progs: subvolume: add quota info to btrfs sub show
  btrfs-progs: help: convert ints used as bools to bool
  btrfs-progs: reorder placement of help declarations for send/receive
  btrfs-progs: filesystem balance: split out special handling
  btrfs-progs: use cmd_struct as command entry point
  btrfs-progs: pass cmd_struct to command callback function
  btrfs-progs: pass cmd_struct to clean_args_no_options{,_relaxed}
  btrfs-progs: pass cmd_struct to usage()
  btrfs-progs: add support for output formats
  btrfs-progs: handle command groups directly for common case
  btrfs-progs: qgroups: don't print dead qgroups

 Documentation/btrfs-qgroup.asciidoc |   4 +
 Documentation/btrfs-quota.asciidoc  |  10 +-
 btrfs-list.c                        |  30 ++-
 btrfs.c                             | 174 +++++++++++-----
 check/main.c                        |  10 +-
 chunk-recover.c                     |   4 +-
 cmds-balance.c                      |  74 ++++---
 cmds-device.c                       |  96 +++++----
 cmds-fi-du.c                        |  11 +-
 cmds-fi-usage.c                     |  17 +-
 cmds-filesystem.c                   | 113 +++++++----
 cmds-inspect-dump-super.c           |  11 +-
 cmds-inspect-dump-tree.c            |  11 +-
 cmds-inspect-tree-stats.c           |  11 +-
 cmds-inspect.c                      |  78 ++++----
 cmds-property.c                     |  55 +++---
 cmds-qgroup.c                       | 107 ++++++----
 cmds-quota.c                        |  63 +++---
 cmds-receive.c                      |  70 +++----
 cmds-replace.c                      |  45 +++--
 cmds-rescue.c                       |  60 +++---
 cmds-restore.c                      |  12 +-
 cmds-scrub.c                        |  64 +++---
 cmds-send.c                         |  74 +++----
 cmds-subvolume.c                    | 163 ++++++++++-----
 commands.h                          | 152 ++++++++------
 help.c                              |  98 ++++++---
 help.h                              |  14 +-
 kerncompat.h                        |   1 +
 qgroup.c                            | 384 +++++++++++++++++++++++++++---------
 qgroup.h                            |  19 +-
 31 files changed, 1325 insertions(+), 710 deletions(-)

-- 
2.15.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/18] btrfs-progs: quota: Add -W option to rescan to wait without starting rescan
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 02/18] btrfs-progs: qgroups: fix misleading index check jeffm
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

This patch adds a new -W option to wait for a rescan without starting a
new operation.  This is useful for things like xfstests where we want
do to do a "btrfs quota enable" and not continue until the subsequent
rescan has finished.

In addition to documenting the new option in the man page, I've cleaned
up the rescan entry to document the -w option a bit better.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 Documentation/btrfs-quota.asciidoc | 10 +++++++---
 cmds-quota.c                       | 20 ++++++++++++++------
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/Documentation/btrfs-quota.asciidoc b/Documentation/btrfs-quota.asciidoc
index 85ebf729..0b64a69b 100644
--- a/Documentation/btrfs-quota.asciidoc
+++ b/Documentation/btrfs-quota.asciidoc
@@ -238,15 +238,19 @@ Disable subvolume quota support for a filesystem.
 *enable* <path>::
 Enable subvolume quota support for a filesystem.
 
-*rescan* [-s] <path>::
+*rescan* [-s|-w|-W] <path>::
 Trash all qgroup numbers and scan the metadata again with the current config.
 +
 `Options`
 +
 -s::::
-show status of a running rescan operation.
+Show status of a running rescan operation.
+
 -w::::
-wait for rescan operation to finish(can be already in progress).
+Start rescan operation and wait until it has finished before exiting.  If a rescan is already running, wait until it finishes and then exit without starting a new one.
+
+-W::::
+Wait for rescan operation to finish and then exit.  If a rescan is not already running, exit silently.
 
 EXIT STATUS
 -----------
diff --git a/cmds-quota.c b/cmds-quota.c
index 745889d1..7f933495 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -120,14 +120,20 @@ static int cmd_quota_rescan(int argc, char **argv)
 	int wait_for_completion = 0;
 
 	while (1) {
-		int c = getopt(argc, argv, "sw");
+		int c = getopt(argc, argv, "swW");
 		if (c < 0)
 			break;
 		switch (c) {
 		case 's':
 			ioctlnum = BTRFS_IOC_QUOTA_RESCAN_STATUS;
 			break;
+		case 'W':
+			ioctlnum = 0;
+			wait_for_completion = 1;
+			break;
 		case 'w':
+			/* Reset it in case the user did both -W and -w */
+			ioctlnum = BTRFS_IOC_QUOTA_RESCAN;
 			wait_for_completion = 1;
 			break;
 		default:
@@ -135,8 +141,8 @@ static int cmd_quota_rescan(int argc, char **argv)
 		}
 	}
 
-	if (ioctlnum != BTRFS_IOC_QUOTA_RESCAN && wait_for_completion) {
-		error("switch -w cannot be used with -s");
+	if (ioctlnum == BTRFS_IOC_QUOTA_RESCAN_STATUS && wait_for_completion) {
+		error("switches -w/-W cannot be used with -s");
 		return 1;
 	}
 
@@ -150,8 +156,10 @@ static int cmd_quota_rescan(int argc, char **argv)
 	if (fd < 0)
 		return 1;
 
-	ret = ioctl(fd, ioctlnum, &args);
-	e = errno;
+	if (ioctlnum) {
+		ret = ioctl(fd, ioctlnum, &args);
+		e = errno;
+	}
 
 	if (ioctlnum == BTRFS_IOC_QUOTA_RESCAN_STATUS) {
 		close_file_or_dir(fd, dirstream);
@@ -167,7 +175,7 @@ static int cmd_quota_rescan(int argc, char **argv)
 		return 0;
 	}
 
-	if (ret == 0) {
+	if (ioctlnum == BTRFS_IOC_QUOTA_RESCAN && ret == 0) {
 		printf("quota rescan started\n");
 		fflush(stdout);
 	} else if (ret < 0 && (!wait_for_completion || e != EINPROGRESS)) {
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/18] btrfs-progs: qgroups: fix misleading index check
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
  2018-05-16 21:38 ` [PATCH 01/18] btrfs-progs: quota: Add -W option to rescan to wait without starting rescan jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 03/18] btrfs-progs: constify pathnames passed as arguments jeffm
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

In print_single_qgroup_table we check the loop index against
BTRFS_QGROUP_CHILD, but what we really mean is "last column."  Since
we have an enum value to indicate the last value, use that instead
of assuming that BTRFS_QGROUP_CHILD is always last.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 qgroup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qgroup.c b/qgroup.c
index 267cd7f1..3269feb2 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -267,7 +267,7 @@ static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
 			continue;
 		print_qgroup_column(qgroup, i);
 
-		if (i != BTRFS_QGROUP_CHILD)
+		if (i != BTRFS_QGROUP_ALL - 1)
 			printf(" ");
 	}
 	printf("\n");
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/18] btrfs-progs: constify pathnames passed as arguments
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
  2018-05-16 21:38 ` [PATCH 01/18] btrfs-progs: quota: Add -W option to rescan to wait without starting rescan jeffm
  2018-05-16 21:38 ` [PATCH 02/18] btrfs-progs: qgroups: fix misleading index check jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 04/18] btrfs-progs: btrfs-list: add rb_entry helpers for root_info jeffm
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

It's unlikely we're going to modify a pathname argument, so codify that
and use const.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 chunk-recover.c | 4 ++--
 cmds-device.c   | 2 +-
 cmds-fi-usage.c | 6 +++---
 cmds-rescue.c   | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/chunk-recover.c b/chunk-recover.c
index 705bcf52..1d30db51 100644
--- a/chunk-recover.c
+++ b/chunk-recover.c
@@ -1492,7 +1492,7 @@ out:
 	return ERR_PTR(ret);
 }
 
-static int recover_prepare(struct recover_control *rc, char *path)
+static int recover_prepare(struct recover_control *rc, const char *path)
 {
 	int ret;
 	int fd;
@@ -2296,7 +2296,7 @@ static void validate_rebuild_chunks(struct recover_control *rc)
 /*
  * Return 0 when successful, < 0 on error and > 0 if aborted by user
  */
-int btrfs_recover_chunk_tree(char *path, int verbose, int yes)
+int btrfs_recover_chunk_tree(const char *path, int verbose, int yes)
 {
 	int ret = 0;
 	struct btrfs_root *root = NULL;
diff --git a/cmds-device.c b/cmds-device.c
index 86459d1b..a49c9d9d 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -526,7 +526,7 @@ static const char * const cmd_device_usage_usage[] = {
 	NULL
 };
 
-static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
+static int _cmd_device_usage(int fd, const char *path, unsigned unit_mode)
 {
 	int i;
 	int ret = 0;
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index b9a2b1c8..d08ec4d3 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -227,7 +227,7 @@ static int cmp_btrfs_ioctl_space_info(const void *a, const void *b)
 /*
  * This function load all the information about the space usage
  */
-static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path)
+static struct btrfs_ioctl_space_args *load_space_info(int fd, const char *path)
 {
 	struct btrfs_ioctl_space_args *sargs = NULL, *sargs_orig = NULL;
 	int ret, count;
@@ -305,7 +305,7 @@ static void get_raid56_used(struct chunk_info *chunks, int chunkcount,
 #define	MIN_UNALOCATED_THRESH	SZ_16M
 static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
 		int chunkcount, struct device_info *devinfo, int devcount,
-		char *path, unsigned unit_mode)
+		const char *path, unsigned unit_mode)
 {
 	struct btrfs_ioctl_space_args *sargs = NULL;
 	int i;
@@ -933,7 +933,7 @@ static void _cmd_filesystem_usage_linear(unsigned unit_mode,
 static int print_filesystem_usage_by_chunk(int fd,
 		struct chunk_info *chunkinfo, int chunkcount,
 		struct device_info *devinfo, int devcount,
-		char *path, unsigned unit_mode, int tabular)
+		const char *path, unsigned unit_mode, int tabular)
 {
 	struct btrfs_ioctl_space_args *sargs;
 	int ret = 0;
diff --git a/cmds-rescue.c b/cmds-rescue.c
index c40088ad..c61145bc 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -32,8 +32,8 @@ static const char * const rescue_cmd_group_usage[] = {
 	NULL
 };
 
-int btrfs_recover_chunk_tree(char *path, int verbose, int yes);
-int btrfs_recover_superblocks(char *path, int verbose, int yes);
+int btrfs_recover_chunk_tree(const char *path, int verbose, int yes);
+int btrfs_recover_superblocks(const char *path, int verbose, int yes);
 
 static const char * const cmd_rescue_chunk_recover_usage[] = {
 	"btrfs rescue chunk-recover [options] <device>",
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/18] btrfs-progs: btrfs-list: add rb_entry helpers for root_info
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (2 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 03/18] btrfs-progs: constify pathnames passed as arguments jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output jeffm
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

We use rb_entry all over the place for the root_info pointers.  Add
a helper to make the code more readable.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs-list.c | 30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index e01c5899..90c98be1 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -44,6 +44,16 @@ struct root_lookup {
 	struct rb_root root;
 };
 
+static inline struct root_info *to_root_info(struct rb_node *node)
+{
+	return rb_entry(node, struct root_info, rb_node);
+}
+
+static inline struct root_info *to_root_info_sorted(struct rb_node *node)
+{
+	return rb_entry(node, struct root_info, sort_node);
+}
+
 static struct {
 	char	*name;
 	char	*column_name;
@@ -309,7 +319,7 @@ static int sort_tree_insert(struct root_lookup *sort_tree,
 
 	while (*p) {
 		parent = *p;
-		curr = rb_entry(parent, struct root_info, sort_node);
+		curr = to_root_info_sorted(parent);
 
 		ret = sort_comp(ins, curr, comp_set);
 		if (ret < 0)
@@ -340,7 +350,7 @@ static int root_tree_insert(struct root_lookup *root_tree,
 
 	while(*p) {
 		parent = *p;
-		curr = rb_entry(parent, struct root_info, rb_node);
+		curr = to_root_info(parent);
 
 		ret = comp_entry_with_rootid(ins, curr, 0);
 		if (ret < 0)
@@ -371,7 +381,7 @@ static struct root_info *root_tree_search(struct root_lookup *root_tree,
 	tmp.root_id = root_id;
 
 	while(n) {
-		entry = rb_entry(n, struct root_info, rb_node);
+		entry = to_root_info(n);
 
 		ret = comp_entry_with_rootid(&tmp, entry, 0);
 		if (ret < 0)
@@ -528,7 +538,7 @@ static void free_root_info(struct rb_node *node)
 {
 	struct root_info *ri;
 
-	ri = rb_entry(node, struct root_info, rb_node);
+	ri = to_root_info(node);
 	free(ri->name);
 	free(ri->path);
 	free(ri->full_path);
@@ -1268,7 +1278,7 @@ static void filter_and_sort_subvol(struct root_lookup *all_subvols,
 
 	n = rb_last(&all_subvols->root);
 	while (n) {
-		entry = rb_entry(n, struct root_info, rb_node);
+		entry = to_root_info(n);
 
 		ret = resolve_root(all_subvols, entry, top_id);
 		if (ret == -ENOENT) {
@@ -1300,7 +1310,7 @@ static int list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
 	while (n) {
 		struct root_info *entry;
 		int ret;
-		entry = rb_entry(n, struct root_info, rb_node);
+		entry = to_root_info(n);
 		ret = lookup_ino_path(fd, entry);
 		if (ret && ret != -ENOENT)
 			return ret;
@@ -1467,7 +1477,7 @@ static void print_all_subvol_info(struct root_lookup *sorted_tree,
 
 	n = rb_first(&sorted_tree->root);
 	while (n) {
-		entry = rb_entry(n, struct root_info, sort_node);
+		entry = to_root_info_sorted(n);
 
 		/* The toplevel subvolume is not listed by default */
 		if (entry->root_id == BTRFS_FS_TREE_OBJECTID)
@@ -1558,7 +1568,7 @@ int btrfs_get_toplevel_subvol(int fd, struct root_info *the_ri)
 		return ret;
 
 	rbn = rb_first(&rl.root);
-	ri = rb_entry(rbn, struct root_info, rb_node);
+	ri = to_root_info(rbn);
 
 	if (ri->root_id != BTRFS_FS_TREE_OBJECTID)
 		return -ENOENT;
@@ -1590,7 +1600,7 @@ int btrfs_get_subvol(int fd, struct root_info *the_ri)
 
 	rbn = rb_first(&rl.root);
 	while(rbn) {
-		ri = rb_entry(rbn, struct root_info, rb_node);
+		ri = to_root_info(rbn);
 		rr = resolve_root(&rl, ri, root_id);
 		if (rr == -ENOENT) {
 			ret = -ENOENT;
@@ -1814,7 +1824,7 @@ char *btrfs_list_path_for_root(int fd, u64 root)
 	while (n) {
 		struct root_info *entry;
 
-		entry = rb_entry(n, struct root_info, rb_node);
+		entry = to_root_info(n);
 		ret = resolve_root(&root_lookup, entry, top_id);
 		if (ret == -ENOENT && entry->root_id == root) {
 			ret_path = NULL;
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (3 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 04/18] btrfs-progs: btrfs-list: add rb_entry helpers for root_info jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-18  4:55   ` Misono Tomohiro
  2018-05-16 21:38 ` [PATCH 06/18] btrfs-progs: qgroups: introduce and use info and limit structures jeffm
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

The btrfs qgroup show command currently only exports qgroup IDs,
forcing the user to resolve which subvolume each corresponds to.

This patch adds pathname resolution to qgroup show so that when
the -P option is used, the last column contains the pathname of
the root of the subvolume it describes.  In the case of nested
qgroups, it will show the number of member qgroups or the paths
of the members if the -v option is used.

Pathname can also be used as a sort parameter.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 Documentation/btrfs-qgroup.asciidoc |   4 +
 cmds-qgroup.c                       |  18 ++++-
 kerncompat.h                        |   1 +
 qgroup.c                            | 149 ++++++++++++++++++++++++++++++++----
 qgroup.h                            |   4 +-
 5 files changed, 157 insertions(+), 19 deletions(-)

diff --git a/Documentation/btrfs-qgroup.asciidoc b/Documentation/btrfs-qgroup.asciidoc
index 3108457c..360b3269 100644
--- a/Documentation/btrfs-qgroup.asciidoc
+++ b/Documentation/btrfs-qgroup.asciidoc
@@ -97,10 +97,14 @@ print child qgroup id.
 print limit of referenced size of qgroup.
 -e::::
 print limit of exclusive size of qgroup.
+-P::::
+print pathname to the root of the subvolume managed by qgroup.  For nested qgroups, the number of members will be printed unless -v is specified.
 -F::::
 list all qgroups which impact the given path(include ancestral qgroups)
 -f::::
 list all qgroups which impact the given path(exclude ancestral qgroups)
+-v::::
+Be more verbose.  Print pathnames of member qgroups when nested.
 --raw::::
 raw numbers in bytes, without the 'B' suffix.
 --human-readable::::
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 93206900..33053725 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -282,8 +282,11 @@ static const char * const cmd_qgroup_show_usage[] = {
 	"               (including ancestral qgroups)",
 	"-f             list all qgroups which impact the given path",
 	"               (excluding ancestral qgroups)",
+	"-P             print first-level qgroups using pathname",
+	"               - nested qgroups will be reported as a count",
+	"-v             verbose, prints pathnames for all nested qgroups",
 	HELPINFO_UNITS_LONG,
-	"--sort=qgroupid,rfer,excl,max_rfer,max_excl",
+	"--sort=qgroupid,rfer,excl,max_rfer,max_excl,pathname",
 	"               list qgroups sorted by specified items",
 	"               you can use '+' or '-' in front of each item.",
 	"               (+:ascending, -:descending, ascending default)",
@@ -302,6 +305,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 	unsigned unit_mode;
 	int sync = 0;
 	enum btrfs_util_error err;
+	bool verbose = false;
 
 	struct btrfs_qgroup_comparer_set *comparer_set;
 	struct btrfs_qgroup_filter_set *filter_set;
@@ -319,10 +323,11 @@ static int cmd_qgroup_show(int argc, char **argv)
 		static const struct option long_options[] = {
 			{"sort", required_argument, NULL, GETOPT_VAL_SORT},
 			{"sync", no_argument, NULL, GETOPT_VAL_SYNC},
+			{"verbose", no_argument, NULL, 'v'},
 			{ NULL, 0, NULL, 0 }
 		};
 
-		c = getopt_long(argc, argv, "pcreFf", long_options, NULL);
+		c = getopt_long(argc, argv, "pPcreFfv", long_options, NULL);
 		if (c < 0)
 			break;
 		switch (c) {
@@ -330,6 +335,10 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_PARENT);
 			break;
+		case 'P':
+			btrfs_qgroup_setup_print_column(
+				BTRFS_QGROUP_PATHNAME);
+			break;
 		case 'c':
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_CHILD);
@@ -357,6 +366,9 @@ static int cmd_qgroup_show(int argc, char **argv)
 		case GETOPT_VAL_SYNC:
 			sync = 1;
 			break;
+		case 'v':
+			verbose = true;
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
@@ -398,7 +410,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 					BTRFS_QGROUP_FILTER_PARENT,
 					qgroupid);
 	}
-	ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
+	ret = btrfs_show_qgroups(fd, filter_set, comparer_set, verbose);
 	close_file_or_dir(fd, dirstream);
 	free(filter_set);
 	free(comparer_set);
diff --git a/kerncompat.h b/kerncompat.h
index fa96715f..f97495ee 100644
--- a/kerncompat.h
+++ b/kerncompat.h
@@ -29,6 +29,7 @@
 #include <stddef.h>
 #include <linux/types.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #include <features.h>
 
diff --git a/qgroup.c b/qgroup.c
index 3269feb2..d8baca33 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -21,6 +21,7 @@
 #include "ctree.h"
 #include "ioctl.h"
 #include "utils.h"
+#include "btrfsutil.h"
 #include <errno.h>
 
 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
@@ -40,6 +41,9 @@ struct btrfs_qgroup {
 	struct rb_node all_parent_node;
 	u64 qgroupid;
 
+	/* NULL for qgroups with level > 0 */
+	const char *pathname;
+
 	/*
 	 * info_item
 	 */
@@ -133,6 +137,13 @@ static struct {
 		.unit_mode	= 0,
 		.max_len	= 5,
 	},
+	{
+		.name		= "pathname",
+		.column_name	= "pathname",
+		.need_print	= 0,
+		.unit_mode	= 0,
+		.max_len	= 10,
+	},
 	{
 		.name		= NULL,
 		.column_name	= NULL,
@@ -210,8 +221,50 @@ static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
 		printf(" ");
 }
 
+void print_pathname_column(struct btrfs_qgroup *qgroup, bool verbose)
+{
+	struct btrfs_qgroup_list *list = NULL;
+
+	fputs("  ", stdout);
+	if (btrfs_qgroup_level(qgroup->qgroupid) > 0) {
+		int count = 0;
+
+		list_for_each_entry(list, &qgroup->qgroups,
+				    next_qgroup) {
+			if (verbose) {
+				struct btrfs_qgroup *member = list->qgroup;
+				u64 qgroupid = member->qgroupid;
+				u64 level = btrfs_qgroup_level(qgroupid);
+				u64 sid = btrfs_qgroup_subvid(qgroupid);
+
+				if (count)
+					fputs(" ", stdout);
+				if (level == 0) {
+					const char *path = member->pathname;
+
+					if (!path)
+						path = "<missing>";
+					fputs(path, stdout);
+				} else
+					printf("%llu/%llu", level, sid);
+			}
+			count++;
+		}
+		if (!count)
+			fputs("<empty>", stdout);
+		else if (!verbose)
+			printf("<%u member qgroup%c>", count,
+			       count != 1 ? 's' : '\0');
+	} else if (qgroup->pathname)
+		printf("<FS_ROOT>%s%s", *qgroup->pathname ? "/" : "",
+		       qgroup->pathname);
+	else
+		fputs("<missing>", stdout);
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
-				enum btrfs_qgroup_column_enum column)
+				enum btrfs_qgroup_column_enum column,
+				bool verbose)
 {
 	int len;
 	int unit_mode = btrfs_qgroup_columns[column].unit_mode;
@@ -253,19 +306,22 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 		len = print_child_column(qgroup);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
 		break;
+	case BTRFS_QGROUP_PATHNAME:
+		print_pathname_column(qgroup, verbose);
+		break;
 	default:
 		break;
 	}
 }
 
-static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
+static void print_single_qgroup_table(struct btrfs_qgroup *qgroup, bool verbose)
 {
 	int i;
 
 	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
 		if (!btrfs_qgroup_columns[i].need_print)
 			continue;
-		print_qgroup_column(qgroup, i);
+		print_qgroup_column(qgroup, i, verbose);
 
 		if (i != BTRFS_QGROUP_ALL - 1)
 			printf(" ");
@@ -338,6 +394,47 @@ static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
 	return is_descending ? -ret : ret;
 }
 
+/* Sorts first-level qgroups by pathname and nested qgroups by qgroupid */
+static int comp_entry_with_pathname(struct btrfs_qgroup *entry1,
+				    struct btrfs_qgroup *entry2,
+				    int is_descending)
+{
+	int ret = 0;
+	const char *p1 = entry1->pathname;
+	const char *p2 = entry2->pathname;
+
+	u64 level1 = btrfs_qgroup_level(entry1->qgroupid);
+	u64 level2 = btrfs_qgroup_level(entry2->qgroupid);
+
+	if (level1 != level2) {
+		if (entry1->qgroupid > entry2->qgroupid)
+			ret = 1;
+		else if (entry1->qgroupid < entry2->qgroupid)
+			ret = -1;
+	}
+
+	if (ret)
+		goto out;
+
+	while (*p1 && *p2) {
+		if (*p1 != *p2)
+			break;
+		p1++;
+		p2++;
+	}
+
+	if (*p1 == '/')
+		ret = 1;
+	else if (*p2 == '/')
+		ret = -1;
+	else if (*p1 > *p2)
+		ret = 1;
+	else if (*p1 < *p2)
+		ret = -1;
+out:
+	return is_descending ? -ret : ret;
+}
+
 static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
 				struct btrfs_qgroup *entry2,
 				int is_descending)
@@ -404,6 +501,7 @@ static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
 
 static btrfs_qgroup_comp_func all_comp_funcs[] = {
 	[BTRFS_QGROUP_COMP_QGROUPID]	= comp_entry_with_qgroupid,
+	[BTRFS_QGROUP_COMP_PATHNAME]	= comp_entry_with_pathname,
 	[BTRFS_QGROUP_COMP_RFER]	= comp_entry_with_rfer,
 	[BTRFS_QGROUP_COMP_EXCL]	= comp_entry_with_excl,
 	[BTRFS_QGROUP_COMP_MAX_RFER]	= comp_entry_with_max_rfer,
@@ -412,6 +510,7 @@ static btrfs_qgroup_comp_func all_comp_funcs[] = {
 
 static char *all_sort_items[] = {
 	[BTRFS_QGROUP_COMP_QGROUPID]	= "qgroupid",
+	[BTRFS_QGROUP_COMP_PATHNAME]	= "pathname",
 	[BTRFS_QGROUP_COMP_RFER]	= "rfer",
 	[BTRFS_QGROUP_COMP_EXCL]	= "excl",
 	[BTRFS_QGROUP_COMP_MAX_RFER]	= "max_rfer",
@@ -588,7 +687,7 @@ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
  * Return the pointer to the btrfs_qgroup if found or if inserted successfully.
  * Return ERR_PTR if any error occurred.
  */
-static struct btrfs_qgroup *get_or_add_qgroup(
+static struct btrfs_qgroup *get_or_add_qgroup(int fd,
 		struct qgroup_lookup *qgroup_lookup, u64 qgroupid)
 {
 	struct btrfs_qgroup *bq;
@@ -608,6 +707,23 @@ static struct btrfs_qgroup *get_or_add_qgroup(
 	INIT_LIST_HEAD(&bq->qgroups);
 	INIT_LIST_HEAD(&bq->members);
 
+	if (btrfs_qgroup_level(qgroupid) == 0) {
+		enum btrfs_util_error uret;
+		char *pathname;
+
+		uret = btrfs_util_subvolume_path_fd(fd, qgroupid, &pathname);
+		if (uret == BTRFS_UTIL_OK)
+			bq->pathname = pathname;
+		/* Ignore stale qgroup items */
+		else if (uret != BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) {
+			error("%s", btrfs_util_strerror(uret));
+			if (uret == BTRFS_UTIL_ERROR_NO_MEMORY)
+				return ERR_PTR(-ENOMEM);
+			else
+				return ERR_PTR(-EIO);
+		}
+	}
+
 	ret = qgroup_tree_insert(qgroup_lookup, bq);
 	if (ret) {
 		error("failed to insert %llu into tree: %s",
@@ -619,12 +735,12 @@ static struct btrfs_qgroup *get_or_add_qgroup(
 	return bq;
 }
 
-static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
-			      struct btrfs_qgroup_info_item *info)
+static int update_qgroup_info(int fd, struct qgroup_lookup *qgroup_lookup,
+			      u64 qgroupid, struct btrfs_qgroup_info_item *info)
 {
 	struct btrfs_qgroup *bq;
 
-	bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
+	bq = get_or_add_qgroup(fd, qgroup_lookup, qgroupid);
 	if (IS_ERR_OR_NULL(bq))
 		return PTR_ERR(bq);
 
@@ -637,13 +753,13 @@ static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
 	return 0;
 }
 
-static int update_qgroup_limit(struct qgroup_lookup *qgroup_lookup,
+static int update_qgroup_limit(int fd, struct qgroup_lookup *qgroup_lookup,
 			       u64 qgroupid,
 			       struct btrfs_qgroup_limit_item *limit)
 {
 	struct btrfs_qgroup *bq;
 
-	bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
+	bq = get_or_add_qgroup(fd, qgroup_lookup, qgroupid);
 	if (IS_ERR_OR_NULL(bq))
 		return PTR_ERR(bq);
 
@@ -712,6 +828,8 @@ static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
 		list_del(&list->next_member);
 		free(list);
 	}
+	if (bq->pathname)
+		free((void *)bq->pathname);
 	free(bq);
 }
 
@@ -1107,7 +1225,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 				info = (struct btrfs_qgroup_info_item *)
 				       (args.buf + off);
 
-				ret = update_qgroup_info(qgroup_lookup,
+				ret = update_qgroup_info(fd, qgroup_lookup,
 							 qgroupid, info);
 				break;
 			case BTRFS_QGROUP_LIMIT_KEY:
@@ -1115,7 +1233,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 				limit = (struct btrfs_qgroup_limit_item *)
 					(args.buf + off);
 
-				ret = update_qgroup_limit(qgroup_lookup,
+				ret = update_qgroup_limit(fd, qgroup_lookup,
 							  qgroupid, limit);
 				break;
 			case BTRFS_QGROUP_RELATION_KEY:
@@ -1159,7 +1277,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 	return ret;
 }
 
-static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
+static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, bool verbose)
 {
 
 	struct rb_node *n;
@@ -1170,14 +1288,15 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
 	n = rb_first(&qgroup_lookup->root);
 	while (n) {
 		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
-		print_single_qgroup_table(entry);
+		print_single_qgroup_table(entry, verbose);
 		n = rb_next(n);
 	}
 }
 
 int btrfs_show_qgroups(int fd,
 		       struct btrfs_qgroup_filter_set *filter_set,
-		       struct btrfs_qgroup_comparer_set *comp_set)
+		       struct btrfs_qgroup_comparer_set *comp_set,
+		       bool verbose)
 {
 
 	struct qgroup_lookup qgroup_lookup;
@@ -1189,7 +1308,7 @@ int btrfs_show_qgroups(int fd,
 		return ret;
 	__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
 				  filter_set, comp_set);
-	print_all_qgroups(&sort_tree);
+	print_all_qgroups(&sort_tree, verbose);
 
 	__free_all_qgroups(&qgroup_lookup);
 	return ret;
diff --git a/qgroup.h b/qgroup.h
index 875fbdf3..f7ab7de5 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -59,11 +59,13 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_MAX_EXCL,
 	BTRFS_QGROUP_PARENT,
 	BTRFS_QGROUP_CHILD,
+	BTRFS_QGROUP_PATHNAME,
 	BTRFS_QGROUP_ALL,
 };
 
 enum btrfs_qgroup_comp_enum {
 	BTRFS_QGROUP_COMP_QGROUPID,
+	BTRFS_QGROUP_COMP_PATHNAME,
 	BTRFS_QGROUP_COMP_RFER,
 	BTRFS_QGROUP_COMP_EXCL,
 	BTRFS_QGROUP_COMP_MAX_RFER,
@@ -80,7 +82,7 @@ enum btrfs_qgroup_filter_enum {
 int btrfs_qgroup_parse_sort_string(const char *opt_arg,
 				struct btrfs_qgroup_comparer_set **comps);
 int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
-		       struct btrfs_qgroup_comparer_set *);
+		       struct btrfs_qgroup_comparer_set *, bool verbose);
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
 void btrfs_qgroup_setup_units(unsigned unit_mode);
 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/18] btrfs-progs: qgroups: introduce and use info and limit structures
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (4 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 07/18] btrfs-progs: qgroups: introduce btrfs_qgroup_query jeffm
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

We use structures to pass the info and limit from the kernel as items
but store the individual values separately in btrfs_qgroup.  We already
have a btrfs_qgroup_limit structure that's used for setting the limit.

This patch introduces a btrfs_qgroup_info structure and uses that and
btrfs_qgroup_limit in btrfs_qgroup.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 qgroup.c | 82 ++++++++++++++++++++++++++++++++++------------------------------
 qgroup.h |  8 +++++++
 2 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/qgroup.c b/qgroup.c
index d8baca33..247f1bfe 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -47,20 +47,12 @@ struct btrfs_qgroup {
 	/*
 	 * info_item
 	 */
-	u64 generation;
-	u64 rfer;	/*referenced*/
-	u64 rfer_cmpr;	/*referenced compressed*/
-	u64 excl;	/*exclusive*/
-	u64 excl_cmpr;	/*exclusive compressed*/
+	struct btrfs_qgroup_info info;
 
 	/*
 	 *limit_item
 	 */
-	u64 flags;	/*which limits are set*/
-	u64 max_rfer;
-	u64 max_excl;
-	u64 rsv_rfer;
-	u64 rsv_excl;
+	struct btrfs_qgroup_limit limit;
 
 	/*qgroups this group is member of*/
 	struct list_head qgroups;
@@ -262,6 +254,11 @@ void print_pathname_column(struct btrfs_qgroup *qgroup, bool verbose)
 		fputs("<missing>", stdout);
 }
 
+static int print_u64(u64 value, int unit_mode, int max_len)
+{
+	return printf("%*s", max_len, pretty_size_mode(value, unit_mode));
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 				enum btrfs_qgroup_column_enum column,
 				bool verbose)
@@ -281,24 +278,26 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 		print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
 		break;
 	case BTRFS_QGROUP_RFER:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
+		len = print_u64(qgroup->info.referenced, unit_mode, max_len);
 		break;
 	case BTRFS_QGROUP_EXCL:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
+		len = print_u64(qgroup->info.exclusive, unit_mode, max_len);
 		break;
 	case BTRFS_QGROUP_PARENT:
 		len = print_parent_column(qgroup);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
-		if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
-			len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
+		if (qgroup->limit.flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
+			len = print_u64(qgroup->limit.max_referenced,
+					unit_mode, max_len);
 		else
 			len = printf("%*s", max_len, "none");
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
-		if (qgroup->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
-			len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
+		if (qgroup->limit.flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
+			len = print_u64(qgroup->limit.max_exclusive,
+					unit_mode, max_len);
 		else
 			len = printf("%*s", max_len, "none");
 		break;
@@ -441,9 +440,9 @@ static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
 {
 	int ret;
 
-	if (entry1->rfer > entry2->rfer)
+	if (entry1->info.referenced > entry2->info.referenced)
 		ret = 1;
-	else if (entry1->rfer < entry2->rfer)
+	else if (entry1->info.referenced < entry2->info.referenced)
 		ret = -1;
 	else
 		ret = 0;
@@ -457,9 +456,9 @@ static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
 {
 	int ret;
 
-	if (entry1->excl > entry2->excl)
+	if (entry1->info.exclusive > entry2->info.exclusive)
 		ret = 1;
-	else if (entry1->excl < entry2->excl)
+	else if (entry1->info.exclusive < entry2->info.exclusive)
 		ret = -1;
 	else
 		ret = 0;
@@ -473,9 +472,9 @@ static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
 {
 	int ret;
 
-	if (entry1->max_rfer > entry2->max_rfer)
+	if (entry1->limit.max_referenced > entry2->limit.max_referenced)
 		ret = 1;
-	else if (entry1->max_rfer < entry2->max_rfer)
+	else if (entry1->limit.max_referenced < entry2->limit.max_referenced)
 		ret = -1;
 	else
 		ret = 0;
@@ -489,9 +488,9 @@ static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
 {
 	int ret;
 
-	if (entry1->max_excl > entry2->max_excl)
+	if (entry1->limit.max_exclusive > entry2->limit.max_exclusive)
 		ret = 1;
-	else if (entry1->max_excl < entry2->max_excl)
+	else if (entry1->limit.max_exclusive < entry2->limit.max_exclusive)
 		ret = -1;
 	else
 		ret = 0;
@@ -744,11 +743,13 @@ static int update_qgroup_info(int fd, struct qgroup_lookup *qgroup_lookup,
 	if (IS_ERR_OR_NULL(bq))
 		return PTR_ERR(bq);
 
-	bq->generation = btrfs_stack_qgroup_info_generation(info);
-	bq->rfer = btrfs_stack_qgroup_info_referenced(info);
-	bq->rfer_cmpr = btrfs_stack_qgroup_info_referenced_compressed(info);
-	bq->excl = btrfs_stack_qgroup_info_exclusive(info);
-	bq->excl_cmpr = btrfs_stack_qgroup_info_exclusive_compressed(info);
+	bq->info.generation = btrfs_stack_qgroup_info_generation(info);
+	bq->info.referenced = btrfs_stack_qgroup_info_referenced(info);
+	bq->info.referenced_compressed =
+			btrfs_stack_qgroup_info_referenced_compressed(info);
+	bq->info.exclusive = btrfs_stack_qgroup_info_exclusive(info);
+	bq->info.exclusive_compressed =
+			btrfs_stack_qgroup_info_exclusive_compressed(info);
 
 	return 0;
 }
@@ -763,11 +764,14 @@ static int update_qgroup_limit(int fd, struct qgroup_lookup *qgroup_lookup,
 	if (IS_ERR_OR_NULL(bq))
 		return PTR_ERR(bq);
 
-	bq->flags = btrfs_stack_qgroup_limit_flags(limit);
-	bq->max_rfer = btrfs_stack_qgroup_limit_max_referenced(limit);
-	bq->max_excl = btrfs_stack_qgroup_limit_max_exclusive(limit);
-	bq->rsv_rfer = btrfs_stack_qgroup_limit_rsv_referenced(limit);
-	bq->rsv_excl = btrfs_stack_qgroup_limit_rsv_exclusive(limit);
+	bq->limit.flags = btrfs_stack_qgroup_limit_flags(limit);
+	bq->limit.max_referenced =
+			btrfs_stack_qgroup_limit_max_referenced(limit);
+	bq->limit.max_exclusive =
+			btrfs_stack_qgroup_limit_max_exclusive(limit);
+	bq->limit.rsv_referenced =
+			btrfs_stack_qgroup_limit_rsv_referenced(limit);
+	bq->limit.rsv_exclusive = btrfs_stack_qgroup_limit_rsv_exclusive(limit);
 
 	return 0;
 }
@@ -1060,22 +1064,24 @@ static void __update_columns_max_len(struct btrfs_qgroup *bq,
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_RFER:
-		len = strlen(pretty_size_mode(bq->rfer, unit_mode));
+		len = strlen(pretty_size_mode(bq->info.referenced, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_EXCL:
-		len = strlen(pretty_size_mode(bq->excl, unit_mode));
+		len = strlen(pretty_size_mode(bq->info.exclusive, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
-		len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
+		len = strlen(pretty_size_mode(bq->limit.max_referenced,
+			     unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
-		len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
+		len = strlen(pretty_size_mode(bq->limit.max_exclusive,
+			     unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
diff --git a/qgroup.h b/qgroup.h
index f7ab7de5..5e71349c 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -79,6 +79,14 @@ enum btrfs_qgroup_filter_enum {
 	BTRFS_QGROUP_FILTER_MAX,
 };
 
+struct btrfs_qgroup_info {
+	u64 generation;
+	u64 referenced;
+	u64 referenced_compressed;
+	u64 exclusive;
+	u64 exclusive_compressed;
+};
+
 int btrfs_qgroup_parse_sort_string(const char *opt_arg,
 				struct btrfs_qgroup_comparer_set **comps);
 int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/18] btrfs-progs: qgroups: introduce btrfs_qgroup_query
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (5 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 06/18] btrfs-progs: qgroups: introduce and use info and limit structures jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 08/18] btrfs-progs: subvolume: add quota info to btrfs sub show jeffm
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

The only mechanism we have in the progs for searching qgroups is to load
all of them and filter the results.  This works for qgroup show but
to add quota information to 'btrfs subvoluem show' it's pretty wasteful.

This patch splits out setting up the search and performing the search so
we can search for a single qgroupid more easily.  Since TREE_SEARCH
will give results that don't strictly match the search terms, we add
a filter to match only the results we care about.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 qgroup.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 qgroup.h |   7 ++++
 2 files changed, 116 insertions(+), 34 deletions(-)

diff --git a/qgroup.c b/qgroup.c
index 247f1bfe..647bc2f3 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -1162,11 +1162,30 @@ static inline void print_status_flag_warning(u64 flags)
 		warning("qgroup data inconsistent, rescan recommended");
 }
 
-static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
+static bool key_in_range(const struct btrfs_key *key,
+			 const struct btrfs_ioctl_search_key *sk)
+{
+	if (key->objectid < sk->min_objectid ||
+	    key->objectid > sk->max_objectid)
+		return false;
+
+	if (key->type < sk->min_type ||
+	    key->type > sk->max_type)
+		return false;
+
+	if (key->offset < sk->min_offset ||
+	    key->offset > sk->max_offset)
+		return false;
+
+	return true;
+}
+
+static int __qgroups_search(int fd, struct btrfs_ioctl_search_args *args,
+			    struct qgroup_lookup *qgroup_lookup)
 {
 	int ret;
-	struct btrfs_ioctl_search_args args;
-	struct btrfs_ioctl_search_key *sk = &args.key;
+	struct btrfs_ioctl_search_key *sk = &args->key;
+	struct btrfs_ioctl_search_key filter_key = args->key;
 	struct btrfs_ioctl_search_header *sh;
 	unsigned long off = 0;
 	unsigned int i;
@@ -1177,30 +1196,15 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 	u64 qgroupid;
 	u64 child, parent;
 
-	memset(&args, 0, sizeof(args));
-
-	sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
-	sk->max_type = BTRFS_QGROUP_RELATION_KEY;
-	sk->min_type = BTRFS_QGROUP_STATUS_KEY;
-	sk->max_objectid = (u64)-1;
-	sk->max_offset = (u64)-1;
-	sk->max_transid = (u64)-1;
-	sk->nr_items = 4096;
-
 	qgroup_lookup_init(qgroup_lookup);
 
 	while (1) {
-		ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+		ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, args);
 		if (ret < 0) {
-			if (errno == ENOENT) {
-				error("can't list qgroups: quotas not enabled");
+			if (errno == ENOENT)
 				ret = -ENOTTY;
-			} else {
-				error("can't list qgroups: %s",
-				       strerror(errno));
+			else
 				ret = -errno;
-			}
-
 			break;
 		}
 
@@ -1214,37 +1218,46 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 		 * read the root_ref item it contains
 		 */
 		for (i = 0; i < sk->nr_items; i++) {
-			sh = (struct btrfs_ioctl_search_header *)(args.buf +
+			struct btrfs_key key;
+
+			sh = (struct btrfs_ioctl_search_header *)(args->buf +
 								  off);
 			off += sizeof(*sh);
 
-			switch (btrfs_search_header_type(sh)) {
+			key.objectid = btrfs_search_header_objectid(sh);
+			key.type = btrfs_search_header_type(sh);
+			key.offset = btrfs_search_header_offset(sh);
+
+			if (!key_in_range(&key, &filter_key))
+				goto next;
+
+			switch (key.type) {
 			case BTRFS_QGROUP_STATUS_KEY:
 				si = (struct btrfs_qgroup_status_item *)
-				     (args.buf + off);
+				     (args->buf + off);
 				flags = btrfs_stack_qgroup_status_flags(si);
 
 				print_status_flag_warning(flags);
 				break;
 			case BTRFS_QGROUP_INFO_KEY:
-				qgroupid = btrfs_search_header_offset(sh);
+				qgroupid = key.offset;
 				info = (struct btrfs_qgroup_info_item *)
-				       (args.buf + off);
+				       (args->buf + off);
 
 				ret = update_qgroup_info(fd, qgroup_lookup,
 							 qgroupid, info);
 				break;
 			case BTRFS_QGROUP_LIMIT_KEY:
-				qgroupid = btrfs_search_header_offset(sh);
+				qgroupid = key.offset;
 				limit = (struct btrfs_qgroup_limit_item *)
-					(args.buf + off);
+					(args->buf + off);
 
 				ret = update_qgroup_limit(fd, qgroup_lookup,
 							  qgroupid, limit);
 				break;
 			case BTRFS_QGROUP_RELATION_KEY:
-				child = btrfs_search_header_offset(sh);
-				parent = btrfs_search_header_objectid(sh);
+				child = key.offset;
+				parent = key.objectid;
 
 				if (parent <= child)
 					break;
@@ -1259,15 +1272,16 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 			if (ret)
 				return ret;
 
+next:
 			off += btrfs_search_header_len(sh);
 
 			/*
 			 * record the mins in sk so we can make sure the
 			 * next search doesn't repeat this root
 			 */
-			sk->min_type = btrfs_search_header_type(sh);
-			sk->min_offset = btrfs_search_header_offset(sh);
-			sk->min_objectid = btrfs_search_header_objectid(sh);
+			sk->min_type = key.type;
+			sk->min_offset = key.offset;
+			sk->min_objectid = key.objectid;
 		}
 		sk->nr_items = 4096;
 		/*
@@ -1283,6 +1297,67 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 	return ret;
 }
 
+static int qgroups_search_all(int fd, struct qgroup_lookup *qgroup_lookup)
+{
+	struct btrfs_ioctl_search_args args = {
+		.key = {
+			.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+			.max_type = BTRFS_QGROUP_RELATION_KEY,
+			.min_type = BTRFS_QGROUP_STATUS_KEY,
+			.max_objectid = (u64)-1,
+			.max_offset = (u64)-1,
+			.max_transid = (u64)-1,
+			.nr_items = 4096,
+		},
+	};
+	int ret;
+
+	ret = __qgroups_search(fd, &args, qgroup_lookup);
+	if (ret == -ENOTTY)
+		error("can't list qgroups: quotas not enabled");
+	else if (ret < 0)
+		error("can't list qgroups: %s", strerror(-ret));
+	return ret;
+}
+
+int btrfs_qgroup_query(int fd, u64 qgroupid, struct btrfs_qgroup_stats *stats)
+{
+	struct btrfs_ioctl_search_args args = {
+		.key = {
+			.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+			.min_type = BTRFS_QGROUP_INFO_KEY,
+			.max_type = BTRFS_QGROUP_LIMIT_KEY,
+			.max_objectid = 0,
+			.min_offset = qgroupid,
+			.max_offset = qgroupid,
+			.max_transid = (u64)-1,
+			.nr_items = 4096,
+		},
+	};
+	struct qgroup_lookup qgroup_lookup;
+	struct btrfs_qgroup *qgroup;
+	struct rb_node *n;
+	int ret;
+
+	ret = __qgroups_search(fd, &args, &qgroup_lookup);
+	if (ret < 0)
+		return ret;
+
+	ret = -ENODATA;
+	n = rb_first(&qgroup_lookup.root);
+	if (n) {
+		qgroup = rb_entry(n, struct btrfs_qgroup, rb_node);
+		stats->qgroupid = qgroup->qgroupid;
+		stats->info = qgroup->info;
+		stats->limit = qgroup->limit;
+
+		ret = 0;
+	}
+
+	__free_all_qgroups(&qgroup_lookup);
+	return ret;
+}
+
 static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, bool verbose)
 {
 
@@ -1309,7 +1384,7 @@ int btrfs_show_qgroups(int fd,
 	struct qgroup_lookup sort_tree;
 	int ret;
 
-	ret = __qgroups_search(fd, &qgroup_lookup);
+	ret = qgroups_search_all(fd, &qgroup_lookup);
 	if (ret)
 		return ret;
 	__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
diff --git a/qgroup.h b/qgroup.h
index 5e71349c..688f92b2 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -87,6 +87,12 @@ struct btrfs_qgroup_info {
 	u64 exclusive_compressed;
 };
 
+struct btrfs_qgroup_stats {
+	u64 qgroupid;
+	struct btrfs_qgroup_info info;
+	struct btrfs_qgroup_limit limit;
+};
+
 int btrfs_qgroup_parse_sort_string(const char *opt_arg,
 				struct btrfs_qgroup_comparer_set **comps);
 int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
@@ -105,4 +111,5 @@ int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg);
 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
 			    int type);
 
+int btrfs_qgroup_query(int fd, u64 qgroupid, struct btrfs_qgroup_stats *stats);
 #endif
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/18] btrfs-progs: subvolume: add quota info to btrfs sub show
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (6 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 07/18] btrfs-progs: qgroups: introduce btrfs_qgroup_query jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 09/18] btrfs-progs: help: convert ints used as bools to bool jeffm
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

This patch reports on the first-level qgroup, if any, associated with
a particular subvolume.  It displays the usage and limit, subject
to the usual unit parameters.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 cmds-subvolume.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 45363a5a..d3c8e37c 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -910,6 +910,7 @@ static const char * const cmd_subvol_show_usage[] = {
 	"Show more information about the subvolume",
 	"-r|--rootid   rootid of the subvolume",
 	"-u|--uuid     uuid of the subvolume",
+	HELPINFO_UNITS_SHORT_LONG,
 	"",
 	"If no option is specified, <subvol-path> will be shown, otherwise",
 	"the rootid or uuid are resolved relative to the <mnt> path.",
@@ -932,6 +933,13 @@ static int cmd_subvol_show(int argc, char **argv)
 	struct btrfs_util_subvolume_info subvol;
 	char *subvol_path = NULL;
 	enum btrfs_util_error err;
+	struct btrfs_qgroup_stats stats;
+	unsigned int unit_mode;
+	const char *referenced_size;
+	const char *referenced_limit_size = "-";
+	unsigned int field_width = 0;
+
+	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
 	while (1) {
 		int c;
@@ -1101,7 +1109,48 @@ static int cmd_subvol_show(int argc, char **argv)
 	}
 	btrfs_util_destroy_subvolume_iterator(iter);
 
-	ret = 0;
+	ret = btrfs_qgroup_query(fd, subvol.id, &stats);
+	if (ret && ret != -ENOTTY && ret != -ENODATA) {
+		fprintf(stderr,
+			"\nERROR: BTRFS_IOC_QUOTA_QUERY failed: %s\n",
+			strerror(-ret));
+		goto out;
+	}
+
+	printf("\tQuota Usage:\t\t");
+	fflush(stdout);
+	if (ret) {
+		if (ret == -ENOTTY)
+			printf("quotas not enabled\n");
+		else
+			printf("quotas not available\n");
+		goto out;
+	}
+
+	referenced_size = pretty_size_mode(stats.info.referenced, unit_mode);
+	if (stats.limit.max_referenced)
+		referenced_limit_size = pretty_size_mode(
+						stats.limit.max_referenced,
+						unit_mode);
+	field_width = max(strlen(referenced_size),
+			  strlen(referenced_limit_size));
+
+	printf("%-*s referenced, %s exclusive\n ", field_width,
+	       referenced_size,
+	       pretty_size_mode(stats.info.exclusive, unit_mode));
+
+	printf("\tQuota Limits:\t\t");
+	if (stats.limit.max_referenced || stats.limit.max_exclusive) {
+		const char *excl = "-";
+
+		if (stats.limit.max_exclusive)
+			excl = pretty_size_mode(stats.limit.max_exclusive,
+						unit_mode);
+		printf("%-*s referenced, %s exclusive\n", field_width,
+		       referenced_limit_size, excl);
+	} else
+		printf("None\n");
+
 out:
 	free(subvol_path);
 	close_file_or_dir(fd, dirstream1);
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/18] btrfs-progs: help: convert ints used as bools to bool
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (7 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 08/18] btrfs-progs: subvolume: add quota info to btrfs sub show jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 10/18] btrfs-progs: reorder placement of help declarations for send/receive jeffm
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

We use an int for 'full', 'all', and 'err' when we really mean a boolean.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs.c | 14 +++++++-------
 help.c  | 25 +++++++++++++------------
 help.h  |  4 ++--
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 2d39f2ce..fec1a135 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -109,7 +109,7 @@ static void handle_help_options_next_level(const struct cmd_struct *cmd,
 			argv++;
 			help_command_group(cmd->next, argc, argv);
 		} else {
-			usage_command(cmd, 1, 0);
+			usage_command(cmd, true, false);
 		}
 
 		exit(0);
@@ -125,7 +125,7 @@ int handle_command_group(const struct cmd_group *grp, int argc,
 	argc--;
 	argv++;
 	if (argc < 1) {
-		usage_command_group(grp, 0, 0);
+		usage_command_group(grp, false, false);
 		exit(1);
 	}
 
@@ -212,20 +212,20 @@ static int handle_global_options(int argc, char **argv)
 
 void handle_special_globals(int shift, int argc, char **argv)
 {
-	int has_help = 0;
-	int has_full = 0;
+	bool has_help = false;
+	bool has_full = false;
 	int i;
 
 	for (i = 0; i < shift; i++) {
 		if (strcmp(argv[i], "--help") == 0)
-			has_help = 1;
+			has_help = true;
 		else if (strcmp(argv[i], "--full") == 0)
-			has_full = 1;
+			has_full = true;
 	}
 
 	if (has_help) {
 		if (has_full)
-			usage_command_group(&btrfs_cmd_group, 1, 0);
+			usage_command_group(&btrfs_cmd_group, true, false);
 		else
 			cmd_help(argc, argv);
 		exit(0);
diff --git a/help.c b/help.c
index f1dd3946..99fd325b 100644
--- a/help.c
+++ b/help.c
@@ -196,8 +196,8 @@ static int do_usage_one_command(const char * const *usagestr,
 }
 
 static int usage_command_internal(const char * const *usagestr,
-				  const char *token, int full, int lst,
-				  int alias, FILE *outf)
+				  const char *token, bool full, bool lst,
+				  bool alias, FILE *outf)
 {
 	unsigned int flags = 0;
 	int ret;
@@ -223,17 +223,17 @@ static int usage_command_internal(const char * const *usagestr,
 }
 
 static void usage_command_usagestr(const char * const *usagestr,
-				   const char *token, int full, int err)
+				   const char *token, bool full, bool err)
 {
 	FILE *outf = err ? stderr : stdout;
 	int ret;
 
-	ret = usage_command_internal(usagestr, token, full, 0, 0, outf);
+	ret = usage_command_internal(usagestr, token, full, false, false, outf);
 	if (!ret)
 		fputc('\n', outf);
 }
 
-void usage_command(const struct cmd_struct *cmd, int full, int err)
+void usage_command(const struct cmd_struct *cmd, bool full, bool err)
 {
 	usage_command_usagestr(cmd->usagestr, cmd->token, full, err);
 }
@@ -241,11 +241,11 @@ void usage_command(const struct cmd_struct *cmd, int full, int err)
 __attribute__((noreturn))
 void usage(const char * const *usagestr)
 {
-	usage_command_usagestr(usagestr, NULL, 1, 1);
+	usage_command_usagestr(usagestr, NULL, true, true);
 	exit(1);
 }
 
-static void usage_command_group_internal(const struct cmd_group *grp, int full,
+static void usage_command_group_internal(const struct cmd_group *grp, bool full,
 					 FILE *outf)
 {
 	const struct cmd_struct *cmd = grp->commands;
@@ -265,7 +265,8 @@ static void usage_command_group_internal(const struct cmd_group *grp, int full,
 			}
 
 			usage_command_internal(cmd->usagestr, cmd->token, full,
-					       1, cmd->flags & CMD_ALIAS, outf);
+					       true, cmd->flags & CMD_ALIAS,
+					       outf);
 			if (cmd->flags & CMD_ALIAS)
 				putchar('\n');
 			continue;
@@ -327,7 +328,7 @@ void usage_command_group_short(const struct cmd_group *grp)
 	fprintf(stderr, "All command groups have their manual page named 'btrfs-<group>'.\n");
 }
 
-void usage_command_group(const struct cmd_group *grp, int full, int err)
+void usage_command_group(const struct cmd_group *grp, bool full, bool err)
 {
 	const char * const *usagestr = grp->usagestr;
 	FILE *outf = err ? stderr : stdout;
@@ -350,7 +351,7 @@ __attribute__((noreturn))
 void help_unknown_token(const char *arg, const struct cmd_group *grp)
 {
 	fprintf(stderr, "%s: unknown token '%s'\n", get_argv0_buf(), arg);
-	usage_command_group(grp, 0, 1);
+	usage_command_group(grp, false, true);
 	exit(1);
 }
 
@@ -372,13 +373,13 @@ void help_ambiguous_token(const char *arg, const struct cmd_group *grp)
 
 void help_command_group(const struct cmd_group *grp, int argc, char **argv)
 {
-	int full = 0;
+	bool full = false;
 
 	if (argc > 1) {
 		if (!strcmp(argv[1], "--full"))
 			full = 1;
 	}
 
-	usage_command_group(grp, full, 0);
+	usage_command_group(grp, full, false);
 }
 
diff --git a/help.h b/help.h
index a1405942..322b910a 100644
--- a/help.h
+++ b/help.h
@@ -57,8 +57,8 @@ struct cmd_group;
 
 __attribute__((noreturn))
 void usage(const char * const *usagestr);
-void usage_command(const struct cmd_struct *cmd, int full, int err);
-void usage_command_group(const struct cmd_group *grp, int all, int err);
+void usage_command(const struct cmd_struct *cmd, bool full, bool err);
+void usage_command_group(const struct cmd_group *grp, bool all, bool err);
 void usage_command_group_short(const struct cmd_group *grp);
 
 __attribute__((noreturn))
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/18] btrfs-progs: reorder placement of help declarations for send/receive
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (8 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 09/18] btrfs-progs: help: convert ints used as bools to bool jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 11/18] btrfs-progs: filesystem balance: split out special handling jeffm
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

The usage definitions for send and receive follow the command
definitions, which use them.  This works because we declare them
in commands.h.  When we move to using cmd_struct as the entry point,
these declarations will be removed, breaking the commands.  Since
that would be an otherwise unrelated change, this patch reorders
them separately.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 cmds-receive.c | 62 ++++++++++++++++++++++++++--------------------------
 cmds-send.c    | 69 +++++++++++++++++++++++++++++-----------------------------
 2 files changed, 66 insertions(+), 65 deletions(-)

diff --git a/cmds-receive.c b/cmds-receive.c
index 68123a31..b3709f36 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1248,6 +1248,37 @@ out:
 	return ret;
 }
 
+const char * const cmd_receive_usage[] = {
+	"btrfs receive [options] <mount>\n"
+	"btrfs receive --dump [options]",
+	"Receive subvolumes from a stream",
+	"Receives one or more subvolumes that were previously",
+	"sent with btrfs send. The received subvolumes are stored",
+	"into MOUNT.",
+	"The receive will fail in case the receiving subvolume",
+	"already exists. It will also fail in case a previously",
+	"received subvolume has been changed after it was received.",
+	"After receiving a subvolume, it is immediately set to",
+	"read-only.",
+	"",
+	"-v               increase verbosity about performed actions",
+	"-f FILE          read the stream from FILE instead of stdin",
+	"-e               terminate after receiving an <end cmd> marker in the stream.",
+	"                 Without this option the receiver side terminates only in case",
+	"                 of an error on end of file.",
+	"-C|--chroot      confine the process to <mount> using chroot",
+	"-E|--max-errors NERR",
+	"                 terminate as soon as NERR errors occur while",
+	"                 stream processing commands from the stream.",
+	"                 Default value is 1. A value of 0 means no limit.",
+	"-m ROOTMOUNT     the root mount point of the destination filesystem.",
+	"                 If /proc is not accessible, use this to tell us where",
+	"                 this file system is mounted.",
+	"--dump           dump stream metadata, one line per operation,",
+	"                 does not require the MOUNT parameter",
+	NULL
+};
+
 int cmd_receive(int argc, char **argv)
 {
 	char *tomnt = NULL;
@@ -1357,34 +1388,3 @@ out:
 
 	return !!ret;
 }
-
-const char * const cmd_receive_usage[] = {
-	"btrfs receive [options] <mount>\n"
-	"btrfs receive --dump [options]",
-	"Receive subvolumes from a stream",
-	"Receives one or more subvolumes that were previously",
-	"sent with btrfs send. The received subvolumes are stored",
-	"into MOUNT.",
-	"The receive will fail in case the receiving subvolume",
-	"already exists. It will also fail in case a previously",
-	"received subvolume has been changed after it was received.",
-	"After receiving a subvolume, it is immediately set to",
-	"read-only.",
-	"",
-	"-v               increase verbosity about performed actions",
-	"-f FILE          read the stream from FILE instead of stdin",
-	"-e               terminate after receiving an <end cmd> marker in the stream.",
-	"                 Without this option the receiver side terminates only in case",
-	"                 of an error on end of file.",
-	"-C|--chroot      confine the process to <mount> using chroot",
-	"-E|--max-errors NERR",
-	"                 terminate as soon as NERR errors occur while",
-	"                 stream processing commands from the stream.",
-	"                 Default value is 1. A value of 0 means no limit.",
-	"-m ROOTMOUNT     the root mount point of the destination filesystem.",
-	"                 If /proc is not accessible, use this to tell us where",
-	"                 this file system is mounted.",
-	"--dump           dump stream metadata, one line per operation,",
-	"                 does not require the MOUNT parameter",
-	NULL
-};
diff --git a/cmds-send.c b/cmds-send.c
index c5ecdaa1..8365e9c9 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -489,6 +489,41 @@ static void free_send_info(struct btrfs_send *sctx)
 	subvol_uuid_search_finit(&sctx->sus);
 }
 
+
+const char * const cmd_send_usage[] = {
+	"btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
+	"Send the subvolume(s) to stdout.",
+	"Sends the subvolume(s) specified by <subvol> to stdout.",
+	"<subvol> should be read-only here.",
+	"By default, this will send the whole subvolume. To do an incremental",
+	"send, use '-p <parent>'. If you want to allow btrfs to clone from",
+	"any additional local snapshots, use '-c <clone-src>' (multiple times",
+	"where applicable). You must not specify clone sources unless you",
+	"guarantee that these snapshots are exactly in the same state on both",
+	"sides, the sender and the receiver. It is allowed to omit the",
+	"'-p <parent>' option when '-c <clone-src>' options are given, in",
+	"which case 'btrfs send' will determine a suitable parent among the",
+	"clone sources itself.",
+	"\n",
+	"-e               If sending multiple subvols at once, use the new",
+	"                 format and omit the end-cmd between the subvols.",
+	"-p <parent>      Send an incremental stream from <parent> to",
+	"                 <subvol>.",
+	"-c <clone-src>   Use this snapshot as a clone source for an ",
+	"                 incremental send (multiple allowed)",
+	"-f <outfile>     Output is normally written to stdout. To write to",
+	"                 a file, use this option. An alternative would be to",
+	"                 use pipes.",
+	"--no-data        send in NO_FILE_DATA mode, Note: the output stream",
+	"                 does not contain any file data and thus cannot be used",
+	"                 to transfer changes. This mode is faster and useful to",
+	"                 show the differences in metadata.",
+	"-v|--verbose     enable verbose output to stderr, each occurrence of",
+	"                 this option increases verbosity",
+	"-q|--quiet       suppress all messages, except errors",
+	NULL
+};
+
 int cmd_send(int argc, char **argv)
 {
 	char *subvol = NULL;
@@ -774,37 +809,3 @@ out:
 	free_send_info(&send);
 	return !!ret;
 }
-
-const char * const cmd_send_usage[] = {
-	"btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
-	"Send the subvolume(s) to stdout.",
-	"Sends the subvolume(s) specified by <subvol> to stdout.",
-	"<subvol> should be read-only here.",
-	"By default, this will send the whole subvolume. To do an incremental",
-	"send, use '-p <parent>'. If you want to allow btrfs to clone from",
-	"any additional local snapshots, use '-c <clone-src>' (multiple times",
-	"where applicable). You must not specify clone sources unless you",
-	"guarantee that these snapshots are exactly in the same state on both",
-	"sides, the sender and the receiver. It is allowed to omit the",
-	"'-p <parent>' option when '-c <clone-src>' options are given, in",
-	"which case 'btrfs send' will determine a suitable parent among the",
-	"clone sources itself.",
-	"\n",
-	"-e               If sending multiple subvols at once, use the new",
-	"                 format and omit the end-cmd between the subvols.",
-	"-p <parent>      Send an incremental stream from <parent> to",
-	"                 <subvol>.",
-	"-c <clone-src>   Use this snapshot as a clone source for an ",
-	"                 incremental send (multiple allowed)",
-	"-f <outfile>     Output is normally written to stdout. To write to",
-	"                 a file, use this option. An alternative would be to",
-	"                 use pipes.",
-	"--no-data        send in NO_FILE_DATA mode, Note: the output stream",
-	"                 does not contain any file data and thus cannot be used",
-	"                 to transfer changes. This mode is faster and useful to",
-	"                 show the differences in metadata.",
-	"-v|--verbose     enable verbose output to stderr, each occurrence of",
-	"                 this option increases verbosity",
-	"-q|--quiet       suppress all messages, except errors",
-	NULL
-};
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/18] btrfs-progs: filesystem balance: split out special handling
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (9 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 10/18] btrfs-progs: reorder placement of help declarations for send/receive jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 12/18] btrfs-progs: use cmd_struct as command entry point jeffm
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

In preparation to use cmd_struct as the command entry point, we need
to split out the 'filesystem balance' handling to not call cmd_balance
directly.  The reason is that the flags that indicate a command is
hidden are a part of cmd_struct and so we can use a cmd_struct as a
direct alias in another command group and ALSO have it be hidden
without declaring another cmd_struct.

This change has no immediate impact since cmd_balance will still
use its usage information directly from cmds-balance.c.  It will
take effect once we start passing cmd_structs around for usage
information.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 cmds-filesystem.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 30a50bf5..01d639e3 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -1177,6 +1177,18 @@ static int cmd_filesystem_label(int argc, char **argv)
 	}
 }
 
+static const char * const cmd_filesystem_balance_usage[] = {
+	"btrfs filesystem balance [args...] (alias of \"btrfs balance\")",
+	"Please see \"btrfs balance --help\" for more information.",
+	NULL
+};
+
+/* Compatible old "btrfs filesystem balance" command */
+static int cmd_filesystem_balance(int argc, char **argv)
+{
+	return cmd_balance(argc, argv);
+}
+
 static const char filesystem_cmd_group_info[] =
 "overall filesystem tasks and information";
 
@@ -1190,8 +1202,9 @@ const struct cmd_group filesystem_cmd_group = {
 			0 },
 		{ "defragment", cmd_filesystem_defrag,
 			cmd_filesystem_defrag_usage, NULL, 0 },
-		{ "balance", cmd_balance, NULL, &balance_cmd_group,
-			CMD_HIDDEN },
+		{ "balance", cmd_filesystem_balance,
+		   cmd_filesystem_balance_usage, &balance_cmd_group,
+		   CMD_HIDDEN },
 		{ "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
 			NULL, 0 },
 		{ "label", cmd_filesystem_label, cmd_filesystem_label_usage,
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 12/18] btrfs-progs: use cmd_struct as command entry point
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (10 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 11/18] btrfs-progs: filesystem balance: split out special handling jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 13/18] btrfs-progs: pass cmd_struct to command callback function jeffm
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

Rather than having global command usage and callbacks used to create
cmd_structs in the command array, establish the cmd_struct structures
separately and use those.  The next commit in the series passes the
cmd_struct to the command callbacks such that we can access flags
and determine which of several potential command we were called as.

This establishes several macros to more easily define the commands
within each command's source.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs.c                   |  48 ++++++++++--------
 check/main.c              |   5 +-
 cmds-balance.c            |  27 ++++++----
 cmds-device.c             |  31 ++++++-----
 cmds-fi-du.c              |   5 +-
 cmds-fi-usage.c           |   5 +-
 cmds-filesystem.c         |  52 ++++++++++---------
 cmds-inspect-dump-super.c |   5 +-
 cmds-inspect-dump-tree.c  |   5 +-
 cmds-inspect-tree-stats.c |   5 +-
 cmds-inspect.c            |  36 +++++++------
 cmds-property.c           |  19 +++----
 cmds-qgroup.c             |  31 +++++------
 cmds-quota.c              |  17 ++++---
 cmds-receive.c            |   5 +-
 cmds-replace.c            |  19 +++----
 cmds-rescue.c             |  22 ++++----
 cmds-restore.c            |   5 +-
 cmds-scrub.c              |  20 +++++---
 cmds-send.c               |   6 +--
 cmds-subvolume.c          |  38 ++++++++------
 commands.h                | 127 +++++++++++++++++++++++++++-------------------
 help.c                    |  21 +++++---
 23 files changed, 317 insertions(+), 237 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index fec1a135..1e68b0c0 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -42,10 +42,11 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
 static int parse_one_token(const char *arg, const struct cmd_group *grp,
 			   const struct cmd_struct **cmd_ret)
 {
-	const struct cmd_struct *cmd = grp->commands;
 	const struct cmd_struct *abbrev_cmd = NULL, *ambiguous_cmd = NULL;
+	int i = 0;
 
-	for (; cmd->token; cmd++) {
+	for (i = 0; grp->commands[i]; i++) {
+		const struct cmd_struct *cmd = grp->commands[i];
 		const char *rest;
 
 		rest = skip_prefix(arg, cmd->token);
@@ -134,7 +135,7 @@ int handle_command_group(const struct cmd_group *grp, int argc,
 	handle_help_options_next_level(cmd, argc, argv);
 
 	fixup_argv0(argv, cmd->token);
-	return cmd->fn(argc, argv);
+	return cmd_execute(cmd, argc, argv);
 }
 
 static const struct cmd_group btrfs_cmd_group;
@@ -153,6 +154,8 @@ static int cmd_help(int argc, char **argv)
 	return 0;
 }
 
+static DEFINE_SIMPLE_COMMAND(help, "help");
+
 static const char * const cmd_version_usage[] = {
 	"btrfs version",
 	"Display btrfs-progs version",
@@ -164,6 +167,7 @@ static int cmd_version(int argc, char **argv)
 	printf("%s\n", PACKAGE_STRING);
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(version, "version");
 
 /*
  * Parse global options, between binary name and first non-option argument
@@ -240,24 +244,24 @@ void handle_special_globals(int shift, int argc, char **argv)
 
 static const struct cmd_group btrfs_cmd_group = {
 	btrfs_cmd_group_usage, btrfs_cmd_group_info, {
-		{ "subvolume", cmd_subvolume, NULL, &subvolume_cmd_group, 0 },
-		{ "filesystem", cmd_filesystem, NULL, &filesystem_cmd_group, 0 },
-		{ "balance", cmd_balance, NULL, &balance_cmd_group, 0 },
-		{ "device", cmd_device, NULL, &device_cmd_group, 0 },
-		{ "scrub", cmd_scrub, NULL, &scrub_cmd_group, 0 },
-		{ "check", cmd_check, cmd_check_usage, NULL, 0 },
-		{ "rescue", cmd_rescue, NULL, &rescue_cmd_group, 0 },
-		{ "restore", cmd_restore, cmd_restore_usage, NULL, 0 },
-		{ "inspect-internal", cmd_inspect, NULL, &inspect_cmd_group, 0 },
-		{ "property", cmd_property, NULL, &property_cmd_group, 0 },
-		{ "send", cmd_send, cmd_send_usage, NULL, 0 },
-		{ "receive", cmd_receive, cmd_receive_usage, NULL, 0 },
-		{ "quota", cmd_quota, NULL, &quota_cmd_group, 0 },
-		{ "qgroup", cmd_qgroup, NULL, &qgroup_cmd_group, 0 },
-		{ "replace", cmd_replace, NULL, &replace_cmd_group, 0 },
-		{ "help", cmd_help, cmd_help_usage, NULL, 0 },
-		{ "version", cmd_version, cmd_version_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_subvolume,
+		&cmd_struct_filesystem,
+		&cmd_struct_balance,
+		&cmd_struct_device,
+		&cmd_struct_scrub,
+		&cmd_struct_check,
+		&cmd_struct_rescue,
+		&cmd_struct_restore,
+		&cmd_struct_inspect,
+		&cmd_struct_property,
+		&cmd_struct_send,
+		&cmd_struct_receive,
+		&cmd_struct_quota,
+		&cmd_struct_qgroup,
+		&cmd_struct_replace,
+		&cmd_struct_help,
+		&cmd_struct_version,
+		NULL
 	},
 };
 
@@ -299,7 +303,7 @@ int main(int argc, char **argv)
 
 	fixup_argv0(argv, cmd->token);
 
-	ret = cmd->fn(argc, argv);
+	ret = cmd_execute(cmd, argc, argv);
 
 	btrfs_close_all_devices();
 
diff --git a/check/main.c b/check/main.c
index 68da994f..a1b685e7 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9360,7 +9360,7 @@ close_out:
 	return ret;
 }
 
-const char * const cmd_check_usage[] = {
+static const char * const cmd_check_usage[] = {
 	"btrfs check [options] <device>",
 	"Check structural integrity of a filesystem (unmounted).",
 	"Check structural integrity of an unmounted filesystem. Verify internal",
@@ -9392,7 +9392,7 @@ const char * const cmd_check_usage[] = {
 	NULL
 };
 
-int cmd_check(int argc, char **argv)
+static int cmd_check(int argc, char **argv)
 {
 	struct cache_tree root_cache;
 	struct btrfs_root *root;
@@ -9891,3 +9891,4 @@ err_out:
 
 	return err;
 }
+DEFINE_SIMPLE_COMMAND(check, "check");
diff --git a/cmds-balance.c b/cmds-balance.c
index 0c91bdf1..7a60be61 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -672,6 +672,7 @@ static int cmd_balance_start(int argc, char **argv)
 
 	return do_balance(argv[optind], &args, start_flags);
 }
+static DEFINE_SIMPLE_COMMAND(balance_start, "start");
 
 static const char * const cmd_balance_pause_usage[] = {
 	"btrfs balance pause <path>",
@@ -710,6 +711,7 @@ static int cmd_balance_pause(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(balance_pause, "pause");
 
 static const char * const cmd_balance_cancel_usage[] = {
 	"btrfs balance cancel <path>",
@@ -748,6 +750,7 @@ static int cmd_balance_cancel(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(balance_cancel, "cancel");
 
 static const char * const cmd_balance_resume_usage[] = {
 	"btrfs balance resume <path>",
@@ -807,6 +810,7 @@ static int cmd_balance_resume(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(balance_resume, "resume");
 
 static const char * const cmd_balance_status_usage[] = {
 	"btrfs balance status [-v] <path>",
@@ -898,6 +902,7 @@ out:
 	close_file_or_dir(fd, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(balance_status, "status");
 
 static int cmd_balance_full(int argc, char **argv)
 {
@@ -908,23 +913,25 @@ static int cmd_balance_full(int argc, char **argv)
 
 	return do_balance(argv[1], &args, BALANCE_START_NOWARN);
 }
+static DEFINE_COMMAND(balance_full, "--full-balance", cmd_balance_full,
+		      NULL, NULL, CMD_HIDDEN);
 
 static const char balance_cmd_group_info[] =
 "balance data across devices, or change block groups using filters";
 
-const struct cmd_group balance_cmd_group = {
+static const struct cmd_group balance_cmd_group = {
 	balance_cmd_group_usage, balance_cmd_group_info, {
-		{ "start", cmd_balance_start, cmd_balance_start_usage, NULL, 0 },
-		{ "pause", cmd_balance_pause, cmd_balance_pause_usage, NULL, 0 },
-		{ "cancel", cmd_balance_cancel, cmd_balance_cancel_usage, NULL, 0 },
-		{ "resume", cmd_balance_resume, cmd_balance_resume_usage, NULL, 0 },
-		{ "status", cmd_balance_status, cmd_balance_status_usage, NULL, 0 },
-		{ "--full-balance", cmd_balance_full, NULL, NULL, 1 },
-		NULL_CMD_STRUCT
+		&cmd_struct_balance_start,
+		&cmd_struct_balance_pause,
+		&cmd_struct_balance_cancel,
+		&cmd_struct_balance_resume,
+		&cmd_struct_balance_status,
+		&cmd_struct_balance_full,
+		NULL
 	}
 };
 
-int cmd_balance(int argc, char **argv)
+static int cmd_balance(int argc, char **argv)
 {
 	if (argc == 2 && strcmp("start", argv[1]) != 0) {
 		/* old 'btrfs filesystem balance <path>' syntax */
@@ -938,3 +945,5 @@ int cmd_balance(int argc, char **argv)
 
 	return handle_command_group(&balance_cmd_group, argc, argv);
 }
+
+DEFINE_GROUP_COMMAND(balance, "balance");
diff --git a/cmds-device.c b/cmds-device.c
index a49c9d9d..96764d6c 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -140,6 +140,7 @@ error_out:
 	close_file_or_dir(fdmnt, dirstream);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(device_add, "add");
 
 static int _cmd_device_remove(int argc, char **argv,
 		const char * const *usagestr)
@@ -239,6 +240,7 @@ static int cmd_device_remove(int argc, char **argv)
 {
 	return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
 }
+static DEFINE_SIMPLE_COMMAND(device_remove, "remove");
 
 static const char * const cmd_device_delete_usage[] = {
 	"btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
@@ -252,6 +254,8 @@ static int cmd_device_delete(int argc, char **argv)
 {
 	return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
 }
+static DEFINE_COMMAND(device_delete, "delete", cmd_device_delete,
+		      cmd_device_delete_usage, NULL, CMD_ALIAS);
 
 static const char * const cmd_device_scan_usage[] = {
 	"btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
@@ -325,6 +329,7 @@ static int cmd_device_scan(int argc, char **argv)
 out:
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(device_scan, "scan");
 
 static const char * const cmd_device_ready_usage[] = {
 	"btrfs device ready <device>",
@@ -378,6 +383,7 @@ out:
 	close(fd);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(device_ready, "ready");
 
 static const char * const cmd_device_stats_usage[] = {
 	"btrfs device stats [options] <path>|<device>",
@@ -518,6 +524,7 @@ out:
 
 	return err;
 }
+static DEFINE_SIMPLE_COMMAND(device_stats, "stats");
 
 static const char * const cmd_device_usage_usage[] = {
 	"btrfs device usage [options] <path> [<path>..]",
@@ -590,26 +597,26 @@ static int cmd_device_usage(int argc, char **argv)
 
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(device_usage, "usage");
 
 static const char device_cmd_group_info[] =
 "manage and query devices in the filesystem";
 
-const struct cmd_group device_cmd_group = {
+static const struct cmd_group device_cmd_group = {
 	device_cmd_group_usage, device_cmd_group_info, {
-		{ "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
-		{ "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
-			CMD_ALIAS },
-		{ "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
-		{ "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
-		{ "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
-		{ "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
-		{ "usage", cmd_device_usage,
-			cmd_device_usage_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_device_add,
+		&cmd_struct_device_delete,
+		&cmd_struct_device_remove,
+		&cmd_struct_device_scan,
+		&cmd_struct_device_ready,
+		&cmd_struct_device_stats,
+		&cmd_struct_device_usage,
+		NULL
 	}
 };
 
-int cmd_device(int argc, char **argv)
+static int cmd_device(int argc, char **argv)
 {
 	return handle_command_group(&device_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(device);
diff --git a/cmds-fi-du.c b/cmds-fi-du.c
index 7e6bb7f6..334151d6 100644
--- a/cmds-fi-du.c
+++ b/cmds-fi-du.c
@@ -549,7 +549,7 @@ out:
 	return ret;
 }
 
-const char * const cmd_filesystem_du_usage[] = {
+static const char * const cmd_filesystem_du_usage[] = {
 	"btrfs filesystem du [options] <path> [<path>..]",
 	"Summarize disk usage of each file.",
 	"-s|--summarize     display only a total for each argument",
@@ -557,7 +557,7 @@ const char * const cmd_filesystem_du_usage[] = {
 	NULL
 };
 
-int cmd_filesystem_du(int argc, char **argv)
+static int cmd_filesystem_du(int argc, char **argv)
 {
 	int ret = 0, err = 0;
 	int i;
@@ -611,3 +611,4 @@ int cmd_filesystem_du(int argc, char **argv)
 
 	return err;
 }
+DEFINE_SIMPLE_COMMAND(filesystem_du, "du");
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index d08ec4d3..4f19f5e1 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -956,7 +956,7 @@ out:
 	return ret;
 }
 
-const char * const cmd_filesystem_usage_usage[] = {
+static const char * const cmd_filesystem_usage_usage[] = {
 	"btrfs filesystem usage [options] <path> [<path>..]",
 	"Show detailed information about internal filesystem usage .",
 	HELPINFO_UNITS_SHORT_LONG,
@@ -964,7 +964,7 @@ const char * const cmd_filesystem_usage_usage[] = {
 	NULL
 };
 
-int cmd_filesystem_usage(int argc, char **argv)
+static int cmd_filesystem_usage(int argc, char **argv)
 {
 	int ret = 0;
 	unsigned unit_mode;
@@ -1034,6 +1034,7 @@ cleanup:
 out:
 	return !!ret;
 }
+DEFINE_SIMPLE_COMMAND(filesystem_usage, "usage");
 
 void print_device_chunks(struct device_info *devinfo,
 		struct chunk_info *chunks_info_ptr,
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 01d639e3..c19290cc 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -151,6 +151,7 @@ static int cmd_filesystem_df(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_df, "df");
 
 static int match_search_item_kernel(u8 *fsid, char *mnt, char *label,
 					char *search)
@@ -806,6 +807,7 @@ out:
 	free_seen_fsid(seen_fsid_hash);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_show, "show");
 
 static const char * const cmd_filesystem_sync_usage[] = {
 	"btrfs filesystem sync <path>",
@@ -830,6 +832,7 @@ static int cmd_filesystem_sync(int argc, char **argv)
 
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_sync, "sync");
 
 static int parse_compress_type(char *s)
 {
@@ -1068,6 +1071,7 @@ next:
 
 	return !!defrag_global_errors;
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_defrag, "defragment");
 
 static const char * const cmd_filesystem_resize_usage[] = {
 	"btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
@@ -1146,6 +1150,7 @@ static int cmd_filesystem_resize(int argc, char **argv)
 	}
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_resize, "resize");
 
 static const char * const cmd_filesystem_label_usage[] = {
 	"btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
@@ -1176,6 +1181,7 @@ static int cmd_filesystem_label(int argc, char **argv)
 		return ret;
 	}
 }
+static DEFINE_SIMPLE_COMMAND(filesystem_label, "label");
 
 static const char * const cmd_filesystem_balance_usage[] = {
 	"btrfs filesystem balance [args...] (alias of \"btrfs balance\")",
@@ -1183,40 +1189,40 @@ static const char * const cmd_filesystem_balance_usage[] = {
 	NULL
 };
 
-/* Compatible old "btrfs filesystem balance" command */
 static int cmd_filesystem_balance(int argc, char **argv)
 {
-	return cmd_balance(argc, argv);
+	return cmd_execute(&cmd_struct_balance, argc, argv);
 }
 
+/*
+ * Compatible old "btrfs filesystem balance" command
+ *
+ * We can't use cmd_struct_balance directly here since this alias is
+ * for historical compatibility and is hidden.
+ */
+static DEFINE_COMMAND(filesystem_balance, "balance", cmd_filesystem_balance,
+		      cmd_filesystem_balance_usage, NULL, CMD_HIDDEN);
+
 static const char filesystem_cmd_group_info[] =
 "overall filesystem tasks and information";
 
-const struct cmd_group filesystem_cmd_group = {
+static const struct cmd_group filesystem_cmd_group = {
 	filesystem_cmd_group_usage, filesystem_cmd_group_info, {
-		{ "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
-		{ "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
-		{ "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
-			0 },
-		{ "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
-			0 },
-		{ "defragment", cmd_filesystem_defrag,
-			cmd_filesystem_defrag_usage, NULL, 0 },
-		{ "balance", cmd_filesystem_balance,
-		   cmd_filesystem_balance_usage, &balance_cmd_group,
-		   CMD_HIDDEN },
-		{ "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
-			NULL, 0 },
-		{ "label", cmd_filesystem_label, cmd_filesystem_label_usage,
-			NULL, 0 },
-		{ "usage", cmd_filesystem_usage,
-			cmd_filesystem_usage_usage, NULL, 0 },
-
-		NULL_CMD_STRUCT
+		&cmd_struct_filesystem_df,
+		&cmd_struct_filesystem_du,
+		&cmd_struct_filesystem_show,
+		&cmd_struct_filesystem_sync,
+		&cmd_struct_filesystem_defrag,
+		&cmd_struct_filesystem_balance,
+		&cmd_struct_filesystem_resize,
+		&cmd_struct_filesystem_label,
+		&cmd_struct_filesystem_usage,
+		NULL
 	}
 };
 
-int cmd_filesystem(int argc, char **argv)
+static int cmd_filesystem(int argc, char **argv)
 {
 	return handle_command_group(&filesystem_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(filesystem);
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index e965267c..393af59e 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -489,7 +489,7 @@ static int load_and_dump_sb(char *filename, int fd, u64 sb_bytenr, int full,
 	return 0;
 }
 
-const char * const cmd_inspect_dump_super_usage[] = {
+static const char * const cmd_inspect_dump_super_usage[] = {
 	"btrfs inspect-internal dump-super [options] device [device...]",
 	"Dump superblock from a device in a textual form",
 	"-f|--full             print full superblock information, backup roots etc.",
@@ -507,7 +507,7 @@ const char * const cmd_inspect_dump_super_usage[] = {
 	NULL
 };
 
-int cmd_inspect_dump_super(int argc, char **argv)
+static int cmd_inspect_dump_super(int argc, char **argv)
 {
 	int all = 0;
 	int full = 0;
@@ -615,3 +615,4 @@ int cmd_inspect_dump_super(int argc, char **argv)
 out:
 	return ret;
 }
+DEFINE_SIMPLE_COMMAND(inspect_dump_super, "dump-super");
diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index 92a2a45b..2d4bbd62 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -184,7 +184,7 @@ static u64 treeid_from_string(const char *str, const char **end)
 	return id;
 }
 
-const char * const cmd_inspect_dump_tree_usage[] = {
+static const char * const cmd_inspect_dump_tree_usage[] = {
 	"btrfs inspect-internal dump-tree [options] device",
 	"Dump tree structures from a given device",
 	"Dump tree structures from a given device in textual form, expand keys to human",
@@ -203,7 +203,7 @@ const char * const cmd_inspect_dump_tree_usage[] = {
 	NULL
 };
 
-int cmd_inspect_dump_tree(int argc, char **argv)
+static int cmd_inspect_dump_tree(int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_fs_info *info;
@@ -597,3 +597,4 @@ close_root:
 out:
 	return !!ret;
 }
+DEFINE_SIMPLE_COMMAND(inspect_dump_tree, "dump-tree");
diff --git a/cmds-inspect-tree-stats.c b/cmds-inspect-tree-stats.c
index eced0db9..14d79ccc 100644
--- a/cmds-inspect-tree-stats.c
+++ b/cmds-inspect-tree-stats.c
@@ -420,14 +420,14 @@ out:
 	return ret;
 }
 
-const char * const cmd_inspect_tree_stats_usage[] = {
+static const char * const cmd_inspect_tree_stats_usage[] = {
 	"btrfs inspect-internal tree-stats [options] <device>",
 	"Print various stats for trees",
 	"-b		raw numbers in bytes",
 	NULL
 };
 
-int cmd_inspect_tree_stats(int argc, char **argv)
+static int cmd_inspect_tree_stats(int argc, char **argv)
 {
 	struct btrfs_key key;
 	struct btrfs_root *root;
@@ -494,3 +494,4 @@ out:
 	close_ctree(root);
 	return ret;
 }
+DEFINE_SIMPLE_COMMAND(inspect_tree_stats, "tree-stats");
diff --git a/cmds-inspect.c b/cmds-inspect.c
index afd7fe48..b45dbffe 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -121,6 +121,7 @@ static int cmd_inspect_inode_resolve(int argc, char **argv)
 	return !!ret;
 
 }
+static DEFINE_SIMPLE_COMMAND(inspect_inode_resolve, "inode-resolve");
 
 static const char * const cmd_inspect_logical_resolve_usage[] = {
 	"btrfs inspect-internal logical-resolve [-Pv] [-s bufsize] <logical> <path>",
@@ -257,6 +258,7 @@ out:
 	free(inodes);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(inspect_logical_resolve, "logical-resolve");
 
 static const char * const cmd_inspect_subvolid_resolve_usage[] = {
 	"btrfs inspect-internal subvolid-resolve <subvolid> <path>",
@@ -299,6 +301,7 @@ out:
 	close_file_or_dir(fd, dirstream);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(inspect_subvolid_resolve, "subvolid-resolve");
 
 static const char* const cmd_inspect_rootid_usage[] = {
 	"btrfs inspect-internal rootid <path>",
@@ -336,6 +339,7 @@ out:
 
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(inspect_rootid, "rootid");
 
 static const char* const cmd_inspect_min_dev_size_usage[] = {
 	"btrfs inspect-internal min-dev-size [options] <path>",
@@ -625,33 +629,27 @@ static int cmd_inspect_min_dev_size(int argc, char **argv)
 out:
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(inspect_min_dev_size, "min-dev-size");
 
 static const char inspect_cmd_group_info[] =
 "query various internal information";
 
-const struct cmd_group inspect_cmd_group = {
+static const struct cmd_group inspect_cmd_group = {
 	inspect_cmd_group_usage, inspect_cmd_group_info, {
-		{ "inode-resolve", cmd_inspect_inode_resolve,
-			cmd_inspect_inode_resolve_usage, NULL, 0 },
-		{ "logical-resolve", cmd_inspect_logical_resolve,
-			cmd_inspect_logical_resolve_usage, NULL, 0 },
-		{ "subvolid-resolve", cmd_inspect_subvolid_resolve,
-			cmd_inspect_subvolid_resolve_usage, NULL, 0 },
-		{ "rootid", cmd_inspect_rootid, cmd_inspect_rootid_usage, NULL,
-			0 },
-		{ "min-dev-size", cmd_inspect_min_dev_size,
-			cmd_inspect_min_dev_size_usage, NULL, 0 },
-		{ "dump-tree", cmd_inspect_dump_tree,
-				cmd_inspect_dump_tree_usage, NULL, 0 },
-		{ "dump-super", cmd_inspect_dump_super,
-				cmd_inspect_dump_super_usage, NULL, 0 },
-		{ "tree-stats", cmd_inspect_tree_stats,
-				cmd_inspect_tree_stats_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_inspect_inode_resolve,
+		&cmd_struct_inspect_logical_resolve,
+		&cmd_struct_inspect_subvolid_resolve,
+		&cmd_struct_inspect_rootid,
+		&cmd_struct_inspect_min_dev_size,
+		&cmd_struct_inspect_dump_tree,
+		&cmd_struct_inspect_dump_super,
+		&cmd_struct_inspect_tree_stats,
+		NULL
 	}
 };
 
-int cmd_inspect(int argc, char **argv)
+static int cmd_inspect(int argc, char **argv)
 {
 	return handle_command_group(&inspect_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND(inspect, "inspect-internal");
diff --git a/cmds-property.c b/cmds-property.c
index 03bafa05..dce1f2a9 100644
--- a/cmds-property.c
+++ b/cmds-property.c
@@ -358,6 +358,7 @@ static int cmd_property_get(int argc, char **argv)
 
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(property_get, "get");
 
 static const char * const cmd_property_set_usage[] = {
 	"btrfs property set [-t <type>] <object> <name> <value>",
@@ -382,6 +383,7 @@ static int cmd_property_set(int argc, char **argv)
 
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(property_set, "set");
 
 static const char * const cmd_property_list_usage[] = {
 	"btrfs property list [-t <type>] <object>",
@@ -404,23 +406,22 @@ static int cmd_property_list(int argc, char **argv)
 
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(property_list, "list");
 
 static const char property_cmd_group_info[] =
 "modify properties of filesystem objects";
 
-const struct cmd_group property_cmd_group = {
+static const struct cmd_group property_cmd_group = {
 	property_cmd_group_usage, property_cmd_group_info, {
-		{ "get", cmd_property_get,
-			cmd_property_get_usage, NULL, 0 },
-		{ "set", cmd_property_set,
-			cmd_property_set_usage, NULL, 0 },
-		{ "list", cmd_property_list,
-			cmd_property_list_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_property_get,
+		&cmd_struct_property_set,
+		&cmd_struct_property_list,
+		NULL
 	}
 };
 
-int cmd_property(int argc, char **argv)
+static int cmd_property(int argc, char **argv)
 {
 	return handle_command_group(&property_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(property);
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 33053725..ddfa2aa0 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -221,6 +221,7 @@ static int cmd_qgroup_assign(int argc, char **argv)
 {
 	return _cmd_qgroup_assign(1, argc, argv, cmd_qgroup_assign_usage);
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_assign, "assign");
 
 static const char * const cmd_qgroup_remove_usage[] = {
 	"btrfs qgroup remove <src> <dst> <path>",
@@ -232,6 +233,7 @@ static int cmd_qgroup_remove(int argc, char **argv)
 {
 	return _cmd_qgroup_assign(0, argc, argv, cmd_qgroup_remove_usage);
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_remove, "remove");
 
 static const char * const cmd_qgroup_create_usage[] = {
 	"btrfs qgroup create <qgroupid> <path>",
@@ -251,6 +253,7 @@ static int cmd_qgroup_create(int argc, char **argv)
 		usage(cmd_qgroup_create_usage);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_create, "create");
 
 static const char * const cmd_qgroup_destroy_usage[] = {
 	"btrfs qgroup destroy <qgroupid> <path>",
@@ -270,6 +273,7 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 		usage(cmd_qgroup_destroy_usage);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_destroy, "destroy");
 
 static const char * const cmd_qgroup_show_usage[] = {
 	"btrfs qgroup show [options] <path>",
@@ -418,6 +422,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 out:
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_show, "show");
 
 static const char * const cmd_qgroup_limit_usage[] = {
 	"btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
@@ -507,29 +512,25 @@ static int cmd_qgroup_limit(int argc, char **argv)
 	}
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(qgroup_limit, "limit");
 
 static const char qgroup_cmd_group_info[] =
 "manage quota groups";
 
-const struct cmd_group qgroup_cmd_group = {
+static const struct cmd_group qgroup_cmd_group = {
 	qgroup_cmd_group_usage, qgroup_cmd_group_info, {
-		{ "assign", cmd_qgroup_assign, cmd_qgroup_assign_usage,
-		   NULL, 0 },
-		{ "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage,
-		   NULL, 0 },
-		{ "create", cmd_qgroup_create, cmd_qgroup_create_usage,
-		   NULL, 0 },
-		{ "destroy", cmd_qgroup_destroy, cmd_qgroup_destroy_usage,
-		   NULL, 0 },
-		{ "show", cmd_qgroup_show, cmd_qgroup_show_usage,
-		   NULL, 0 },
-		{ "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage,
-		   NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_qgroup_assign,
+		&cmd_struct_qgroup_remove,
+		&cmd_struct_qgroup_create,
+		&cmd_struct_qgroup_destroy,
+		&cmd_struct_qgroup_show,
+		&cmd_struct_qgroup_limit,
+		NULL
 	}
 };
 
-int cmd_qgroup(int argc, char **argv)
+static int cmd_qgroup(int argc, char **argv)
 {
 	return handle_command_group(&qgroup_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(qgroup);
diff --git a/cmds-quota.c b/cmds-quota.c
index 7f933495..5cd5607f 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -79,6 +79,7 @@ static int cmd_quota_enable(int argc, char **argv)
 		usage(cmd_quota_enable_usage);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(quota_enable, "enable");
 
 static const char * const cmd_quota_disable_usage[] = {
 	"btrfs quota disable <path>",
@@ -98,6 +99,7 @@ static int cmd_quota_disable(int argc, char **argv)
 		usage(cmd_quota_disable_usage);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(quota_disable, "disable");
 
 static const char * const cmd_quota_rescan_usage[] = {
 	"btrfs quota rescan [-sw] <path>",
@@ -197,21 +199,22 @@ static int cmd_quota_rescan(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(quota_rescan, "rescan");
 
 static const char quota_cmd_group_info[] =
 "manage filesystem quota settings";
 
-const struct cmd_group quota_cmd_group = {
+static const struct cmd_group quota_cmd_group = {
 	quota_cmd_group_usage, quota_cmd_group_info, {
-		{ "enable", cmd_quota_enable, cmd_quota_enable_usage, NULL, 0 },
-		{ "disable", cmd_quota_disable, cmd_quota_disable_usage,
-		   NULL, 0 },
-		{ "rescan", cmd_quota_rescan, cmd_quota_rescan_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_quota_enable,
+		&cmd_struct_quota_disable,
+		&cmd_struct_quota_rescan,
+		NULL
 	}
 };
 
-int cmd_quota(int argc, char **argv)
+static int cmd_quota(int argc, char **argv)
 {
 	return handle_command_group(&quota_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(quota);
diff --git a/cmds-receive.c b/cmds-receive.c
index b3709f36..d88b8793 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1248,7 +1248,7 @@ out:
 	return ret;
 }
 
-const char * const cmd_receive_usage[] = {
+static const char * const cmd_receive_usage[] = {
 	"btrfs receive [options] <mount>\n"
 	"btrfs receive --dump [options]",
 	"Receive subvolumes from a stream",
@@ -1279,7 +1279,7 @@ const char * const cmd_receive_usage[] = {
 	NULL
 };
 
-int cmd_receive(int argc, char **argv)
+static int cmd_receive(int argc, char **argv)
 {
 	char *tomnt = NULL;
 	char fromfile[PATH_MAX];
@@ -1388,3 +1388,4 @@ out:
 
 	return !!ret;
 }
+DEFINE_SIMPLE_COMMAND(receive, "receive");
diff --git a/cmds-replace.c b/cmds-replace.c
index 032a44fc..a7379c71 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -313,6 +313,7 @@ leave_with_error:
 		close(fddstdev);
 	return 1;
 }
+static DEFINE_SIMPLE_COMMAND(replace_start, "start");
 
 static const char *const cmd_replace_status_usage[] = {
 	"btrfs replace status [-1] <mount_point>",
@@ -356,6 +357,7 @@ static int cmd_replace_status(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(replace_status, "status");
 
 static int print_replace_status(int fd, const char *path, int once)
 {
@@ -538,23 +540,22 @@ static int cmd_replace_cancel(int argc, char **argv)
 	}
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(replace_cancel, "cancel");
 
 static const char replace_cmd_group_info[] =
 "replace a device in the filesystem";
 
-const struct cmd_group replace_cmd_group = {
+static const struct cmd_group replace_cmd_group = {
 	replace_cmd_group_usage, replace_cmd_group_info, {
-		{ "start", cmd_replace_start, cmd_replace_start_usage, NULL,
-		  0 },
-		{ "status", cmd_replace_status, cmd_replace_status_usage, NULL,
-		  0 },
-		{ "cancel", cmd_replace_cancel, cmd_replace_cancel_usage, NULL,
-		  0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_replace_start,
+		&cmd_struct_replace_status,
+		&cmd_struct_replace_cancel,
+		NULL
 	}
 };
 
-int cmd_replace(int argc, char **argv)
+static int cmd_replace(int argc, char **argv)
 {
 	return handle_command_group(&replace_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(replace);
diff --git a/cmds-rescue.c b/cmds-rescue.c
index c61145bc..e3611f2f 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -94,6 +94,7 @@ static int cmd_rescue_chunk_recover(int argc, char *argv[])
 	}
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(rescue_chunk_recover, "chunk-recover");
 
 static const char * const cmd_rescue_super_recover_usage[] = {
 	"btrfs rescue super-recover [options] <device>",
@@ -149,6 +150,7 @@ static int cmd_rescue_super_recover(int argc, char **argv)
 	ret = btrfs_recover_superblocks(dname, verbose, yes);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(rescue_super_recover, "super-recover");
 
 static const char * const cmd_rescue_zero_log_usage[] = {
 	"btrfs rescue zero-log <device>",
@@ -202,6 +204,7 @@ static int cmd_rescue_zero_log(int argc, char **argv)
 out:
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(rescue_zero_log, "zero-log");
 
 static const char * const cmd_rescue_fix_device_size_usage[] = {
 	"btrfs rescue fix-device-size <device>",
@@ -247,24 +250,23 @@ static int cmd_rescue_fix_device_size(int argc, char **argv)
 out:
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(rescue_fix_device_size, "fix-device-size");
 
 static const char rescue_cmd_group_info[] =
 "toolbox for specific rescue operations";
 
-const struct cmd_group rescue_cmd_group = {
+static const struct cmd_group rescue_cmd_group = {
 	rescue_cmd_group_usage, rescue_cmd_group_info, {
-		{ "chunk-recover", cmd_rescue_chunk_recover,
-			cmd_rescue_chunk_recover_usage, NULL, 0},
-		{ "super-recover", cmd_rescue_super_recover,
-			cmd_rescue_super_recover_usage, NULL, 0},
-		{ "zero-log", cmd_rescue_zero_log, cmd_rescue_zero_log_usage, NULL, 0},
-		{ "fix-device-size", cmd_rescue_fix_device_size,
-			cmd_rescue_fix_device_size_usage, NULL, 0},
-		NULL_CMD_STRUCT
+		&cmd_struct_rescue_chunk_recover,
+		&cmd_struct_rescue_super_recover,
+		&cmd_struct_rescue_zero_log,
+		&cmd_struct_rescue_fix_device_size,
+		NULL
 	}
 };
 
-int cmd_rescue(int argc, char **argv)
+static int cmd_rescue(int argc, char **argv)
 {
 	return handle_command_group(&rescue_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(rescue);
diff --git a/cmds-restore.c b/cmds-restore.c
index f228acab..f8391294 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -1396,7 +1396,7 @@ out:
 	return ret;
 }
 
-const char * const cmd_restore_usage[] = {
+static const char * const cmd_restore_usage[] = {
 	"btrfs restore [options] <device> <path> | -l <device>",
 	"Try to restore files from a damaged filesystem (unmounted)",
 	"",
@@ -1422,7 +1422,7 @@ const char * const cmd_restore_usage[] = {
 	NULL
 };
 
-int cmd_restore(int argc, char **argv)
+static int cmd_restore(int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_key key;
@@ -1628,3 +1628,4 @@ out:
 	close_ctree(root);
 	return !!ret;
 }
+DEFINE_SIMPLE_COMMAND(restore, "restore");
diff --git a/cmds-scrub.c b/cmds-scrub.c
index 6b909f20..f2a579b9 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1578,6 +1578,7 @@ static int cmd_scrub_start(int argc, char **argv)
 {
 	return scrub_start(argc, argv, 0);
 }
+static DEFINE_SIMPLE_COMMAND(scrub_start, "start");
 
 static const char * const cmd_scrub_cancel_usage[] = {
 	"btrfs scrub cancel <path>|<device>",
@@ -1624,6 +1625,7 @@ out:
 	close_file_or_dir(fdmnt, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(scrub_cancel, "cancel");
 
 static const char * const cmd_scrub_resume_usage[] = {
 	"btrfs scrub resume [-BdqrR] [-c ioprio_class -n ioprio_classdata] <path>|<device>",
@@ -1643,6 +1645,7 @@ static int cmd_scrub_resume(int argc, char **argv)
 {
 	return scrub_start(argc, argv, 1);
 }
+static DEFINE_SIMPLE_COMMAND(scrub_resume, "resume");
 
 static const char * const cmd_scrub_status_usage[] = {
 	"btrfs scrub status [-dR] <path>|<device>",
@@ -1784,21 +1787,24 @@ out:
 
 	return !!err;
 }
+static DEFINE_SIMPLE_COMMAND(scrub_status, "status");
 
 static const char scrub_cmd_group_info[] =
 "verify checksums of data and metadata";
 
-const struct cmd_group scrub_cmd_group = {
+static const struct cmd_group scrub_cmd_group = {
 	scrub_cmd_group_usage, scrub_cmd_group_info, {
-		{ "start", cmd_scrub_start, cmd_scrub_start_usage, NULL, 0 },
-		{ "cancel", cmd_scrub_cancel, cmd_scrub_cancel_usage, NULL, 0 },
-		{ "resume", cmd_scrub_resume, cmd_scrub_resume_usage, NULL, 0 },
-		{ "status", cmd_scrub_status, cmd_scrub_status_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_scrub_start,
+		&cmd_struct_scrub_cancel,
+		&cmd_struct_scrub_resume,
+		&cmd_struct_scrub_status,
+		NULL
 	}
 };
 
-int cmd_scrub(int argc, char **argv)
+static int cmd_scrub(int argc, char **argv)
 {
 	return handle_command_group(&scrub_cmd_group, argc, argv);
 }
+
+DEFINE_GROUP_COMMAND_TOKEN(scrub);
diff --git a/cmds-send.c b/cmds-send.c
index 8365e9c9..f1e5124d 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -489,8 +489,7 @@ static void free_send_info(struct btrfs_send *sctx)
 	subvol_uuid_search_finit(&sctx->sus);
 }
 
-
-const char * const cmd_send_usage[] = {
+static const char * const cmd_send_usage[] = {
 	"btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",
 	"Send the subvolume(s) to stdout.",
 	"Sends the subvolume(s) specified by <subvol> to stdout.",
@@ -524,7 +523,7 @@ const char * const cmd_send_usage[] = {
 	NULL
 };
 
-int cmd_send(int argc, char **argv)
+static int cmd_send(int argc, char **argv)
 {
 	char *subvol = NULL;
 	int ret;
@@ -809,3 +808,4 @@ out:
 	free_send_info(&send);
 	return !!ret;
 }
+DEFINE_SIMPLE_COMMAND(send, "send");
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index d3c8e37c..9967b6d7 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -197,6 +197,7 @@ out:
 
 	return retval;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_create, "create");
 
 static int wait_for_commit(int fd)
 {
@@ -403,6 +404,7 @@ keep_fd:
 
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_delete, "delete");
 
 /*
  * Naming of options:
@@ -606,6 +608,7 @@ out:
 		usage(cmd_subvol_list_usage);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_list, "list");
 
 static const char * const cmd_subvol_snapshot_usage[] = {
 	"btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>",
@@ -759,6 +762,7 @@ out:
 
 	return retval;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_snapshot, "snapshot");
 
 static const char * const cmd_subvol_get_default_usage[] = {
 	"btrfs subvolume get-default <path>",
@@ -820,6 +824,7 @@ out:
 	close_file_or_dir(fd, dirstream);
 	return ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_get_default, "get-default");
 
 static const char * const cmd_subvol_set_default_usage[] = {
 	"btrfs subvolume set-default <subvolume>\n"
@@ -859,6 +864,7 @@ static int cmd_subvol_set_default(int argc, char **argv)
 	}
 	return 0;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_set_default, "set-default");
 
 static const char * const cmd_subvol_find_new_usage[] = {
 	"btrfs subvolume find-new <path> <lastgen>",
@@ -904,6 +910,7 @@ static int cmd_subvol_find_new(int argc, char **argv)
 	close_file_or_dir(fd, dirstream);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_find_new, "find-new");
 
 static const char * const cmd_subvol_show_usage[] = {
 	"btrfs subvolume show [options] <subvol-path>|<mnt>",
@@ -1157,6 +1164,7 @@ out:
 	free(fullpath);
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_show, "show");
 
 static const char * const cmd_subvol_sync_usage[] = {
 	"btrfs subvolume sync <path> [<subvol-id>...]",
@@ -1261,30 +1269,28 @@ out:
 
 	return !!ret;
 }
+static DEFINE_SIMPLE_COMMAND(subvol_sync, "sync");
 
 static const char subvolume_cmd_group_info[] =
 "manage subvolumes: create, delete, list, etc";
 
-const struct cmd_group subvolume_cmd_group = {
+static const struct cmd_group subvolume_cmd_group = {
 	subvolume_cmd_group_usage, subvolume_cmd_group_info, {
-		{ "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
-		{ "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
-		{ "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
-		{ "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
-			NULL, 0 },
-		{ "get-default", cmd_subvol_get_default,
-			cmd_subvol_get_default_usage, NULL, 0 },
-		{ "set-default", cmd_subvol_set_default,
-			cmd_subvol_set_default_usage, NULL, 0 },
-		{ "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
-			NULL, 0 },
-		{ "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
-		{ "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
-		NULL_CMD_STRUCT
+		&cmd_struct_subvol_create,
+		&cmd_struct_subvol_delete,
+		&cmd_struct_subvol_list,
+		&cmd_struct_subvol_snapshot,
+		&cmd_struct_subvol_get_default,
+		&cmd_struct_subvol_set_default,
+		&cmd_struct_subvol_find_new,
+		&cmd_struct_subvol_show,
+		&cmd_struct_subvol_sync,
+		NULL
 	}
 };
 
-int cmd_subvolume(int argc, char **argv)
+static int cmd_subvolume(int argc, char **argv)
 {
 	return handle_command_group(&subvolume_cmd_group, argc, argv);
 }
+DEFINE_GROUP_COMMAND_TOKEN(subvolume);
diff --git a/commands.h b/commands.h
index 76991f2b..9a65204b 100644
--- a/commands.h
+++ b/commands.h
@@ -56,69 +56,92 @@ struct cmd_struct {
 	int flags;
 };
 
-#define NULL_CMD_STRUCT {NULL, NULL, NULL, NULL, 0}
+/*
+ * These macros will create cmd_struct structures with a standard name:
+ * cmd_struct_<name>.
+ */
+#define __CMD_NAME(name)	cmd_struct_ ##name
+#define DECLARE_COMMAND(name)						\
+	extern const struct cmd_struct __CMD_NAME(name)
+
+/* Define a command with all members specified */
+#define DEFINE_COMMAND(name, _token, _fn, _usagestr, _group, _flags)	\
+	const struct cmd_struct __CMD_NAME(name) =			\
+		{							\
+			.token = (_token),				\
+			.fn = (_fn),					\
+			.usagestr = (_usagestr),			\
+			.next = (_group),				\
+			.flags = (_flags),				\
+		}
+
+/*
+ * Define a command for the common case - just a name and string.
+ * It's assumed that the callback is called cmd_<name> and the usage
+ * array is named cmd_<name>_usage.
+ */
+#define DEFINE_SIMPLE_COMMAND(name, token)				\
+	DEFINE_COMMAND(name, token, cmd_ ##name,			\
+		       cmd_ ##name ##_usage, NULL, 0)
+
+/*
+ * Define a command group callback.
+ * It's assumed that the callback is called cmd_<name> and the
+ * struct cmd_group is called <name>_cmd_group.
+ */
+#define DEFINE_GROUP_COMMAND(name, token)				\
+	DEFINE_COMMAND(name, token, cmd_ ##name,			\
+		       NULL, &(name ## _cmd_group), 0)
+
+/*
+ * Define a command group callback when the name and the string are
+ * the same.
+ */
+#define DEFINE_GROUP_COMMAND_TOKEN(name)				\
+	DEFINE_GROUP_COMMAND(name, #name)
 
 struct cmd_group {
 	const char * const *usagestr;
 	const char *infostr;
 
-	const struct cmd_struct commands[];
+	const struct cmd_struct * const commands[];
 };
 
+static inline int cmd_execute(const struct cmd_struct *cmd,
+			      int argc, char **argv)
+{
+	return cmd->fn(argc, argv);
+}
+
 int handle_command_group(const struct cmd_group *grp, int argc,
 			 char **argv);
 
 extern const char * const generic_cmd_help_usage[];
 
-extern const struct cmd_group subvolume_cmd_group;
-extern const struct cmd_group filesystem_cmd_group;
-extern const struct cmd_group balance_cmd_group;
-extern const struct cmd_group device_cmd_group;
-extern const struct cmd_group scrub_cmd_group;
-extern const struct cmd_group inspect_cmd_group;
-extern const struct cmd_group property_cmd_group;
-extern const struct cmd_group quota_cmd_group;
-extern const struct cmd_group qgroup_cmd_group;
-extern const struct cmd_group replace_cmd_group;
-extern const struct cmd_group rescue_cmd_group;
-
-extern const char * const cmd_send_usage[];
-extern const char * const cmd_receive_usage[];
-extern const char * const cmd_check_usage[];
-extern const char * const cmd_chunk_recover_usage[];
-extern const char * const cmd_super_recover_usage[];
-extern const char * const cmd_restore_usage[];
-extern const char * const cmd_rescue_usage[];
-extern const char * const cmd_inspect_dump_super_usage[];
-extern const char * const cmd_inspect_dump_tree_usage[];
-extern const char * const cmd_inspect_tree_stats_usage[];
-extern const char * const cmd_filesystem_du_usage[];
-extern const char * const cmd_filesystem_usage_usage[];
-
-int cmd_subvolume(int argc, char **argv);
-int cmd_filesystem(int argc, char **argv);
-int cmd_filesystem_du(int argc, char **argv);
-int cmd_filesystem_usage(int argc, char **argv);
-int cmd_balance(int argc, char **argv);
-int cmd_device(int argc, char **argv);
-int cmd_scrub(int argc, char **argv);
-int cmd_check(int argc, char **argv);
-int cmd_chunk_recover(int argc, char **argv);
-int cmd_super_recover(int argc, char **argv);
-int cmd_inspect(int argc, char **argv);
-int cmd_inspect_dump_super(int argc, char **argv);
-int cmd_inspect_dump_tree(int argc, char **argv);
-int cmd_inspect_tree_stats(int argc, char **argv);
-int cmd_property(int argc, char **argv);
-int cmd_send(int argc, char **argv);
-int cmd_receive(int argc, char **argv);
-int cmd_quota(int argc, char **argv);
-int cmd_qgroup(int argc, char **argv);
-int cmd_replace(int argc, char **argv);
-int cmd_restore(int argc, char **argv);
-int cmd_select_super(int argc, char **argv);
-int cmd_dump_super(int argc, char **argv);
-int cmd_debug_tree(int argc, char **argv);
-int cmd_rescue(int argc, char **argv);
+DECLARE_COMMAND(subvolume);
+DECLARE_COMMAND(filesystem);
+DECLARE_COMMAND(filesystem_du);
+DECLARE_COMMAND(filesystem_usage);
+DECLARE_COMMAND(balance);
+DECLARE_COMMAND(device);
+DECLARE_COMMAND(scrub);
+DECLARE_COMMAND(check);
+DECLARE_COMMAND(chunk_recover);
+DECLARE_COMMAND(super_recover);
+DECLARE_COMMAND(inspect);
+DECLARE_COMMAND(inspect_dump_super);
+DECLARE_COMMAND(inspect_dump_tree);
+DECLARE_COMMAND(inspect_tree_stats);
+DECLARE_COMMAND(property);
+DECLARE_COMMAND(send);
+DECLARE_COMMAND(receive);
+DECLARE_COMMAND(quota);
+DECLARE_COMMAND(qgroup);
+DECLARE_COMMAND(replace);
+DECLARE_COMMAND(restore);
+DECLARE_COMMAND(select_super);
+DECLARE_COMMAND(dump_super);
+DECLARE_COMMAND(debug_tree);
+DECLARE_COMMAND(rescue);
 
 #endif
diff --git a/help.c b/help.c
index 99fd325b..2c0d8d71 100644
--- a/help.c
+++ b/help.c
@@ -248,14 +248,15 @@ void usage(const char * const *usagestr)
 static void usage_command_group_internal(const struct cmd_group *grp, bool full,
 					 FILE *outf)
 {
-	const struct cmd_struct *cmd = grp->commands;
+	int i;
 	int do_sep = 0;
 
-	for (; cmd->token; cmd++) {
+	for (i = 0; grp->commands[i]; i++) {
+		const struct cmd_struct *cmd = grp->commands[i];
 		if (cmd->flags & CMD_HIDDEN)
 			continue;
 
-		if (full && cmd != grp->commands)
+		if (full && i)
 			fputc('\n', outf);
 
 		if (!cmd->next) {
@@ -274,7 +275,7 @@ static void usage_command_group_internal(const struct cmd_group *grp, bool full,
 
 		/* this is an entry point to a nested command group */
 
-		if (!full && cmd != grp->commands)
+		if (!full && i)
 			fputc('\n', outf);
 
 		usage_command_group_internal(cmd->next, full, outf);
@@ -289,6 +290,7 @@ void usage_command_group_short(const struct cmd_group *grp)
 	const char * const *usagestr = grp->usagestr;
 	FILE *outf = stdout;
 	const struct cmd_struct *cmd;
+	int i;
 
 	if (usagestr && *usagestr) {
 		fprintf(outf, "usage: %s\n", *usagestr++);
@@ -299,7 +301,8 @@ void usage_command_group_short(const struct cmd_group *grp)
 	fputc('\n', outf);
 
 	fprintf(outf, "Command groups:\n");
-	for (cmd = grp->commands; cmd->token; cmd++) {
+	for (i = 0; grp->commands[i]; i++) {
+		cmd = grp->commands[i];
 		if (cmd->flags & CMD_HIDDEN)
 			continue;
 
@@ -310,7 +313,8 @@ void usage_command_group_short(const struct cmd_group *grp)
 	}
 
 	fprintf(outf, "\nCommands:\n");
-	for (cmd = grp->commands; cmd->token; cmd++) {
+	for (i = 0; grp->commands[i]; i++) {
+		cmd = grp->commands[i];
 		if (cmd->flags & CMD_HIDDEN)
 			continue;
 
@@ -358,12 +362,13 @@ void help_unknown_token(const char *arg, const struct cmd_group *grp)
 __attribute__((noreturn))
 void help_ambiguous_token(const char *arg, const struct cmd_group *grp)
 {
-	const struct cmd_struct *cmd = grp->commands;
+	int i;
 
 	fprintf(stderr, "%s: ambiguous token '%s'\n", get_argv0_buf(), arg);
 	fprintf(stderr, "\nDid you mean one of these ?\n");
 
-	for (; cmd->token; cmd++) {
+	for (i = 0; grp->commands[i]; i++) {
+		const struct cmd_struct *cmd = grp->commands[i];
 		if (!prefixcmp(cmd->token, arg))
 			fprintf(stderr, "\t%s\n", cmd->token);
 	}
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 13/18] btrfs-progs: pass cmd_struct to command callback function
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (11 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 12/18] btrfs-progs: use cmd_struct as command entry point jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 14/18] btrfs-progs: pass cmd_struct to clean_args_no_options{,_relaxed} jeffm
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

This patch passes the cmd_struct to the command callback function.  This
has several purposes: It allows the command callback to identify which
command was used to call it.  It also gives us direct access to the
usage associated with that command.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs.c                   |  8 ++++----
 check/main.c              |  2 +-
 cmds-balance.c            | 19 ++++++++++++-------
 cmds-device.c             | 35 +++++++++++++++++++----------------
 cmds-fi-du.c              |  3 ++-
 cmds-fi-usage.c           |  3 ++-
 cmds-filesystem.c         | 24 ++++++++++++++++--------
 cmds-inspect-dump-super.c |  3 ++-
 cmds-inspect-dump-tree.c  |  3 ++-
 cmds-inspect-tree-stats.c |  3 ++-
 cmds-inspect.c            | 17 +++++++++++------
 cmds-property.c           | 12 ++++++++----
 cmds-qgroup.c             | 18 +++++++++++-------
 cmds-quota.c              |  9 +++++----
 cmds-receive.c            |  2 +-
 cmds-replace.c            | 11 +++++++----
 cmds-rescue.c             | 14 +++++++++-----
 cmds-restore.c            |  2 +-
 cmds-scrub.c              | 23 +++++++++++------------
 cmds-send.c               |  2 +-
 cmds-subvolume.c          | 27 +++++++++++++++++----------
 commands.h                |  4 ++--
 22 files changed, 146 insertions(+), 98 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 1e68b0c0..49128182 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -148,7 +148,7 @@ static const char * const cmd_help_usage[] = {
 	NULL
 };
 
-static int cmd_help(int argc, char **argv)
+static int cmd_help(const struct cmd_struct *unused, int argc, char **argv)
 {
 	help_command_group(&btrfs_cmd_group, argc, argv);
 	return 0;
@@ -162,7 +162,7 @@ static const char * const cmd_version_usage[] = {
 	NULL
 };
 
-static int cmd_version(int argc, char **argv)
+static int cmd_version(const struct cmd_struct *unused, int argc, char **argv)
 {
 	printf("%s\n", PACKAGE_STRING);
 	return 0;
@@ -231,13 +231,13 @@ void handle_special_globals(int shift, int argc, char **argv)
 		if (has_full)
 			usage_command_group(&btrfs_cmd_group, true, false);
 		else
-			cmd_help(argc, argv);
+			cmd_execute(&cmd_struct_help, argc, argv);
 		exit(0);
 	}
 
 	for (i = 0; i < shift; i++)
 		if (strcmp(argv[i], "--version") == 0) {
-			cmd_version(argc, argv);
+			cmd_execute(&cmd_struct_version, argc, argv);
 			exit(0);
 		}
 }
diff --git a/check/main.c b/check/main.c
index a1b685e7..0375eec3 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9392,7 +9392,7 @@ static const char * const cmd_check_usage[] = {
 	NULL
 };
 
-static int cmd_check(int argc, char **argv)
+static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	struct cache_tree root_cache;
 	struct btrfs_root *root;
diff --git a/cmds-balance.c b/cmds-balance.c
index 7a60be61..1bd7b3ce 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -515,7 +515,8 @@ static const char * const cmd_balance_start_usage[] = {
 	NULL
 };
 
-static int cmd_balance_start(int argc, char **argv)
+static int cmd_balance_start(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
 	struct btrfs_balance_args *ptrs[] = { &args.data, &args.sys,
@@ -680,7 +681,8 @@ static const char * const cmd_balance_pause_usage[] = {
 	NULL
 };
 
-static int cmd_balance_pause(int argc, char **argv)
+static int cmd_balance_pause(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	const char *path;
 	int fd;
@@ -719,7 +721,8 @@ static const char * const cmd_balance_cancel_usage[] = {
 	NULL
 };
 
-static int cmd_balance_cancel(int argc, char **argv)
+static int cmd_balance_cancel(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	const char *path;
 	int fd;
@@ -758,7 +761,8 @@ static const char * const cmd_balance_resume_usage[] = {
 	NULL
 };
 
-static int cmd_balance_resume(int argc, char **argv)
+static int cmd_balance_resume(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
 	const char *path;
@@ -826,7 +830,8 @@ static const char * const cmd_balance_status_usage[] = {
  *   1 : Successful to know status of a pending balance
  *   0 : When there is no pending balance or completed
  */
-static int cmd_balance_status(int argc, char **argv)
+static int cmd_balance_status(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
 	const char *path;
@@ -904,7 +909,7 @@ out:
 }
 static DEFINE_SIMPLE_COMMAND(balance_status, "status");
 
-static int cmd_balance_full(int argc, char **argv)
+static int cmd_balance_full(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
 
@@ -931,7 +936,7 @@ static const struct cmd_group balance_cmd_group = {
 	}
 };
 
-static int cmd_balance(int argc, char **argv)
+static int cmd_balance(const struct cmd_struct *unused, int argc, char **argv)
 {
 	if (argc == 2 && strcmp("start", argv[1]) != 0) {
 		/* old 'btrfs filesystem balance <path>' syntax */
diff --git a/cmds-device.c b/cmds-device.c
index 96764d6c..feb53f68 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -48,7 +48,8 @@ static const char * const cmd_device_add_usage[] = {
 	NULL
 };
 
-static int cmd_device_add(int argc, char **argv)
+static int cmd_device_add(const struct cmd_struct *cmd,
+			  int argc, char **argv)
 {
 	char	*mntpnt;
 	int i, fdmnt, ret = 0;
@@ -142,17 +143,17 @@ error_out:
 }
 static DEFINE_SIMPLE_COMMAND(device_add, "add");
 
-static int _cmd_device_remove(int argc, char **argv,
-		const char * const *usagestr)
+static int _cmd_device_remove(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	char	*mntpnt;
 	int i, fdmnt, ret = 0;
 	DIR	*dirstream = NULL;
 
-	clean_args_no_options(argc, argv, usagestr);
+	clean_args_no_options(argc, argv, cmd->usagestr);
 
 	if (check_argc_min(argc - optind, 2))
-		usage(usagestr);
+		usage(cmd->usagestr);
 
 	mntpnt = argv[argc - 1];
 
@@ -236,9 +237,10 @@ static const char * const cmd_device_remove_usage[] = {
 	NULL
 };
 
-static int cmd_device_remove(int argc, char **argv)
+static int cmd_device_remove(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
-	return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
+	return _cmd_device_remove(cmd, argc, argv);
 }
 static DEFINE_SIMPLE_COMMAND(device_remove, "remove");
 
@@ -250,9 +252,10 @@ static const char * const cmd_device_delete_usage[] = {
 	NULL
 };
 
-static int cmd_device_delete(int argc, char **argv)
+static int cmd_device_delete(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
-	return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
+	return _cmd_device_remove(cmd, argc, argv);
 }
 static DEFINE_COMMAND(device_delete, "delete", cmd_device_delete,
 		      cmd_device_delete_usage, NULL, CMD_ALIAS);
@@ -264,7 +267,7 @@ static const char * const cmd_device_scan_usage[] = {
 	NULL
 };
 
-static int cmd_device_scan(int argc, char **argv)
+static int cmd_device_scan(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int i;
 	int devstart;
@@ -337,14 +340,14 @@ static const char * const cmd_device_ready_usage[] = {
 	NULL
 };
 
-static int cmd_device_ready(int argc, char **argv)
+static int cmd_device_ready(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	struct	btrfs_ioctl_vol_args args;
 	int	fd;
 	int	ret;
 	char	*path;
 
-	clean_args_no_options(argc, argv, cmd_device_ready_usage);
+	clean_args_no_options(argc, argv, cmd->usagestr);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_device_ready_usage);
@@ -396,7 +399,7 @@ static const char * const cmd_device_stats_usage[] = {
 	NULL
 };
 
-static int cmd_device_stats(int argc, char **argv)
+static int cmd_device_stats(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *dev_path;
 	struct btrfs_ioctl_fs_info_args fi_args;
@@ -562,7 +565,7 @@ out:
 	return ret;
 }
 
-static int cmd_device_usage(int argc, char **argv)
+static int cmd_device_usage(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	unsigned unit_mode;
 	int ret = 0;
@@ -570,7 +573,7 @@ static int cmd_device_usage(int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
-	clean_args_no_options(argc, argv, cmd_device_usage_usage);
+	clean_args_no_options(argc, argv, cmd->usagestr);
 
 	if (check_argc_min(argc - optind, 1))
 		usage(cmd_device_usage_usage);
@@ -615,7 +618,7 @@ static const struct cmd_group device_cmd_group = {
 	}
 };
 
-static int cmd_device(int argc, char **argv)
+static int cmd_device(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&device_cmd_group, argc, argv);
 }
diff --git a/cmds-fi-du.c b/cmds-fi-du.c
index 334151d6..67d65519 100644
--- a/cmds-fi-du.c
+++ b/cmds-fi-du.c
@@ -557,7 +557,8 @@ static const char * const cmd_filesystem_du_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_du(int argc, char **argv)
+static int cmd_filesystem_du(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int ret = 0, err = 0;
 	int i;
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index 4f19f5e1..c01b677a 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -964,7 +964,8 @@ static const char * const cmd_filesystem_usage_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_usage(int argc, char **argv)
+static int cmd_filesystem_usage(const struct cmd_struct *cmd,
+				int argc, char **argv)
 {
 	int ret = 0;
 	unsigned unit_mode;
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index c19290cc..649d97a9 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -117,7 +117,8 @@ static void print_df(struct btrfs_ioctl_space_args *sargs, unsigned unit_mode)
 	}
 }
 
-static int cmd_filesystem_df(int argc, char **argv)
+static int cmd_filesystem_df(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	struct btrfs_ioctl_space_args *sargs = NULL;
 	int ret;
@@ -668,7 +669,8 @@ static const char * const cmd_filesystem_show_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_show(int argc, char **argv)
+static int cmd_filesystem_show(const struct cmd_struct *cmd,
+			       int argc, char **argv)
 {
 	LIST_HEAD(all_uuids);
 	struct btrfs_fs_devices *fs_devices;
@@ -815,7 +817,8 @@ static const char * const cmd_filesystem_sync_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_sync(int argc, char **argv)
+static int cmd_filesystem_sync(const struct cmd_struct *cmd,
+			       int argc, char **argv)
 {
 	enum btrfs_util_error err;
 
@@ -903,7 +906,8 @@ error:
 	return 0;
 }
 
-static int cmd_filesystem_defrag(int argc, char **argv)
+static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
+				 int argc, char **argv)
 {
 	int fd;
 	int flush = 0;
@@ -1082,7 +1086,8 @@ static const char * const cmd_filesystem_resize_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_resize(int argc, char **argv)
+static int cmd_filesystem_resize(const struct cmd_struct *cmd,
+				 int argc, char **argv)
 {
 	struct btrfs_ioctl_vol_args	args;
 	int	fd, res, len, e;
@@ -1160,7 +1165,8 @@ static const char * const cmd_filesystem_label_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_label(int argc, char **argv)
+static int cmd_filesystem_label(const struct cmd_struct *cmd,
+				int argc, char **argv)
 {
 	clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
 
@@ -1189,7 +1195,8 @@ static const char * const cmd_filesystem_balance_usage[] = {
 	NULL
 };
 
-static int cmd_filesystem_balance(int argc, char **argv)
+static int cmd_filesystem_balance(const struct cmd_struct *unused,
+				  int argc, char **argv)
 {
 	return cmd_execute(&cmd_struct_balance, argc, argv);
 }
@@ -1221,7 +1228,8 @@ static const struct cmd_group filesystem_cmd_group = {
 	}
 };
 
-static int cmd_filesystem(int argc, char **argv)
+static int cmd_filesystem(const struct cmd_struct *unused,
+			  int argc, char **argv)
 {
 	return handle_command_group(&filesystem_cmd_group, argc, argv);
 }
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index 393af59e..49df12eb 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -507,7 +507,8 @@ static const char * const cmd_inspect_dump_super_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_dump_super(int argc, char **argv)
+static int cmd_inspect_dump_super(const struct cmd_struct *cmd,
+				  int argc, char **argv)
 {
 	int all = 0;
 	int full = 0;
diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index 2d4bbd62..97f5ea46 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -203,7 +203,8 @@ static const char * const cmd_inspect_dump_tree_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_dump_tree(int argc, char **argv)
+static int cmd_inspect_dump_tree(const struct cmd_struct *cmd,
+				 int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_fs_info *info;
diff --git a/cmds-inspect-tree-stats.c b/cmds-inspect-tree-stats.c
index 14d79ccc..64ca3d0b 100644
--- a/cmds-inspect-tree-stats.c
+++ b/cmds-inspect-tree-stats.c
@@ -427,7 +427,8 @@ static const char * const cmd_inspect_tree_stats_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_tree_stats(int argc, char **argv)
+static int cmd_inspect_tree_stats(const struct cmd_struct *cmd,
+				  int argc, char **argv)
 {
 	struct btrfs_key key;
 	struct btrfs_root *root;
diff --git a/cmds-inspect.c b/cmds-inspect.c
index b45dbffe..46ea5551 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -87,7 +87,8 @@ static const char * const cmd_inspect_inode_resolve_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_inode_resolve(int argc, char **argv)
+static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
+				     int argc, char **argv)
 {
 	int fd;
 	int verbose = 0;
@@ -134,7 +135,8 @@ static const char * const cmd_inspect_logical_resolve_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_logical_resolve(int argc, char **argv)
+static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
+				       int argc, char **argv)
 {
 	int ret;
 	int fd;
@@ -266,7 +268,8 @@ static const char * const cmd_inspect_subvolid_resolve_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_subvolid_resolve(int argc, char **argv)
+static int cmd_inspect_subvolid_resolve(const struct cmd_struct *cmd,
+					int argc, char **argv)
 {
 	int ret;
 	int fd = -1;
@@ -309,7 +312,8 @@ static const char* const cmd_inspect_rootid_usage[] = {
 	NULL
 };
 
-static int cmd_inspect_rootid(int argc, char **argv)
+static int cmd_inspect_rootid(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	int ret;
 	int fd = -1;
@@ -588,7 +592,8 @@ out:
 	return ret;
 }
 
-static int cmd_inspect_min_dev_size(int argc, char **argv)
+static int cmd_inspect_min_dev_size(const struct cmd_struct *cmd,
+				    int argc, char **argv)
 {
 	int ret;
 	int fd = -1;
@@ -648,7 +653,7 @@ static const struct cmd_group inspect_cmd_group = {
 	}
 };
 
-static int cmd_inspect(int argc, char **argv)
+static int cmd_inspect(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&inspect_cmd_group, argc, argv);
 }
diff --git a/cmds-property.c b/cmds-property.c
index dce1f2a9..5684443c 100644
--- a/cmds-property.c
+++ b/cmds-property.c
@@ -341,7 +341,8 @@ static const char * const cmd_property_get_usage[] = {
 	NULL
 };
 
-static int cmd_property_get(int argc, char **argv)
+static int cmd_property_get(const struct cmd_struct *cmd,
+			    int argc, char **argv)
 {
 	int ret;
 	char *object = NULL;
@@ -368,7 +369,8 @@ static const char * const cmd_property_set_usage[] = {
 	NULL
 };
 
-static int cmd_property_set(int argc, char **argv)
+static int cmd_property_set(const struct cmd_struct *cmd,
+			    int argc, char **argv)
 {
 	int ret;
 	char *object = NULL;
@@ -393,7 +395,8 @@ static const char * const cmd_property_list_usage[] = {
 	NULL
 };
 
-static int cmd_property_list(int argc, char **argv)
+static int cmd_property_list(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int ret;
 	char *object = NULL;
@@ -420,7 +423,8 @@ static const struct cmd_group property_cmd_group = {
 	}
 };
 
-static int cmd_property(int argc, char **argv)
+static int cmd_property(const struct cmd_struct *unused,
+			int argc, char **argv)
 {
 	return handle_command_group(&property_cmd_group, argc, argv);
 }
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index ddfa2aa0..5426c8fe 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -217,7 +217,8 @@ static const char * const cmd_qgroup_assign_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_assign(int argc, char **argv)
+static int cmd_qgroup_assign(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	return _cmd_qgroup_assign(1, argc, argv, cmd_qgroup_assign_usage);
 }
@@ -229,7 +230,8 @@ static const char * const cmd_qgroup_remove_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_remove(int argc, char **argv)
+static int cmd_qgroup_remove(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	return _cmd_qgroup_assign(0, argc, argv, cmd_qgroup_remove_usage);
 }
@@ -241,7 +243,8 @@ static const char * const cmd_qgroup_create_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_create(int argc, char **argv)
+static int cmd_qgroup_create(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int ret;
 
@@ -261,7 +264,8 @@ static const char * const cmd_qgroup_destroy_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_destroy(int argc, char **argv)
+static int cmd_qgroup_destroy(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	int ret;
 
@@ -298,7 +302,7 @@ static const char * const cmd_qgroup_show_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_show(int argc, char **argv)
+static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *path;
 	int ret = 0;
@@ -434,7 +438,7 @@ static const char * const cmd_qgroup_limit_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_limit(int argc, char **argv)
+static int cmd_qgroup_limit(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
@@ -529,7 +533,7 @@ static const struct cmd_group qgroup_cmd_group = {
 	}
 };
 
-static int cmd_qgroup(int argc, char **argv)
+static int cmd_qgroup(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&qgroup_cmd_group, argc, argv);
 }
diff --git a/cmds-quota.c b/cmds-quota.c
index 5cd5607f..a6e7a6f6 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -67,7 +67,7 @@ static const char * const cmd_quota_enable_usage[] = {
 	NULL
 };
 
-static int cmd_quota_enable(int argc, char **argv)
+static int cmd_quota_enable(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int ret;
 
@@ -87,7 +87,8 @@ static const char * const cmd_quota_disable_usage[] = {
 	NULL
 };
 
-static int cmd_quota_disable(int argc, char **argv)
+static int cmd_quota_disable(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int ret;
 
@@ -110,7 +111,7 @@ static const char * const cmd_quota_rescan_usage[] = {
 	NULL
 };
 
-static int cmd_quota_rescan(int argc, char **argv)
+static int cmd_quota_rescan(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
@@ -213,7 +214,7 @@ static const struct cmd_group quota_cmd_group = {
 	}
 };
 
-static int cmd_quota(int argc, char **argv)
+static int cmd_quota(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&quota_cmd_group, argc, argv);
 }
diff --git a/cmds-receive.c b/cmds-receive.c
index d88b8793..93c1838d 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1279,7 +1279,7 @@ static const char * const cmd_receive_usage[] = {
 	NULL
 };
 
-static int cmd_receive(int argc, char **argv)
+static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *tomnt = NULL;
 	char fromfile[PATH_MAX];
diff --git a/cmds-replace.c b/cmds-replace.c
index a7379c71..f1e76bdf 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -114,7 +114,8 @@ static const char *const cmd_replace_start_usage[] = {
 	NULL
 };
 
-static int cmd_replace_start(int argc, char **argv)
+static int cmd_replace_start(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	struct btrfs_ioctl_dev_replace_args start_args = {0};
 	struct btrfs_ioctl_dev_replace_args status_args = {0};
@@ -325,7 +326,8 @@ static const char *const cmd_replace_status_usage[] = {
 	NULL
 };
 
-static int cmd_replace_status(int argc, char **argv)
+static int cmd_replace_status(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	int fd;
 	int c;
@@ -494,7 +496,8 @@ static const char *const cmd_replace_cancel_usage[] = {
 	NULL
 };
 
-static int cmd_replace_cancel(int argc, char **argv)
+static int cmd_replace_cancel(const struct cmd_struct *cmd,
+			      int argc, char **argv)
 {
 	struct btrfs_ioctl_dev_replace_args args = {0};
 	int ret;
@@ -554,7 +557,7 @@ static const struct cmd_group replace_cmd_group = {
 	}
 };
 
-static int cmd_replace(int argc, char **argv)
+static int cmd_replace(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&replace_cmd_group, argc, argv);
 }
diff --git a/cmds-rescue.c b/cmds-rescue.c
index e3611f2f..f5a618e1 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -45,7 +45,8 @@ static const char * const cmd_rescue_chunk_recover_usage[] = {
 	NULL
 };
 
-static int cmd_rescue_chunk_recover(int argc, char *argv[])
+static int cmd_rescue_chunk_recover(const struct cmd_struct *cmd,
+				    int argc, char *argv[])
 {
 	int ret = 0;
 	char *file;
@@ -113,7 +114,8 @@ static const char * const cmd_rescue_super_recover_usage[] = {
  *   3 : Fail to Recover bad supeblocks
  *   4 : Abort to recover bad superblocks
  */
-static int cmd_rescue_super_recover(int argc, char **argv)
+static int cmd_rescue_super_recover(const struct cmd_struct *cmd,
+				    int argc, char **argv)
 {
 	int ret;
 	int verbose = 0;
@@ -159,7 +161,8 @@ static const char * const cmd_rescue_zero_log_usage[] = {
 	NULL
 };
 
-static int cmd_rescue_zero_log(int argc, char **argv)
+static int cmd_rescue_zero_log(const struct cmd_struct *cmd,
+			       int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_trans_handle *trans;
@@ -213,7 +216,8 @@ static const char * const cmd_rescue_fix_device_size_usage[] = {
 	NULL
 };
 
-static int cmd_rescue_fix_device_size(int argc, char **argv)
+static int cmd_rescue_fix_device_size(const struct cmd_struct *cmd,
+				      int argc, char **argv)
 {
 	struct btrfs_fs_info *fs_info;
 	char *devname;
@@ -265,7 +269,7 @@ static const struct cmd_group rescue_cmd_group = {
 	}
 };
 
-static int cmd_rescue(int argc, char **argv)
+static int cmd_rescue(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&rescue_cmd_group, argc, argv);
 }
diff --git a/cmds-restore.c b/cmds-restore.c
index f8391294..e1e58ac2 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -1422,7 +1422,7 @@ static const char * const cmd_restore_usage[] = {
 	NULL
 };
 
-static int cmd_restore(int argc, char **argv)
+static int cmd_restore(const struct cmd_struct *unused, int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_key key;
diff --git a/cmds-scrub.c b/cmds-scrub.c
index f2a579b9..a421047b 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1095,7 +1095,8 @@ static int is_scrub_running_in_kernel(int fd,
 static const char * const cmd_scrub_start_usage[];
 static const char * const cmd_scrub_resume_usage[];
 
-static int scrub_start(int argc, char **argv, int resume)
+static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
+		       bool resume)
 {
 	int fdmnt;
 	int prg_fd = -1;
@@ -1174,16 +1175,14 @@ static int scrub_start(int argc, char **argv, int resume)
 			break;
 		case '?':
 		default:
-			usage(resume ? cmd_scrub_resume_usage :
-						cmd_scrub_start_usage);
+			usage(cmd->usagestr);
 		}
 	}
 
 	/* try to catch most error cases before forking */
 
 	if (check_argc_exact(argc - optind, 1)) {
-		usage(resume ? cmd_scrub_resume_usage :
-					cmd_scrub_start_usage);
+		usage(cmd->usagestr);
 	}
 
 	spc.progress = NULL;
@@ -1574,9 +1573,9 @@ static const char * const cmd_scrub_start_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_start(int argc, char **argv)
+static int cmd_scrub_start(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(argc, argv, 0);
+	return scrub_start(cmd, argc, argv, false);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_start, "start");
 
@@ -1586,7 +1585,7 @@ static const char * const cmd_scrub_cancel_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_cancel(int argc, char **argv)
+static int cmd_scrub_cancel(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *path;
 	int ret;
@@ -1641,9 +1640,9 @@ static const char * const cmd_scrub_resume_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_resume(int argc, char **argv)
+static int cmd_scrub_resume(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(argc, argv, 1);
+	return scrub_start(cmd, argc, argv, true);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_resume, "resume");
 
@@ -1656,7 +1655,7 @@ static const char * const cmd_scrub_status_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_status(int argc, char **argv)
+static int cmd_scrub_status(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *path;
 	struct btrfs_ioctl_fs_info_args fi_args;
@@ -1802,7 +1801,7 @@ static const struct cmd_group scrub_cmd_group = {
 	}
 };
 
-static int cmd_scrub(int argc, char **argv)
+static int cmd_scrub(const struct cmd_struct *unused, int argc, char **argv)
 {
 	return handle_command_group(&scrub_cmd_group, argc, argv);
 }
diff --git a/cmds-send.c b/cmds-send.c
index f1e5124d..bd501576 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -523,7 +523,7 @@ static const char * const cmd_send_usage[] = {
 	NULL
 };
 
-static int cmd_send(int argc, char **argv)
+static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char *subvol = NULL;
 	int ret;
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 9967b6d7..f00503b5 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -90,7 +90,8 @@ static const char * const cmd_subvol_create_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_create(int argc, char **argv)
+static int cmd_subvol_create(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int	retval, res, len;
 	int	fddst = -1;
@@ -231,7 +232,8 @@ static const char * const cmd_subvol_delete_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_delete(int argc, char **argv)
+static int cmd_subvol_delete(const struct cmd_struct *cmd,
+			     int argc, char **argv)
 {
 	int res, ret = 0;
 	int cnt;
@@ -451,7 +453,7 @@ static const char * const cmd_subvol_list_usage[] = {
 	NULL,
 };
 
-static int cmd_subvol_list(int argc, char **argv)
+static int cmd_subvol_list(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	struct btrfs_list_filter_set *filter_set;
 	struct btrfs_list_comparer_set *comparer_set;
@@ -623,7 +625,8 @@ static const char * const cmd_subvol_snapshot_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_snapshot(int argc, char **argv)
+static int cmd_subvol_snapshot(const struct cmd_struct *cmd,
+			       int argc, char **argv)
 {
 	char	*subvol, *dst;
 	int	res, retval;
@@ -770,7 +773,8 @@ static const char * const cmd_subvol_get_default_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_get_default(int argc, char **argv)
+static int cmd_subvol_get_default(const struct cmd_struct *cmd,
+				  int argc, char **argv)
 {
 	int fd = -1;
 	int ret = 1;
@@ -835,7 +839,8 @@ static const char * const cmd_subvol_set_default_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_set_default(int argc, char **argv)
+static int cmd_subvol_set_default(const struct cmd_struct *cmd,
+				  int argc, char **argv)
 {
 	u64 objectid;
 	char *path;
@@ -872,7 +877,8 @@ static const char * const cmd_subvol_find_new_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_find_new(int argc, char **argv)
+static int cmd_subvol_find_new(const struct cmd_struct *cmd,
+			       int argc, char **argv)
 {
 	int fd;
 	int ret;
@@ -924,7 +930,7 @@ static const char * const cmd_subvol_show_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_show(int argc, char **argv)
+static int cmd_subvol_show(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	char tstr[256];
 	char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
@@ -1179,7 +1185,7 @@ static const char * const cmd_subvol_sync_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_sync(int argc, char **argv)
+static int cmd_subvol_sync(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int fd = -1;
 	int ret = 1;
@@ -1289,7 +1295,8 @@ static const struct cmd_group subvolume_cmd_group = {
 	}
 };
 
-static int cmd_subvolume(int argc, char **argv)
+static int cmd_subvolume(const struct cmd_struct *unused,
+			 int argc, char **argv)
 {
 	return handle_command_group(&subvolume_cmd_group, argc, argv);
 }
diff --git a/commands.h b/commands.h
index 9a65204b..4c5469ac 100644
--- a/commands.h
+++ b/commands.h
@@ -24,7 +24,7 @@ enum {
 
 struct cmd_struct {
 	const char *token;
-	int (*fn)(int, char **);
+	int (*fn)(const struct cmd_struct *cmd, int argc, char **argv);
 
 	/*
 	 * Usage strings
@@ -110,7 +110,7 @@ struct cmd_group {
 static inline int cmd_execute(const struct cmd_struct *cmd,
 			      int argc, char **argv)
 {
-	return cmd->fn(argc, argv);
+	return cmd->fn(cmd, argc, argv);
 }
 
 int handle_command_group(const struct cmd_group *grp, int argc,
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 14/18] btrfs-progs: pass cmd_struct to clean_args_no_options{,_relaxed}
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (12 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 13/18] btrfs-progs: pass cmd_struct to command callback function jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 15/18] btrfs-progs: pass cmd_struct to usage() jeffm
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

Now that we have a cmd_struct everywhere, we can pass it to
clean_args_no_options and have it resolve the usage string from
it there.  This is necessary for it to pass the cmd_struct to
usage() in the next patch.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 cmds-balance.c    |  6 +++---
 cmds-device.c     |  9 +++++----
 cmds-filesystem.c |  8 ++++----
 cmds-inspect.c    |  4 ++--
 cmds-qgroup.c     | 16 ++++++++--------
 cmds-quota.c      |  4 ++--
 cmds-rescue.c     |  4 ++--
 cmds-scrub.c      | 15 ++++++++-------
 cmds-subvolume.c  |  6 +++---
 help.c            |  9 +++++----
 help.h            |  6 ++++--
 11 files changed, 46 insertions(+), 41 deletions(-)

diff --git a/cmds-balance.c b/cmds-balance.c
index 1bd7b3ce..488fffcc 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -689,7 +689,7 @@ static int cmd_balance_pause(const struct cmd_struct *cmd,
 	int ret;
 	DIR *dirstream = NULL;
 
-	clean_args_no_options(argc, argv, cmd_balance_pause_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_balance_pause_usage);
@@ -729,7 +729,7 @@ static int cmd_balance_cancel(const struct cmd_struct *cmd,
 	int ret;
 	DIR *dirstream = NULL;
 
-	clean_args_no_options(argc, argv, cmd_balance_cancel_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_balance_cancel_usage);
@@ -770,7 +770,7 @@ static int cmd_balance_resume(const struct cmd_struct *cmd,
 	int fd;
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_balance_resume_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_balance_resume_usage);
diff --git a/cmds-device.c b/cmds-device.c
index feb53f68..5be748f7 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -149,11 +149,12 @@ static int _cmd_device_remove(const struct cmd_struct *cmd,
 	char	*mntpnt;
 	int i, fdmnt, ret = 0;
 	DIR	*dirstream = NULL;
+	const char * const *usagestr = cmd->usagestr;
 
-	clean_args_no_options(argc, argv, cmd->usagestr);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 2))
-		usage(cmd->usagestr);
+		usage(usagestr);
 
 	mntpnt = argv[argc - 1];
 
@@ -347,7 +348,7 @@ static int cmd_device_ready(const struct cmd_struct *cmd, int argc, char **argv)
 	int	ret;
 	char	*path;
 
-	clean_args_no_options(argc, argv, cmd->usagestr);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_device_ready_usage);
@@ -573,7 +574,7 @@ static int cmd_device_usage(const struct cmd_struct *cmd, int argc, char **argv)
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
-	clean_args_no_options(argc, argv, cmd->usagestr);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 1))
 		usage(cmd_device_usage_usage);
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 649d97a9..2a9f530d 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -129,7 +129,7 @@ static int cmd_filesystem_df(const struct cmd_struct *cmd,
 
 	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
 
-	clean_args_no_options(argc, argv, cmd_filesystem_df_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_filesystem_df_usage);
@@ -822,7 +822,7 @@ static int cmd_filesystem_sync(const struct cmd_struct *cmd,
 {
 	enum btrfs_util_error err;
 
-	clean_args_no_options(argc, argv, cmd_filesystem_sync_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_filesystem_sync_usage);
@@ -1095,7 +1095,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd,
 	DIR	*dirstream = NULL;
 	struct stat st;
 
-	clean_args_no_options_relaxed(argc, argv);
+	clean_args_no_options_relaxed(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
 		usage(cmd_filesystem_resize_usage);
@@ -1168,7 +1168,7 @@ static const char * const cmd_filesystem_label_usage[] = {
 static int cmd_filesystem_label(const struct cmd_struct *cmd,
 				int argc, char **argv)
 {
-	clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 1) ||
 			check_argc_max(argc - optind, 2))
diff --git a/cmds-inspect.c b/cmds-inspect.c
index 46ea5551..b6d045a3 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -277,7 +277,7 @@ static int cmd_inspect_subvolid_resolve(const struct cmd_struct *cmd,
 	char path[PATH_MAX];
 	DIR *dirstream = NULL;
 
-	clean_args_no_options(argc, argv, cmd_inspect_subvolid_resolve_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
 		usage(cmd_inspect_subvolid_resolve_usage);
@@ -320,7 +320,7 @@ static int cmd_inspect_rootid(const struct cmd_struct *cmd,
 	u64 rootid;
 	DIR *dirstream = NULL;
 
-	clean_args_no_options(argc, argv, cmd_inspect_rootid_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_inspect_rootid_usage);
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 5426c8fe..2b220224 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -35,8 +35,8 @@ static const char * const qgroup_cmd_group_usage[] = {
 	NULL
 };
 
-static int _cmd_qgroup_assign(int assign, int argc, char **argv,
-		const char * const *usage_str)
+static int _cmd_qgroup_assign(const struct cmd_struct *cmd, int assign,
+			      int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
@@ -72,11 +72,11 @@ static int _cmd_qgroup_assign(int assign, int argc, char **argv,
 			}
 		}
 	} else {
-		clean_args_no_options(argc, argv, usage_str);
+		clean_args_no_options(cmd, argc, argv);
 	}
 
 	if (check_argc_exact(argc - optind, 3))
-		usage(usage_str);
+		usage(cmd->usagestr);
 
 	memset(&args, 0, sizeof(args));
 	args.assign = assign;
@@ -220,7 +220,7 @@ static const char * const cmd_qgroup_assign_usage[] = {
 static int cmd_qgroup_assign(const struct cmd_struct *cmd,
 			     int argc, char **argv)
 {
-	return _cmd_qgroup_assign(1, argc, argv, cmd_qgroup_assign_usage);
+	return _cmd_qgroup_assign(cmd, 1, argc, argv);
 }
 static DEFINE_SIMPLE_COMMAND(qgroup_assign, "assign");
 
@@ -233,7 +233,7 @@ static const char * const cmd_qgroup_remove_usage[] = {
 static int cmd_qgroup_remove(const struct cmd_struct *cmd,
 			     int argc, char **argv)
 {
-	return _cmd_qgroup_assign(0, argc, argv, cmd_qgroup_remove_usage);
+	return _cmd_qgroup_assign(cmd, 0, argc, argv);
 }
 static DEFINE_SIMPLE_COMMAND(qgroup_remove, "remove");
 
@@ -248,7 +248,7 @@ static int cmd_qgroup_create(const struct cmd_struct *cmd,
 {
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_qgroup_create_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	ret = _cmd_qgroup_create(1, argc, argv);
 
@@ -269,7 +269,7 @@ static int cmd_qgroup_destroy(const struct cmd_struct *cmd,
 {
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_qgroup_destroy_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	ret = _cmd_qgroup_create(0, argc, argv);
 
diff --git a/cmds-quota.c b/cmds-quota.c
index a6e7a6f6..23757f9a 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -71,7 +71,7 @@ static int cmd_quota_enable(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_quota_enable_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	ret = quota_ctl(BTRFS_QUOTA_CTL_ENABLE, argc, argv);
 
@@ -92,7 +92,7 @@ static int cmd_quota_disable(const struct cmd_struct *cmd,
 {
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_quota_disable_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	ret = quota_ctl(BTRFS_QUOTA_CTL_DISABLE, argc, argv);
 
diff --git a/cmds-rescue.c b/cmds-rescue.c
index f5a618e1..975ff05a 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -170,7 +170,7 @@ static int cmd_rescue_zero_log(const struct cmd_struct *cmd,
 	char *devname;
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_rescue_zero_log_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc, 2))
 		usage(cmd_rescue_zero_log_usage);
@@ -223,7 +223,7 @@ static int cmd_rescue_fix_device_size(const struct cmd_struct *cmd,
 	char *devname;
 	int ret;
 
-	clean_args_no_options(argc, argv, cmd_rescue_fix_device_size_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc, 2))
 		usage(cmd_rescue_fix_device_size_usage);
diff --git a/cmds-scrub.c b/cmds-scrub.c
index a421047b..b07ff2e3 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1095,8 +1095,7 @@ static int is_scrub_running_in_kernel(int fd,
 static const char * const cmd_scrub_start_usage[];
 static const char * const cmd_scrub_resume_usage[];
 
-static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
-		       bool resume)
+static int scrub_start(int argc, char **argv, bool resume)
 {
 	int fdmnt;
 	int prg_fd = -1;
@@ -1175,14 +1174,16 @@ static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
 			break;
 		case '?':
 		default:
-			usage(cmd->usagestr);
+			usage(resume ? cmd_scrub_resume_usage :
+						cmd_scrub_start_usage);
 		}
 	}
 
 	/* try to catch most error cases before forking */
 
 	if (check_argc_exact(argc - optind, 1)) {
-		usage(cmd->usagestr);
+		usage(resume ? cmd_scrub_resume_usage :
+					cmd_scrub_start_usage);
 	}
 
 	spc.progress = NULL;
@@ -1575,7 +1576,7 @@ static const char * const cmd_scrub_start_usage[] = {
 
 static int cmd_scrub_start(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(cmd, argc, argv, false);
+	return scrub_start(argc, argv, false);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_start, "start");
 
@@ -1592,7 +1593,7 @@ static int cmd_scrub_cancel(const struct cmd_struct *cmd, int argc, char **argv)
 	int fdmnt = -1;
 	DIR *dirstream = NULL;
 
-	clean_args_no_options(argc, argv, cmd_scrub_cancel_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_scrub_cancel_usage);
@@ -1642,7 +1643,7 @@ static const char * const cmd_scrub_resume_usage[] = {
 
 static int cmd_scrub_resume(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(cmd, argc, argv, true);
+	return scrub_start(argc, argv, true);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_resume, "resume");
 
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index f00503b5..dc065ea7 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -784,7 +784,7 @@ static int cmd_subvol_get_default(const struct cmd_struct *cmd,
 	struct btrfs_util_subvolume_info subvol;
 	char *path;
 
-	clean_args_no_options(argc, argv, cmd_subvol_get_default_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_subvol_get_default_usage);
@@ -846,7 +846,7 @@ static int cmd_subvol_set_default(const struct cmd_struct *cmd,
 	char *path;
 	enum btrfs_util_error err;
 
-	clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 1) ||
 			check_argc_max(argc - optind, 2))
@@ -887,7 +887,7 @@ static int cmd_subvol_find_new(const struct cmd_struct *cmd,
 	DIR *dirstream = NULL;
 	enum btrfs_util_error err;
 
-	clean_args_no_options(argc, argv, cmd_subvol_find_new_usage);
+	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
 		usage(cmd_subvol_find_new_usage);
diff --git a/help.c b/help.c
index 2c0d8d71..23d6ea8f 100644
--- a/help.c
+++ b/help.c
@@ -86,7 +86,7 @@ int check_argc_max(int nargs, int expected)
  * Unknown short and long options are reported, optionally the @usage is printed
  * before exit.
  */
-void clean_args_no_options(int argc, char *argv[], const char * const *usagestr)
+void clean_args_no_options(const struct cmd_struct *cmd, int argc, char *argv[])
 {
 	static const struct option long_options[] = {
 		{NULL, 0, NULL, 0}
@@ -100,8 +100,8 @@ void clean_args_no_options(int argc, char *argv[], const char * const *usagestr)
 
 		switch (c) {
 		default:
-			if (usagestr)
-				usage(usagestr);
+			if (cmd->usagestr)
+				usage(cmd->usagestr);
 		}
 	}
 }
@@ -115,7 +115,8 @@ void clean_args_no_options(int argc, char *argv[], const char * const *usagestr)
  * - "-- option1 option2 ..."
  * - "option1 option2 ..."
  */
-void clean_args_no_options_relaxed(int argc, char *argv[])
+void clean_args_no_options_relaxed(const struct cmd_struct *cmd,
+				   int argc, char *argv[])
 {
 	if (argc <= 1)
 		return;
diff --git a/help.h b/help.h
index 322b910a..e642f58d 100644
--- a/help.h
+++ b/help.h
@@ -71,8 +71,10 @@ void help_command_group(const struct cmd_group *grp, int argc, char **argv);
 int check_argc_exact(int nargs, int expected);
 int check_argc_min(int nargs, int expected);
 int check_argc_max(int nargs, int expected);
-void clean_args_no_options(int argc, char *argv[], const char * const *usage);
-void clean_args_no_options_relaxed(int argc, char *argv[]);
+void clean_args_no_options(const struct cmd_struct *cmd,
+			   int argc, char *argv[]);
+void clean_args_no_options_relaxed(const struct cmd_struct *cmd,
+				   int argc, char *argv[]);
 
 void fixup_argv0(char **argv, const char *token);
 void set_argv0(char **argv);
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 15/18] btrfs-progs: pass cmd_struct to usage()
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (13 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 14/18] btrfs-progs: pass cmd_struct to clean_args_no_options{,_relaxed} jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 16/18] btrfs-progs: add support for output formats jeffm
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

Now that every call site has a cmd_struct, we can just pass the cmd_struct
to usage to print the usager information.  This allows us to interpret
the format flags we'll add later in this series to inform the user of
which output formats any given command supports.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 check/main.c              |  4 ++--
 cmds-balance.c            | 14 +++++++-------
 cmds-device.c             | 19 +++++++++----------
 cmds-fi-du.c              |  4 ++--
 cmds-fi-usage.c           |  4 ++--
 cmds-filesystem.c         | 18 +++++++++---------
 cmds-inspect-dump-super.c |  4 ++--
 cmds-inspect-dump-tree.c  |  4 ++--
 cmds-inspect-tree-stats.c |  4 ++--
 cmds-inspect.c            | 16 ++++++++--------
 cmds-property.c           | 22 +++++++++-------------
 cmds-qgroup.c             | 18 +++++++++---------
 cmds-quota.c              |  8 ++++----
 cmds-receive.c            |  4 ++--
 cmds-replace.c            | 12 ++++++------
 cmds-rescue.c             | 12 ++++++------
 cmds-restore.c            |  8 ++++----
 cmds-scrub.c              | 25 ++++++++++---------------
 cmds-send.c               |  2 +-
 cmds-subvolume.c          | 30 +++++++++++++++---------------
 help.c                    |  6 +++---
 help.h                    |  2 +-
 22 files changed, 115 insertions(+), 125 deletions(-)

diff --git a/check/main.c b/check/main.c
index 0375eec3..49ccdf2f 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9483,7 +9483,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
 				break;
 			case '?':
 			case 'h':
-				usage(cmd_check_usage);
+				usage(cmd);
 			case GETOPT_VAL_REPAIR:
 				printf("enabling repair mode\n");
 				repair = 1;
@@ -9534,7 +9534,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_check_usage);
+		usage(cmd);
 
 	if (ctx.progress_enabled) {
 		ctx.tp = TASK_NOTHING;
diff --git a/cmds-balance.c b/cmds-balance.c
index 488fffcc..c639459f 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -585,12 +585,12 @@ static int cmd_balance_start(const struct cmd_struct *cmd,
 			background = 1;
 			break;
 		default:
-			usage(cmd_balance_start_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_balance_start_usage);
+		usage(cmd);
 
 	/*
 	 * allow -s only under --force, otherwise do with system chunks
@@ -692,7 +692,7 @@ static int cmd_balance_pause(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_balance_pause_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
@@ -732,7 +732,7 @@ static int cmd_balance_cancel(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_balance_cancel_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
@@ -773,7 +773,7 @@ static int cmd_balance_resume(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_balance_resume_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
@@ -856,12 +856,12 @@ static int cmd_balance_status(const struct cmd_struct *cmd,
 			verbose = 1;
 			break;
 		default:
-			usage(cmd_balance_status_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_balance_status_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
diff --git a/cmds-device.c b/cmds-device.c
index 5be748f7..6c74ca8e 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -77,12 +77,12 @@ static int cmd_device_add(const struct cmd_struct *cmd,
 			force = 1;
 			break;
 		default:
-			usage(cmd_device_add_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 2))
-		usage(cmd_device_add_usage);
+		usage(cmd);
 
 	last_dev = argc - 1;
 	mntpnt = argv[last_dev];
@@ -149,12 +149,11 @@ static int _cmd_device_remove(const struct cmd_struct *cmd,
 	char	*mntpnt;
 	int i, fdmnt, ret = 0;
 	DIR	*dirstream = NULL;
-	const char * const *usagestr = cmd->usagestr;
 
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 2))
-		usage(usagestr);
+		usage(cmd);
 
 	mntpnt = argv[argc - 1];
 
@@ -290,13 +289,13 @@ static int cmd_device_scan(const struct cmd_struct *cmd, int argc, char **argv)
 			all = 1;
 			break;
 		default:
-			usage(cmd_device_scan_usage);
+			usage(cmd);
 		}
 	}
 	devstart = optind;
 
 	if (all && check_argc_max(argc - optind, 1))
-		usage(cmd_device_scan_usage);
+		usage(cmd);
 
 	if (all || argc - optind == 0) {
 		printf("Scanning for Btrfs filesystems\n");
@@ -351,7 +350,7 @@ static int cmd_device_ready(const struct cmd_struct *cmd, int argc, char **argv)
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_device_ready_usage);
+		usage(cmd);
 
 	fd = open("/dev/btrfs-control", O_RDWR);
 	if (fd < 0) {
@@ -434,12 +433,12 @@ static int cmd_device_stats(const struct cmd_struct *cmd, int argc, char **argv)
 			break;
 		case '?':
 		default:
-			usage(cmd_device_stats_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_device_stats_usage);
+		usage(cmd);
 
 	dev_path = argv[optind];
 
@@ -577,7 +576,7 @@ static int cmd_device_usage(const struct cmd_struct *cmd, int argc, char **argv)
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_device_usage_usage);
+		usage(cmd);
 
 	for (i = optind; i < argc; i++) {
 		int fd;
diff --git a/cmds-fi-du.c b/cmds-fi-du.c
index 67d65519..9635866a 100644
--- a/cmds-fi-du.c
+++ b/cmds-fi-du.c
@@ -580,12 +580,12 @@ static int cmd_filesystem_du(const struct cmd_struct *cmd,
 			summarize = 1;
 			break;
 		default:
-			usage(cmd_filesystem_du_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_filesystem_du_usage);
+		usage(cmd);
 
 	kernel_version = get_running_kernel_version();
 
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index c01b677a..a14d0017 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -987,12 +987,12 @@ static int cmd_filesystem_usage(const struct cmd_struct *cmd,
 			tabular = 1;
 			break;
 		default:
-			usage(cmd_filesystem_usage_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_filesystem_usage_usage);
+		usage(cmd);
 
 	for (i = optind; i < argc; i++) {
 		int fd;
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 2a9f530d..d8290968 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -132,7 +132,7 @@ static int cmd_filesystem_df(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_filesystem_df_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
@@ -707,17 +707,17 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
 			where = BTRFS_SCAN_MOUNTED;
 			break;
 		default:
-			usage(cmd_filesystem_show_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_max(argc, optind + 1))
-		usage(cmd_filesystem_show_usage);
+		usage(cmd);
 
 	if (argc > optind) {
 		search = argv[optind];
 		if (*search == 0)
-			usage(cmd_filesystem_show_usage);
+			usage(cmd);
 		type = check_arg_type(search);
 
 		/*
@@ -825,7 +825,7 @@ static int cmd_filesystem_sync(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_filesystem_sync_usage);
+		usage(cmd);
 
 	err = btrfs_util_sync(argv[optind]);
 	if (err) {
@@ -967,12 +967,12 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
 			recursive = 1;
 			break;
 		default:
-			usage(cmd_filesystem_defrag_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_filesystem_defrag_usage);
+		usage(cmd);
 
 	memset(&defrag_global_range, 0, sizeof(defrag_global_range));
 	defrag_global_range.start = start;
@@ -1098,7 +1098,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd,
 	clean_args_no_options_relaxed(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_filesystem_resize_usage);
+		usage(cmd);
 
 	amount = argv[optind];
 	path = argv[optind + 1];
@@ -1172,7 +1172,7 @@ static int cmd_filesystem_label(const struct cmd_struct *cmd,
 
 	if (check_argc_min(argc - optind, 1) ||
 			check_argc_max(argc - optind, 2))
-		usage(cmd_filesystem_label_usage);
+		usage(cmd);
 
 	if (argc - optind > 1) {
 		return set_label(argv[optind], argv[optind + 1]);
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index 49df12eb..bc2eedb5 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -576,12 +576,12 @@ static int cmd_inspect_dump_super(const struct cmd_struct *cmd,
 			all = 0;
 			break;
 		default:
-			usage(cmd_inspect_dump_super_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_inspect_dump_super_usage);
+		usage(cmd);
 
 	for (i = optind; i < argc; i++) {
 		filename = argv[i];
diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index 97f5ea46..b4f413a4 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -304,12 +304,12 @@ static int cmd_inspect_dump_tree(const struct cmd_struct *cmd,
 			follow = true;
 			break;
 		default:
-			usage(cmd_inspect_dump_tree_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_inspect_dump_tree_usage);
+		usage(cmd);
 
 	ret = check_arg_type(argv[optind]);
 	if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) {
diff --git a/cmds-inspect-tree-stats.c b/cmds-inspect-tree-stats.c
index 64ca3d0b..e5e68562 100644
--- a/cmds-inspect-tree-stats.c
+++ b/cmds-inspect-tree-stats.c
@@ -444,12 +444,12 @@ static int cmd_inspect_tree_stats(const struct cmd_struct *cmd,
 			no_pretty = 1;
 			break;
 		default:
-			usage(cmd_inspect_tree_stats_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1)) {
-		usage(cmd_inspect_tree_stats_usage);
+		usage(cmd);
 	}
 
 	ret = check_mounted(argv[optind]);
diff --git a/cmds-inspect.c b/cmds-inspect.c
index b6d045a3..b191939c 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -105,12 +105,12 @@ static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
 			verbose = 1;
 			break;
 		default:
-			usage(cmd_inspect_inode_resolve_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_inspect_inode_resolve_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(argv[optind + 1], &dirstream, 1);
 	if (fd < 0)
@@ -167,12 +167,12 @@ static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
 			size = arg_strtou64(optarg);
 			break;
 		default:
-			usage(cmd_inspect_logical_resolve_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_inspect_logical_resolve_usage);
+		usage(cmd);
 
 	size = min(size, (u64)SZ_64K);
 	inodes = malloc(size);
@@ -280,7 +280,7 @@ static int cmd_inspect_subvolid_resolve(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_inspect_subvolid_resolve_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(argv[optind + 1], &dirstream, 1);
 	if (fd < 0) {
@@ -323,7 +323,7 @@ static int cmd_inspect_rootid(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_inspect_rootid_usage);
+		usage(cmd);
 
 	fd = btrfs_open_file_or_dir(argv[optind], &dirstream, 1);
 	if (fd < 0) {
@@ -617,11 +617,11 @@ static int cmd_inspect_min_dev_size(const struct cmd_struct *cmd,
 			devid = arg_strtou64(optarg);
 			break;
 		default:
-			usage(cmd_inspect_min_dev_size_usage);
+			usage(cmd);
 		}
 	}
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_inspect_min_dev_size_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(argv[optind], &dirstream, 1);
 	if (fd < 0) {
diff --git a/cmds-property.c b/cmds-property.c
index 5684443c..4aa2f18f 100644
--- a/cmds-property.c
+++ b/cmds-property.c
@@ -256,8 +256,7 @@ out:
 
 }
 
-static void parse_args(int argc, char **argv,
-		       const char * const *usage_str,
+static void parse_args(const struct cmd_struct *cmd, int argc, char **argv,
 		       int *types, char **object,
 		       char **name, char **value, int min_nonopt_args)
 {
@@ -276,7 +275,7 @@ static void parse_args(int argc, char **argv,
 			type_str = optarg;
 			break;
 		default:
-			usage(usage_str);
+			usage(cmd);
 		}
 	}
 
@@ -287,7 +286,7 @@ static void parse_args(int argc, char **argv,
 
 	if (check_argc_min(argc - optind, min_nonopt_args) ||
 	    check_argc_max(argc - optind, max_nonopt_args))
-		usage(usage_str);
+		usage(cmd);
 
 	*types = 0;
 	if (type_str) {
@@ -304,7 +303,7 @@ static void parse_args(int argc, char **argv,
 			*types = prop_object_dev;
 		} else {
 			error("invalid object type: %s", type_str);
-			usage(usage_str);
+			usage(cmd);
 		}
 	}
 
@@ -319,11 +318,11 @@ static void parse_args(int argc, char **argv,
 		if (ret < 0) {
 			error("failed to detect object type: %s",
 				strerror(-ret));
-			usage(usage_str);
+			usage(cmd);
 		}
 		if (!*types) {
 			error("object is not a btrfs object: %s", *object);
-			usage(usage_str);
+			usage(cmd);
 		}
 	}
 }
@@ -349,8 +348,7 @@ static int cmd_property_get(const struct cmd_struct *cmd,
 	char *name = NULL;
 	int types = 0;
 
-	parse_args(argc, argv, cmd_property_get_usage, &types, &object, &name,
-		   NULL, 1);
+	parse_args(cmd, argc, argv, &types, &object, &name, NULL, 1);
 
 	if (name)
 		ret = setget_prop(types, object, name, NULL);
@@ -378,8 +376,7 @@ static int cmd_property_set(const struct cmd_struct *cmd,
 	char *value = NULL;
 	int types = 0;
 
-	parse_args(argc, argv, cmd_property_set_usage, &types,
-		   &object, &name, &value, 3);
+	parse_args(cmd, argc, argv, &types, &object, &name, &value, 3);
 
 	ret = setget_prop(types, object, name, value);
 
@@ -402,8 +399,7 @@ static int cmd_property_list(const struct cmd_struct *cmd,
 	char *object = NULL;
 	int types = 0;
 
-	parse_args(argc, argv, cmd_property_list_usage,
-		   &types, &object, NULL, NULL, 1);
+	parse_args(cmd, argc, argv, &types, &object, NULL, NULL, 1);
 
 	ret = dump_props(types, object, 1);
 
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 2b220224..0ee578ff 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -76,7 +76,7 @@ static int _cmd_qgroup_assign(const struct cmd_struct *cmd, int assign,
 	}
 
 	if (check_argc_exact(argc - optind, 3))
-		usage(cmd->usagestr);
+		usage(cmd);
 
 	memset(&args, 0, sizeof(args));
 	args.assign = assign;
@@ -253,7 +253,7 @@ static int cmd_qgroup_create(const struct cmd_struct *cmd,
 	ret = _cmd_qgroup_create(1, argc, argv);
 
 	if (ret < 0)
-		usage(cmd_qgroup_create_usage);
+		usage(cmd);
 	return ret;
 }
 static DEFINE_SIMPLE_COMMAND(qgroup_create, "create");
@@ -274,7 +274,7 @@ static int cmd_qgroup_destroy(const struct cmd_struct *cmd,
 	ret = _cmd_qgroup_create(0, argc, argv);
 
 	if (ret < 0)
-		usage(cmd_qgroup_destroy_usage);
+		usage(cmd);
 	return ret;
 }
 static DEFINE_SIMPLE_COMMAND(qgroup_destroy, "destroy");
@@ -369,7 +369,7 @@ static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
 			ret = btrfs_qgroup_parse_sort_string(optarg,
 							     &comparer_set);
 			if (ret)
-				usage(cmd_qgroup_show_usage);
+				usage(cmd);
 			break;
 		case GETOPT_VAL_SYNC:
 			sync = 1;
@@ -378,13 +378,13 @@ static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
 			verbose = true;
 			break;
 		default:
-			usage(cmd_qgroup_show_usage);
+			usage(cmd);
 		}
 	}
 	btrfs_qgroup_setup_units(unit_mode);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_qgroup_show_usage);
+		usage(cmd);
 
 	path = argv[optind];
 	fd = btrfs_open_dir(path, &dirstream, 1);
@@ -462,12 +462,12 @@ static int cmd_qgroup_limit(const struct cmd_struct *cmd, int argc, char **argv)
 			exclusive = 1;
 			break;
 		default:
-			usage(cmd_qgroup_limit_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 2))
-		usage(cmd_qgroup_limit_usage);
+		usage(cmd);
 
 	if (!parse_limit(argv[optind], &size)) {
 		error("invalid size argument: %s", argv[optind]);
@@ -502,7 +502,7 @@ static int cmd_qgroup_limit(const struct cmd_struct *cmd, int argc, char **argv)
 		args.qgroupid = parse_qgroupid(argv[optind + 1]);
 		path = argv[optind + 2];
 	} else
-		usage(cmd_qgroup_limit_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(path, &dirstream, 1);
 	if (fd < 0)
diff --git a/cmds-quota.c b/cmds-quota.c
index 23757f9a..c634c4e9 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -76,7 +76,7 @@ static int cmd_quota_enable(const struct cmd_struct *cmd, int argc, char **argv)
 	ret = quota_ctl(BTRFS_QUOTA_CTL_ENABLE, argc, argv);
 
 	if (ret < 0)
-		usage(cmd_quota_enable_usage);
+		usage(cmd);
 	return ret;
 }
 static DEFINE_SIMPLE_COMMAND(quota_enable, "enable");
@@ -97,7 +97,7 @@ static int cmd_quota_disable(const struct cmd_struct *cmd,
 	ret = quota_ctl(BTRFS_QUOTA_CTL_DISABLE, argc, argv);
 
 	if (ret < 0)
-		usage(cmd_quota_disable_usage);
+		usage(cmd);
 	return ret;
 }
 static DEFINE_SIMPLE_COMMAND(quota_disable, "disable");
@@ -140,7 +140,7 @@ static int cmd_quota_rescan(const struct cmd_struct *cmd, int argc, char **argv)
 			wait_for_completion = 1;
 			break;
 		default:
-			usage(cmd_quota_rescan_usage);
+			usage(cmd);
 		}
 	}
 
@@ -150,7 +150,7 @@ static int cmd_quota_rescan(const struct cmd_struct *cmd, int argc, char **argv)
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_quota_rescan_usage);
+		usage(cmd);
 
 	memset(&args, 0, sizeof(args));
 
diff --git a/cmds-receive.c b/cmds-receive.c
index 93c1838d..5429c607 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1352,9 +1352,9 @@ static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
 	}
 
 	if (dump && check_argc_exact(argc - optind, 0))
-		usage(cmd_receive_usage);
+		usage(cmd);
 	if (!dump && check_argc_exact(argc - optind, 1))
-		usage(cmd_receive_usage);
+		usage(cmd);
 
 	tomnt = argv[optind];
 
diff --git a/cmds-replace.c b/cmds-replace.c
index f1e76bdf..2057d69e 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -148,7 +148,7 @@ static int cmd_replace_start(const struct cmd_struct *cmd,
 			break;
 		case '?':
 		default:
-			usage(cmd_replace_start_usage);
+			usage(cmd);
 		}
 	}
 
@@ -157,7 +157,7 @@ static int cmd_replace_start(const struct cmd_struct *cmd,
 		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID :
 		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;
 	if (check_argc_exact(argc - optind, 3))
-		usage(cmd_replace_start_usage);
+		usage(cmd);
 	path = argv[optind + 2];
 
 	fdmnt = open_path_or_dev_mnt(path, &dirstream, 1);
@@ -343,12 +343,12 @@ static int cmd_replace_status(const struct cmd_struct *cmd,
 			break;
 		case '?':
 		default:
-			usage(cmd_replace_status_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_replace_status_usage);
+		usage(cmd);
 
 	path = argv[optind];
 	fd = btrfs_open_dir(path, &dirstream, 1);
@@ -510,12 +510,12 @@ static int cmd_replace_cancel(const struct cmd_struct *cmd,
 		switch (c) {
 		case '?':
 		default:
-			usage(cmd_replace_cancel_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_replace_cancel_usage);
+		usage(cmd);
 
 	path = argv[optind];
 	fd = btrfs_open_dir(path, &dirstream, 1);
diff --git a/cmds-rescue.c b/cmds-rescue.c
index 975ff05a..f96d8010 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -66,12 +66,12 @@ static int cmd_rescue_chunk_recover(const struct cmd_struct *cmd,
 			break;
 		case 'h':
 		default:
-			usage(cmd_rescue_chunk_recover_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_rescue_chunk_recover_usage);
+		usage(cmd);
 
 	file = argv[optind];
 
@@ -134,11 +134,11 @@ static int cmd_rescue_super_recover(const struct cmd_struct *cmd,
 			yes = 1;
 			break;
 		default:
-			usage(cmd_rescue_super_recover_usage);
+			usage(cmd);
 		}
 	}
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_rescue_super_recover_usage);
+		usage(cmd);
 
 	dname = argv[optind];
 	ret = check_mounted(dname);
@@ -173,7 +173,7 @@ static int cmd_rescue_zero_log(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc, 2))
-		usage(cmd_rescue_zero_log_usage);
+		usage(cmd);
 
 	devname = argv[optind];
 	ret = check_mounted(devname);
@@ -226,7 +226,7 @@ static int cmd_rescue_fix_device_size(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc, 2))
-		usage(cmd_rescue_fix_device_size_usage);
+		usage(cmd);
 
 	devname = argv[optind];
 	ret = check_mounted(devname);
diff --git a/cmds-restore.c b/cmds-restore.c
index e1e58ac2..0afcc376 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -1422,7 +1422,7 @@ static const char * const cmd_restore_usage[] = {
 	NULL
 };
 
-static int cmd_restore(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_restore(const struct cmd_struct *cmd, int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_key key;
@@ -1525,14 +1525,14 @@ static int cmd_restore(const struct cmd_struct *unused, int argc, char **argv)
 				get_xattrs = 1;
 				break;
 			default:
-				usage(cmd_restore_usage);
+				usage(cmd);
 		}
 	}
 
 	if (!list_roots && check_argc_min(argc - optind, 2))
-		usage(cmd_restore_usage);
+		usage(cmd);
 	else if (list_roots && check_argc_min(argc - optind, 1))
-		usage(cmd_restore_usage);
+		usage(cmd);
 
 	if (fs_location && root_objectid) {
 		fprintf(stderr, "don't use -f and -r at the same time.\n");
diff --git a/cmds-scrub.c b/cmds-scrub.c
index b07ff2e3..d3ca59a9 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1092,10 +1092,8 @@ static int is_scrub_running_in_kernel(int fd,
 	return 0;
 }
 
-static const char * const cmd_scrub_start_usage[];
-static const char * const cmd_scrub_resume_usage[];
-
-static int scrub_start(int argc, char **argv, bool resume)
+static int scrub_start(const struct cmd_struct *cmd, int argc, char **argv,
+		       bool resume)
 {
 	int fdmnt;
 	int prg_fd = -1;
@@ -1174,17 +1172,14 @@ static int scrub_start(int argc, char **argv, bool resume)
 			break;
 		case '?':
 		default:
-			usage(resume ? cmd_scrub_resume_usage :
-						cmd_scrub_start_usage);
+			usage(cmd);
 		}
 	}
 
 	/* try to catch most error cases before forking */
 
-	if (check_argc_exact(argc - optind, 1)) {
-		usage(resume ? cmd_scrub_resume_usage :
-					cmd_scrub_start_usage);
-	}
+	if (check_argc_exact(argc - optind, 1))
+		usage(cmd);
 
 	spc.progress = NULL;
 	if (do_quiet && do_print)
@@ -1576,7 +1571,7 @@ static const char * const cmd_scrub_start_usage[] = {
 
 static int cmd_scrub_start(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(argc, argv, false);
+	return scrub_start(cmd, argc, argv, false);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_start, "start");
 
@@ -1596,7 +1591,7 @@ static int cmd_scrub_cancel(const struct cmd_struct *cmd, int argc, char **argv)
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_scrub_cancel_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
@@ -1643,7 +1638,7 @@ static const char * const cmd_scrub_resume_usage[] = {
 
 static int cmd_scrub_resume(const struct cmd_struct *cmd, int argc, char **argv)
 {
-	return scrub_start(argc, argv, true);
+	return scrub_start(cmd, argc, argv, true);
 }
 static DEFINE_SIMPLE_COMMAND(scrub_resume, "resume");
 
@@ -1689,12 +1684,12 @@ static int cmd_scrub_status(const struct cmd_struct *cmd, int argc, char **argv)
 			break;
 		case '?':
 		default:
-			usage(cmd_scrub_status_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_scrub_status_usage);
+		usage(cmd);
 
 	path = argv[optind];
 
diff --git a/cmds-send.c b/cmds-send.c
index bd501576..e2d87785 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -643,7 +643,7 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_send_usage);
+		usage(cmd);
 
 	if (outname[0]) {
 		int tmpfd;
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index dc065ea7..6b01569f 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -124,12 +124,12 @@ static int cmd_subvol_create(const struct cmd_struct *cmd,
 			}
 			break;
 		default:
-			usage(cmd_subvol_create_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_subvol_create_usage);
+		usage(cmd);
 
 	dst = argv[optind];
 
@@ -275,12 +275,12 @@ static int cmd_subvol_delete(const struct cmd_struct *cmd,
 			verbose++;
 			break;
 		default:
-			usage(cmd_subvol_delete_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_subvol_delete_usage);
+		usage(cmd);
 
 	if (verbose > 0) {
 		printf("Transaction commit: %s\n",
@@ -607,7 +607,7 @@ out:
 	if (comparer_set)
 		free(comparer_set);
 	if (uerr)
-		usage(cmd_subvol_list_usage);
+		usage(cmd);
 	return !!ret;
 }
 static DEFINE_SIMPLE_COMMAND(subvol_list, "list");
@@ -673,12 +673,12 @@ static int cmd_subvol_snapshot(const struct cmd_struct *cmd,
 			}
 			break;
 		default:
-			usage(cmd_subvol_snapshot_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_subvol_snapshot_usage);
+		usage(cmd);
 
 	subvol = argv[optind];
 	dst = argv[optind + 1];
@@ -787,7 +787,7 @@ static int cmd_subvol_get_default(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_subvol_get_default_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(argv[1], &dirstream, 1);
 	if (fd < 0)
@@ -850,7 +850,7 @@ static int cmd_subvol_set_default(const struct cmd_struct *cmd,
 
 	if (check_argc_min(argc - optind, 1) ||
 			check_argc_max(argc - optind, 2))
-		usage(cmd_subvol_set_default_usage);
+		usage(cmd);
 
 	if (argc - optind == 1) {
 		/* path to the subvolume is specified */
@@ -890,7 +890,7 @@ static int cmd_subvol_find_new(const struct cmd_struct *cmd,
 	clean_args_no_options(cmd, argc, argv);
 
 	if (check_argc_exact(argc - optind, 2))
-		usage(cmd_subvol_find_new_usage);
+		usage(cmd);
 
 	subvol = argv[optind];
 	last_gen = arg_strtou64(argv[optind + 1]);
@@ -976,17 +976,17 @@ static int cmd_subvol_show(const struct cmd_struct *cmd, int argc, char **argv)
 			by_uuid = 1;
 			break;
 		default:
-			usage(cmd_subvol_show_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_exact(argc - optind, 1))
-		usage(cmd_subvol_show_usage);
+		usage(cmd);
 
 	if (by_rootid && by_uuid) {
 		error(
 		"options --rootid and --uuid cannot be used at the same time");
-		usage(cmd_subvol_show_usage);
+		usage(cmd);
 	}
 
 	fullpath = realpath(argv[optind], NULL);
@@ -1211,12 +1211,12 @@ static int cmd_subvol_sync(const struct cmd_struct *cmd, int argc, char **argv)
 			}
 			break;
 		default:
-			usage(cmd_subvol_sync_usage);
+			usage(cmd);
 		}
 	}
 
 	if (check_argc_min(argc - optind, 1))
-		usage(cmd_subvol_sync_usage);
+		usage(cmd);
 
 	fd = btrfs_open_dir(argv[optind], &dirstream, 1);
 	if (fd < 0) {
diff --git a/help.c b/help.c
index 23d6ea8f..6ee93161 100644
--- a/help.c
+++ b/help.c
@@ -101,7 +101,7 @@ void clean_args_no_options(const struct cmd_struct *cmd, int argc, char *argv[])
 		switch (c) {
 		default:
 			if (cmd->usagestr)
-				usage(cmd->usagestr);
+				usage(cmd);
 		}
 	}
 }
@@ -240,9 +240,9 @@ void usage_command(const struct cmd_struct *cmd, bool full, bool err)
 }
 
 __attribute__((noreturn))
-void usage(const char * const *usagestr)
+void usage(const struct cmd_struct *cmd)
 {
-	usage_command_usagestr(usagestr, NULL, true, true);
+	usage_command_usagestr(cmd->usagestr, NULL, true, true);
 	exit(1);
 }
 
diff --git a/help.h b/help.h
index e642f58d..7468cf8b 100644
--- a/help.h
+++ b/help.h
@@ -56,7 +56,7 @@ struct cmd_struct;
 struct cmd_group;
 
 __attribute__((noreturn))
-void usage(const char * const *usagestr);
+void usage(const struct cmd_struct *cmd);
 void usage_command(const struct cmd_struct *cmd, bool full, bool err);
 void usage_command_group(const struct cmd_group *grp, bool all, bool err);
 void usage_command_group_short(const struct cmd_group *grp);
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 16/18] btrfs-progs: add support for output formats
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (14 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 15/18] btrfs-progs: pass cmd_struct to usage() jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 17/18] btrfs-progs: handle command groups directly for common case jeffm
  2018-05-16 21:38 ` [PATCH 18/18] btrfs-progs: qgroups: don't print dead qgroups jeffm
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

This adds a global --format option to request extended output formats
from each command.  Most of it is plumbing a new cmd_context structure
that's established at the beginning of argument parsing into the command
callbacks.  That structure currently only contains the output mode enum.

We currently only support text mode.  Command help reports what
output formats are available for each command.  Global help reports
what valid formats are.

If an invalid format is requested, an error is reported and we global usage
is dumped that lists the valid formats.

Each command sets a bitmask that describes which formats it is capable
of outputting.  If a globally valid format is requested of a command
that doesn't support it, an error is reported and command usage dumped.

Commands don't need to specify that they support text output.  All
commands are required to output text.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs.c                   | 110 ++++++++++++++++++++++++++++++++++++++--------
 check/main.c              |   3 +-
 cmds-balance.c            |  16 +++++--
 cmds-device.c             |  31 +++++++++----
 cmds-fi-du.c              |   1 +
 cmds-fi-usage.c           |   1 +
 cmds-filesystem.c         |  14 ++++--
 cmds-inspect-dump-super.c |   1 +
 cmds-inspect-dump-tree.c  |   1 +
 cmds-inspect-tree-stats.c |   1 +
 cmds-inspect.c            |  10 ++++-
 cmds-property.c           |   6 ++-
 cmds-qgroup.c             |  17 +++++--
 cmds-quota.c              |  14 ++++--
 cmds-receive.c            |   3 +-
 cmds-replace.c            |   8 +++-
 cmds-rescue.c             |   9 +++-
 cmds-restore.c            |   3 +-
 cmds-scrub.c              |  21 ++++++---
 cmds-send.c               |   3 +-
 cmds-subvolume.c          |  24 +++++++---
 commands.h                |  32 +++++++++++---
 help.c                    |  51 ++++++++++++++++-----
 help.h                    |   2 +
 24 files changed, 299 insertions(+), 83 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 49128182..32b8e090 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -26,7 +26,7 @@
 #include "help.h"
 
 static const char * const btrfs_cmd_group_usage[] = {
-	"btrfs [--help] [--version] <group> [<group>...] <command> [<args>]",
+	"btrfs [--help] [--version] [--format <format>] <group> [<group>...] <command> [<args>]",
 	NULL
 };
 
@@ -98,13 +98,36 @@ parse_command_token(const char *arg, const struct cmd_group *grp)
 	return cmd;
 }
 
+static bool cmd_provides_output_format(const struct cmd_struct *cmd,
+				       const struct cmd_context *cmdcxt)
+{
+	if (!cmdcxt->output_mode)
+		return true;
+
+	return (1 << cmdcxt->output_mode) & cmd->cmd_format_flags;
+}
+
 static void handle_help_options_next_level(const struct cmd_struct *cmd,
-		int argc, char **argv)
+					   const struct cmd_context *cmdcxt,
+					   int argc, char **argv)
 {
+	int err = 0;
+
 	if (argc < 2)
 		return;
 
-	if (!strcmp(argv[1], "--help")) {
+	/* Check if the command can provide the requested output format */
+	if (!cmd->next && !cmd_provides_output_format(cmd, cmdcxt)) {
+		ASSERT(cmdcxt->output_mode >= 0);
+		ASSERT(cmdcxt->output_mode < CMD_OUTPUT_MAX);
+		fprintf(stderr,
+			"error: %s output is unsupported for this command.\n\n",
+			cmd_outputs[cmdcxt->output_mode]);
+
+		err = 1;
+	}
+
+	if (!strcmp(argv[1], "--help") || err) {
 		if (cmd->next) {
 			argc--;
 			argv++;
@@ -113,12 +136,13 @@ static void handle_help_options_next_level(const struct cmd_struct *cmd,
 			usage_command(cmd, true, false);
 		}
 
-		exit(0);
+		exit(err);
 	}
 }
 
-int handle_command_group(const struct cmd_group *grp, int argc,
-			 char **argv)
+int handle_command_group(const struct cmd_group *grp,
+			 const struct cmd_context *cmdcxt,
+			 int argc, char **argv)
 
 {
 	const struct cmd_struct *cmd;
@@ -132,10 +156,10 @@ int handle_command_group(const struct cmd_group *grp, int argc,
 
 	cmd = parse_command_token(argv[0], grp);
 
-	handle_help_options_next_level(cmd, argc, argv);
+	handle_help_options_next_level(cmd, cmdcxt, argc, argv);
 
 	fixup_argv0(argv, cmd->token);
-	return cmd_execute(cmd, argc, argv);
+	return cmd_execute(cmd, cmdcxt, argc, argv);
 }
 
 static const struct cmd_group btrfs_cmd_group;
@@ -148,7 +172,8 @@ static const char * const cmd_help_usage[] = {
 	NULL
 };
 
-static int cmd_help(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_help(const struct cmd_struct *unused,
+		    const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	help_command_group(&btrfs_cmd_group, argc, argv);
 	return 0;
@@ -162,25 +187,66 @@ static const char * const cmd_version_usage[] = {
 	NULL
 };
 
-static int cmd_version(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_version(const struct cmd_struct *unused,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	printf("%s\n", PACKAGE_STRING);
 	return 0;
 }
 static DEFINE_SIMPLE_COMMAND(version, "version");
 
+static void print_output_formats(FILE *outf)
+{
+	int i;
+
+	fputs("Options for --format are:", outf);
+	for (i = 0; i < CMD_OUTPUT_MAX; i++)
+		fprintf(outf, "%s\"%s\"", i ? ", " : " ", cmd_outputs[i]);
+	fputs("\n", outf);
+
+	/* No extended formats anywhere */
+	if (CMD_OUTPUT_TEXT + 1 != CMD_OUTPUT_MAX)
+		fputs("Extended output formats may not be available for all commands.\n",
+		      outf);
+}
+
+static void handle_output_format(struct cmd_context *cmdcxt,
+				 const char *format)
+{
+	int i;
+
+	for (i = 0; i < CMD_OUTPUT_MAX; i++) {
+		if (!strcasecmp(format, cmd_outputs[i])) {
+			cmdcxt->output_mode = i;
+			break;
+		}
+	}
+
+	/* Print error and usage for invalid format */
+	if (i == CMD_OUTPUT_MAX) {
+		cmdcxt->output_mode = CMD_OUTPUT_TEXT;
+		fprintf(stderr, "error: invalid output format \"%s\"\n\n",
+			format);
+		usage_command_group(&btrfs_cmd_group, false, true);
+		print_output_formats(stderr);
+		exit(1);
+	}
+}
+
 /*
  * Parse global options, between binary name and first non-option argument
  * after processing all valid options (including those with arguments).
  *
  * Returns index to argv where parsting stopped, optind is reset to 1
  */
-static int handle_global_options(int argc, char **argv)
+static int handle_global_options(struct cmd_context *cmdcxt,
+				 int argc, char **argv)
 {
-	enum { OPT_HELP = 256, OPT_VERSION, OPT_FULL };
+	enum { OPT_HELP = 256, OPT_VERSION, OPT_FULL, OPT_FORMAT };
 	static const struct option long_options[] = {
 		{ "help", no_argument, NULL, OPT_HELP },
 		{ "version", no_argument, NULL, OPT_VERSION },
+		{ "format", required_argument, NULL, OPT_FORMAT },
 		{ "full", no_argument, NULL, OPT_FULL },
 		{ NULL, 0, NULL, 0}
 	};
@@ -201,6 +267,9 @@ static int handle_global_options(int argc, char **argv)
 		case OPT_HELP: break;
 		case OPT_VERSION: break;
 		case OPT_FULL: break;
+		case OPT_FORMAT:
+			handle_output_format(cmdcxt, optarg);
+			break;
 		default:
 			fprintf(stderr, "Unknown global option: %s\n",
 					argv[optind - 1]);
@@ -214,7 +283,8 @@ static int handle_global_options(int argc, char **argv)
 	return shift;
 }
 
-void handle_special_globals(int shift, int argc, char **argv)
+void handle_special_globals(const struct cmd_context *cmdcxt, int shift,
+			    int argc, char **argv)
 {
 	bool has_help = false;
 	bool has_full = false;
@@ -231,13 +301,14 @@ void handle_special_globals(int shift, int argc, char **argv)
 		if (has_full)
 			usage_command_group(&btrfs_cmd_group, true, false);
 		else
-			cmd_execute(&cmd_struct_help, argc, argv);
+			cmd_execute(&cmd_struct_help, cmdcxt, argc, argv);
+		print_output_formats(stdout);
 		exit(0);
 	}
 
 	for (i = 0; i < shift; i++)
 		if (strcmp(argv[i], "--version") == 0) {
-			cmd_execute(&cmd_struct_version, argc, argv);
+			cmd_execute(&cmd_struct_version, cmdcxt, argc, argv);
 			exit(0);
 		}
 }
@@ -269,6 +340,7 @@ int main(int argc, char **argv)
 {
 	const struct cmd_struct *cmd;
 	const char *bname;
+	struct cmd_context cmdcxt = { .output_mode = CMD_OUTPUT_TEXT, };
 	int ret;
 
 	btrfs_config_init();
@@ -283,8 +355,8 @@ int main(int argc, char **argv)
 	} else {
 		int shift;
 
-		shift = handle_global_options(argc, argv);
-		handle_special_globals(shift, argc, argv);
+		shift = handle_global_options(&cmdcxt, argc, argv);
+		handle_special_globals(&cmdcxt, shift, argc, argv);
 		while (shift-- > 0) {
 			argc--;
 			argv++;
@@ -297,13 +369,13 @@ int main(int argc, char **argv)
 
 	cmd = parse_command_token(argv[0], &btrfs_cmd_group);
 
-	handle_help_options_next_level(cmd, argc, argv);
+	handle_help_options_next_level(cmd, &cmdcxt, argc, argv);
 
 	crc32c_optimization_init();
 
 	fixup_argv0(argv, cmd->token);
 
-	ret = cmd_execute(cmd, argc, argv);
+	ret = cmd_execute(cmd, &cmdcxt, argc, argv);
 
 	btrfs_close_all_devices();
 
diff --git a/check/main.c b/check/main.c
index 49ccdf2f..599341b1 100644
--- a/check/main.c
+++ b/check/main.c
@@ -9392,7 +9392,8 @@ static const char * const cmd_check_usage[] = {
 	NULL
 };
 
-static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_check(const struct cmd_struct *cmd,
+		     const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	struct cache_tree root_cache;
 	struct btrfs_root *root;
diff --git a/cmds-balance.c b/cmds-balance.c
index c639459f..c17b9ee3 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -516,6 +516,7 @@ static const char * const cmd_balance_start_usage[] = {
 };
 
 static int cmd_balance_start(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
@@ -682,6 +683,7 @@ static const char * const cmd_balance_pause_usage[] = {
 };
 
 static int cmd_balance_pause(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	const char *path;
@@ -722,6 +724,7 @@ static const char * const cmd_balance_cancel_usage[] = {
 };
 
 static int cmd_balance_cancel(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	const char *path;
@@ -762,6 +765,7 @@ static const char * const cmd_balance_resume_usage[] = {
 };
 
 static int cmd_balance_resume(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
@@ -831,6 +835,7 @@ static const char * const cmd_balance_status_usage[] = {
  *   0 : When there is no pending balance or completed
  */
 static int cmd_balance_status(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
@@ -909,7 +914,9 @@ out:
 }
 static DEFINE_SIMPLE_COMMAND(balance_status, "status");
 
-static int cmd_balance_full(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_balance_full(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	struct btrfs_ioctl_balance_args args;
 
@@ -919,7 +926,7 @@ static int cmd_balance_full(const struct cmd_struct *cmd, int argc, char **argv)
 	return do_balance(argv[1], &args, BALANCE_START_NOWARN);
 }
 static DEFINE_COMMAND(balance_full, "--full-balance", cmd_balance_full,
-		      NULL, NULL, CMD_HIDDEN);
+		      NULL, NULL, CMD_HIDDEN, 0);
 
 static const char balance_cmd_group_info[] =
 "balance data across devices, or change block groups using filters";
@@ -936,7 +943,8 @@ static const struct cmd_group balance_cmd_group = {
 	}
 };
 
-static int cmd_balance(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_balance(const struct cmd_struct *unused,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	if (argc == 2 && strcmp("start", argv[1]) != 0) {
 		/* old 'btrfs filesystem balance <path>' syntax */
@@ -948,7 +956,7 @@ static int cmd_balance(const struct cmd_struct *unused, int argc, char **argv)
 		return do_balance(argv[1], &args, 0);
 	}
 
-	return handle_command_group(&balance_cmd_group, argc, argv);
+	return handle_command_group(&balance_cmd_group, cmdcxt, argc, argv);
 }
 
 DEFINE_GROUP_COMMAND(balance, "balance");
diff --git a/cmds-device.c b/cmds-device.c
index 6c74ca8e..ac9e82b1 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -49,6 +49,7 @@ static const char * const cmd_device_add_usage[] = {
 };
 
 static int cmd_device_add(const struct cmd_struct *cmd,
+			  const struct cmd_context *cmdcxt,
 			  int argc, char **argv)
 {
 	char	*mntpnt;
@@ -144,6 +145,7 @@ error_out:
 static DEFINE_SIMPLE_COMMAND(device_add, "add");
 
 static int _cmd_device_remove(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	char	*mntpnt;
@@ -238,9 +240,10 @@ static const char * const cmd_device_remove_usage[] = {
 };
 
 static int cmd_device_remove(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
-	return _cmd_device_remove(cmd, argc, argv);
+	return _cmd_device_remove(cmd, cmdcxt, argc, argv);
 }
 static DEFINE_SIMPLE_COMMAND(device_remove, "remove");
 
@@ -253,12 +256,13 @@ static const char * const cmd_device_delete_usage[] = {
 };
 
 static int cmd_device_delete(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
-	return _cmd_device_remove(cmd, argc, argv);
+	return _cmd_device_remove(cmd, cmdcxt, argc, argv);
 }
 static DEFINE_COMMAND(device_delete, "delete", cmd_device_delete,
-		      cmd_device_delete_usage, NULL, CMD_ALIAS);
+		      cmd_device_delete_usage, NULL, CMD_ALIAS, 0);
 
 static const char * const cmd_device_scan_usage[] = {
 	"btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
@@ -267,7 +271,9 @@ static const char * const cmd_device_scan_usage[] = {
 	NULL
 };
 
-static int cmd_device_scan(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_device_scan(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	int i;
 	int devstart;
@@ -340,7 +346,9 @@ static const char * const cmd_device_ready_usage[] = {
 	NULL
 };
 
-static int cmd_device_ready(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_device_ready(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	struct	btrfs_ioctl_vol_args args;
 	int	fd;
@@ -399,7 +407,9 @@ static const char * const cmd_device_stats_usage[] = {
 	NULL
 };
 
-static int cmd_device_stats(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_device_stats(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	char *dev_path;
 	struct btrfs_ioctl_fs_info_args fi_args;
@@ -565,7 +575,9 @@ out:
 	return ret;
 }
 
-static int cmd_device_usage(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_device_usage(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	unsigned unit_mode;
 	int ret = 0;
@@ -618,8 +630,9 @@ static const struct cmd_group device_cmd_group = {
 	}
 };
 
-static int cmd_device(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_device(const struct cmd_struct *unused,
+		      const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&device_cmd_group, argc, argv);
+	return handle_command_group(&device_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(device);
diff --git a/cmds-fi-du.c b/cmds-fi-du.c
index 9635866a..f2b3b1ce 100644
--- a/cmds-fi-du.c
+++ b/cmds-fi-du.c
@@ -558,6 +558,7 @@ static const char * const cmd_filesystem_du_usage[] = {
 };
 
 static int cmd_filesystem_du(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int ret = 0, err = 0;
diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c
index a14d0017..38a642cc 100644
--- a/cmds-fi-usage.c
+++ b/cmds-fi-usage.c
@@ -965,6 +965,7 @@ static const char * const cmd_filesystem_usage_usage[] = {
 };
 
 static int cmd_filesystem_usage(const struct cmd_struct *cmd,
+				const struct cmd_context *cmdcxt,
 				int argc, char **argv)
 {
 	int ret = 0;
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index d8290968..6701b16f 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -118,6 +118,7 @@ static void print_df(struct btrfs_ioctl_space_args *sargs, unsigned unit_mode)
 }
 
 static int cmd_filesystem_df(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	struct btrfs_ioctl_space_args *sargs = NULL;
@@ -670,6 +671,7 @@ static const char * const cmd_filesystem_show_usage[] = {
 };
 
 static int cmd_filesystem_show(const struct cmd_struct *cmd,
+			       const struct cmd_context *cmdcxt,
 			       int argc, char **argv)
 {
 	LIST_HEAD(all_uuids);
@@ -818,6 +820,7 @@ static const char * const cmd_filesystem_sync_usage[] = {
 };
 
 static int cmd_filesystem_sync(const struct cmd_struct *cmd,
+			       const struct cmd_context *cmdcxt,
 			       int argc, char **argv)
 {
 	enum btrfs_util_error err;
@@ -907,6 +910,7 @@ error:
 }
 
 static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
+				 const struct cmd_context *cmdcxt,
 				 int argc, char **argv)
 {
 	int fd;
@@ -1087,6 +1091,7 @@ static const char * const cmd_filesystem_resize_usage[] = {
 };
 
 static int cmd_filesystem_resize(const struct cmd_struct *cmd,
+				 const struct cmd_context *cmdcxt,
 				 int argc, char **argv)
 {
 	struct btrfs_ioctl_vol_args	args;
@@ -1166,6 +1171,7 @@ static const char * const cmd_filesystem_label_usage[] = {
 };
 
 static int cmd_filesystem_label(const struct cmd_struct *cmd,
+				const struct cmd_context *cmdcxt,
 				int argc, char **argv)
 {
 	clean_args_no_options(cmd, argc, argv);
@@ -1196,9 +1202,10 @@ static const char * const cmd_filesystem_balance_usage[] = {
 };
 
 static int cmd_filesystem_balance(const struct cmd_struct *unused,
+				  const struct cmd_context *cmdcxt,
 				  int argc, char **argv)
 {
-	return cmd_execute(&cmd_struct_balance, argc, argv);
+	return cmd_execute(&cmd_struct_balance, cmdcxt, argc, argv);
 }
 
 /*
@@ -1208,7 +1215,7 @@ static int cmd_filesystem_balance(const struct cmd_struct *unused,
  * for historical compatibility and is hidden.
  */
 static DEFINE_COMMAND(filesystem_balance, "balance", cmd_filesystem_balance,
-		      cmd_filesystem_balance_usage, NULL, CMD_HIDDEN);
+		      cmd_filesystem_balance_usage, NULL, CMD_HIDDEN, 0);
 
 static const char filesystem_cmd_group_info[] =
 "overall filesystem tasks and information";
@@ -1229,8 +1236,9 @@ static const struct cmd_group filesystem_cmd_group = {
 };
 
 static int cmd_filesystem(const struct cmd_struct *unused,
+			  const struct cmd_context *cmdcxt,
 			  int argc, char **argv)
 {
-	return handle_command_group(&filesystem_cmd_group, argc, argv);
+	return handle_command_group(&filesystem_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(filesystem);
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index bc2eedb5..8b843ade 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -508,6 +508,7 @@ static const char * const cmd_inspect_dump_super_usage[] = {
 };
 
 static int cmd_inspect_dump_super(const struct cmd_struct *cmd,
+				  const struct cmd_context *cmdcxt,
 				  int argc, char **argv)
 {
 	int all = 0;
diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index b4f413a4..a97e0368 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -204,6 +204,7 @@ static const char * const cmd_inspect_dump_tree_usage[] = {
 };
 
 static int cmd_inspect_dump_tree(const struct cmd_struct *cmd,
+				 const struct cmd_context *cmdcxt,
 				 int argc, char **argv)
 {
 	struct btrfs_root *root;
diff --git a/cmds-inspect-tree-stats.c b/cmds-inspect-tree-stats.c
index e5e68562..768af025 100644
--- a/cmds-inspect-tree-stats.c
+++ b/cmds-inspect-tree-stats.c
@@ -428,6 +428,7 @@ static const char * const cmd_inspect_tree_stats_usage[] = {
 };
 
 static int cmd_inspect_tree_stats(const struct cmd_struct *cmd,
+				  const struct cmd_context *cmdcxt,
 				  int argc, char **argv)
 {
 	struct btrfs_key key;
diff --git a/cmds-inspect.c b/cmds-inspect.c
index b191939c..eecfd7f9 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -88,6 +88,7 @@ static const char * const cmd_inspect_inode_resolve_usage[] = {
 };
 
 static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
+				     const struct cmd_context *cmdcxt,
 				     int argc, char **argv)
 {
 	int fd;
@@ -136,6 +137,7 @@ static const char * const cmd_inspect_logical_resolve_usage[] = {
 };
 
 static int cmd_inspect_logical_resolve(const struct cmd_struct *cmd,
+				       const struct cmd_context *cmdcxt,
 				       int argc, char **argv)
 {
 	int ret;
@@ -269,6 +271,7 @@ static const char * const cmd_inspect_subvolid_resolve_usage[] = {
 };
 
 static int cmd_inspect_subvolid_resolve(const struct cmd_struct *cmd,
+					const struct cmd_context *cmdcxt,
 					int argc, char **argv)
 {
 	int ret;
@@ -313,6 +316,7 @@ static const char* const cmd_inspect_rootid_usage[] = {
 };
 
 static int cmd_inspect_rootid(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	int ret;
@@ -593,6 +597,7 @@ out:
 }
 
 static int cmd_inspect_min_dev_size(const struct cmd_struct *cmd,
+				    const struct cmd_context *cmdcxt,
 				    int argc, char **argv)
 {
 	int ret;
@@ -653,8 +658,9 @@ static const struct cmd_group inspect_cmd_group = {
 	}
 };
 
-static int cmd_inspect(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_inspect(const struct cmd_struct *unused,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&inspect_cmd_group, argc, argv);
+	return handle_command_group(&inspect_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND(inspect, "inspect-internal");
diff --git a/cmds-property.c b/cmds-property.c
index 4aa2f18f..498fa456 100644
--- a/cmds-property.c
+++ b/cmds-property.c
@@ -341,6 +341,7 @@ static const char * const cmd_property_get_usage[] = {
 };
 
 static int cmd_property_get(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
 			    int argc, char **argv)
 {
 	int ret;
@@ -368,6 +369,7 @@ static const char * const cmd_property_set_usage[] = {
 };
 
 static int cmd_property_set(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
 			    int argc, char **argv)
 {
 	int ret;
@@ -393,6 +395,7 @@ static const char * const cmd_property_list_usage[] = {
 };
 
 static int cmd_property_list(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int ret;
@@ -420,8 +423,9 @@ static const struct cmd_group property_cmd_group = {
 };
 
 static int cmd_property(const struct cmd_struct *unused,
+			const struct cmd_context *cmdcxt,
 			int argc, char **argv)
 {
-	return handle_command_group(&property_cmd_group, argc, argv);
+	return handle_command_group(&property_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(property);
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 0ee578ff..9325b568 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -218,6 +218,7 @@ static const char * const cmd_qgroup_assign_usage[] = {
 };
 
 static int cmd_qgroup_assign(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	return _cmd_qgroup_assign(cmd, 1, argc, argv);
@@ -231,6 +232,7 @@ static const char * const cmd_qgroup_remove_usage[] = {
 };
 
 static int cmd_qgroup_remove(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	return _cmd_qgroup_assign(cmd, 0, argc, argv);
@@ -244,6 +246,7 @@ static const char * const cmd_qgroup_create_usage[] = {
 };
 
 static int cmd_qgroup_create(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int ret;
@@ -265,6 +268,7 @@ static const char * const cmd_qgroup_destroy_usage[] = {
 };
 
 static int cmd_qgroup_destroy(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	int ret;
@@ -302,7 +306,9 @@ static const char * const cmd_qgroup_show_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_qgroup_show(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	char *path;
 	int ret = 0;
@@ -438,7 +444,9 @@ static const char * const cmd_qgroup_limit_usage[] = {
 	NULL
 };
 
-static int cmd_qgroup_limit(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_qgroup_limit(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
@@ -533,8 +541,9 @@ static const struct cmd_group qgroup_cmd_group = {
 	}
 };
 
-static int cmd_qgroup(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_qgroup(const struct cmd_struct *unused,
+		      const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&qgroup_cmd_group, argc, argv);
+	return handle_command_group(&qgroup_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(qgroup);
diff --git a/cmds-quota.c b/cmds-quota.c
index c634c4e9..2a88d4c4 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -67,7 +67,9 @@ static const char * const cmd_quota_enable_usage[] = {
 	NULL
 };
 
-static int cmd_quota_enable(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_quota_enable(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	int ret;
 
@@ -88,6 +90,7 @@ static const char * const cmd_quota_disable_usage[] = {
 };
 
 static int cmd_quota_disable(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int ret;
@@ -111,7 +114,9 @@ static const char * const cmd_quota_rescan_usage[] = {
 	NULL
 };
 
-static int cmd_quota_rescan(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_quota_rescan(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
@@ -214,8 +219,9 @@ static const struct cmd_group quota_cmd_group = {
 	}
 };
 
-static int cmd_quota(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_quota(const struct cmd_struct *unused,
+		     const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&quota_cmd_group, argc, argv);
+	return handle_command_group(&quota_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(quota);
diff --git a/cmds-receive.c b/cmds-receive.c
index 5429c607..57ce2272 100644
--- a/cmds-receive.c
+++ b/cmds-receive.c
@@ -1279,7 +1279,8 @@ static const char * const cmd_receive_usage[] = {
 	NULL
 };
 
-static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_receive(const struct cmd_struct *cmd,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	char *tomnt = NULL;
 	char fromfile[PATH_MAX];
diff --git a/cmds-replace.c b/cmds-replace.c
index 2057d69e..64c93537 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -115,6 +115,7 @@ static const char *const cmd_replace_start_usage[] = {
 };
 
 static int cmd_replace_start(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	struct btrfs_ioctl_dev_replace_args start_args = {0};
@@ -327,6 +328,7 @@ static const char *const cmd_replace_status_usage[] = {
 };
 
 static int cmd_replace_status(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	int fd;
@@ -497,6 +499,7 @@ static const char *const cmd_replace_cancel_usage[] = {
 };
 
 static int cmd_replace_cancel(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
 	struct btrfs_ioctl_dev_replace_args args = {0};
@@ -557,8 +560,9 @@ static const struct cmd_group replace_cmd_group = {
 	}
 };
 
-static int cmd_replace(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_replace(const struct cmd_struct *unused,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&replace_cmd_group, argc, argv);
+	return handle_command_group(&replace_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(replace);
diff --git a/cmds-rescue.c b/cmds-rescue.c
index f96d8010..ec1ea222 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -46,6 +46,7 @@ static const char * const cmd_rescue_chunk_recover_usage[] = {
 };
 
 static int cmd_rescue_chunk_recover(const struct cmd_struct *cmd,
+				    const struct cmd_context *cmdcxt,
 				    int argc, char *argv[])
 {
 	int ret = 0;
@@ -115,6 +116,7 @@ static const char * const cmd_rescue_super_recover_usage[] = {
  *   4 : Abort to recover bad superblocks
  */
 static int cmd_rescue_super_recover(const struct cmd_struct *cmd,
+				    const struct cmd_context *cmdcxt,
 				    int argc, char **argv)
 {
 	int ret;
@@ -162,6 +164,7 @@ static const char * const cmd_rescue_zero_log_usage[] = {
 };
 
 static int cmd_rescue_zero_log(const struct cmd_struct *cmd,
+			       const struct cmd_context *cmdcxt,
 			       int argc, char **argv)
 {
 	struct btrfs_root *root;
@@ -217,6 +220,7 @@ static const char * const cmd_rescue_fix_device_size_usage[] = {
 };
 
 static int cmd_rescue_fix_device_size(const struct cmd_struct *cmd,
+				      const struct cmd_context *cmdcxt,
 				      int argc, char **argv)
 {
 	struct btrfs_fs_info *fs_info;
@@ -269,8 +273,9 @@ static const struct cmd_group rescue_cmd_group = {
 	}
 };
 
-static int cmd_rescue(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_rescue(const struct cmd_struct *unused,
+		      const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&rescue_cmd_group, argc, argv);
+	return handle_command_group(&rescue_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(rescue);
diff --git a/cmds-restore.c b/cmds-restore.c
index 0afcc376..2dd0c8dd 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -1422,7 +1422,8 @@ static const char * const cmd_restore_usage[] = {
 	NULL
 };
 
-static int cmd_restore(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_restore(const struct cmd_struct *cmd,
+		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	struct btrfs_root *root;
 	struct btrfs_key key;
diff --git a/cmds-scrub.c b/cmds-scrub.c
index d3ca59a9..41f9226e 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1569,7 +1569,9 @@ static const char * const cmd_scrub_start_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_start(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_scrub_start(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	return scrub_start(cmd, argc, argv, false);
 }
@@ -1581,7 +1583,9 @@ static const char * const cmd_scrub_cancel_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_cancel(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_scrub_cancel(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	char *path;
 	int ret;
@@ -1636,7 +1640,9 @@ static const char * const cmd_scrub_resume_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_resume(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_scrub_resume(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	return scrub_start(cmd, argc, argv, true);
 }
@@ -1651,7 +1657,9 @@ static const char * const cmd_scrub_status_usage[] = {
 	NULL
 };
 
-static int cmd_scrub_status(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_scrub_status(const struct cmd_struct *cmd,
+			    const struct cmd_context *cmdcxt,
+			    int argc, char **argv)
 {
 	char *path;
 	struct btrfs_ioctl_fs_info_args fi_args;
@@ -1797,9 +1805,10 @@ static const struct cmd_group scrub_cmd_group = {
 	}
 };
 
-static int cmd_scrub(const struct cmd_struct *unused, int argc, char **argv)
+static int cmd_scrub(const struct cmd_struct *unused,
+		     const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&scrub_cmd_group, argc, argv);
+	return handle_command_group(&scrub_cmd_group, cmdcxt, argc, argv);
 }
 
 DEFINE_GROUP_COMMAND_TOKEN(scrub);
diff --git a/cmds-send.c b/cmds-send.c
index e2d87785..c810f842 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -523,7 +523,8 @@ static const char * const cmd_send_usage[] = {
 	NULL
 };
 
-static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_send(const struct cmd_struct *cmd,
+		    const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	char *subvol = NULL;
 	int ret;
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 6b01569f..be78d555 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -91,6 +91,7 @@ static const char * const cmd_subvol_create_usage[] = {
 };
 
 static int cmd_subvol_create(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int	retval, res, len;
@@ -233,6 +234,7 @@ static const char * const cmd_subvol_delete_usage[] = {
 };
 
 static int cmd_subvol_delete(const struct cmd_struct *cmd,
+			     const struct cmd_context *cmdcxt,
 			     int argc, char **argv)
 {
 	int res, ret = 0;
@@ -453,7 +455,9 @@ static const char * const cmd_subvol_list_usage[] = {
 	NULL,
 };
 
-static int cmd_subvol_list(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_subvol_list(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	struct btrfs_list_filter_set *filter_set;
 	struct btrfs_list_comparer_set *comparer_set;
@@ -626,6 +630,7 @@ static const char * const cmd_subvol_snapshot_usage[] = {
 };
 
 static int cmd_subvol_snapshot(const struct cmd_struct *cmd,
+			       const struct cmd_context *cmdcxt,
 			       int argc, char **argv)
 {
 	char	*subvol, *dst;
@@ -774,6 +779,7 @@ static const char * const cmd_subvol_get_default_usage[] = {
 };
 
 static int cmd_subvol_get_default(const struct cmd_struct *cmd,
+				  const struct cmd_context *cmdcxt,
 				  int argc, char **argv)
 {
 	int fd = -1;
@@ -840,6 +846,7 @@ static const char * const cmd_subvol_set_default_usage[] = {
 };
 
 static int cmd_subvol_set_default(const struct cmd_struct *cmd,
+				  const struct cmd_context *cmdcxt,
 				  int argc, char **argv)
 {
 	u64 objectid;
@@ -878,6 +885,7 @@ static const char * const cmd_subvol_find_new_usage[] = {
 };
 
 static int cmd_subvol_find_new(const struct cmd_struct *cmd,
+			       const struct cmd_context *cmdcxt,
 			       int argc, char **argv)
 {
 	int fd;
@@ -930,7 +938,9 @@ static const char * const cmd_subvol_show_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_show(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_subvol_show(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	char tstr[256];
 	char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
@@ -1185,7 +1195,9 @@ static const char * const cmd_subvol_sync_usage[] = {
 	NULL
 };
 
-static int cmd_subvol_sync(const struct cmd_struct *cmd, int argc, char **argv)
+static int cmd_subvol_sync(const struct cmd_struct *cmd,
+			   const struct cmd_context *cmdcxt,
+			   int argc, char **argv)
 {
 	int fd = -1;
 	int ret = 1;
@@ -1295,9 +1307,9 @@ static const struct cmd_group subvolume_cmd_group = {
 	}
 };
 
-static int cmd_subvolume(const struct cmd_struct *unused,
-			 int argc, char **argv)
+int cmd_subvolume(const struct cmd_struct *unused,
+		  const struct cmd_context *cmdcxt, int argc, char **argv)
 {
-	return handle_command_group(&subvolume_cmd_group, argc, argv);
+	return handle_command_group(&subvolume_cmd_group, cmdcxt, argc, argv);
 }
 DEFINE_GROUP_COMMAND_TOKEN(subvolume);
diff --git a/commands.h b/commands.h
index 4c5469ac..83316c6d 100644
--- a/commands.h
+++ b/commands.h
@@ -17,6 +17,17 @@
 #ifndef __BTRFS_COMMANDS_H__
 #define __BTRFS_COMMANDS_H__
 
+enum cmd_output {
+	CMD_OUTPUT_TEXT = 0,
+	CMD_OUTPUT_MAX,
+};
+
+#define CMD_OUTPUT_FLAG(x)	(1 << (CMD_OUTPUT_##x))
+
+struct cmd_context {
+	enum cmd_output output_mode;
+};
+
 enum {
 	CMD_HIDDEN = (1 << 0),	/* should not be in help listings */
 	CMD_ALIAS = (1 << 1),	/* alias of next command in cmd_group */
@@ -24,7 +35,8 @@ enum {
 
 struct cmd_struct {
 	const char *token;
-	int (*fn)(const struct cmd_struct *cmd, int argc, char **argv);
+	int (*fn)(const struct cmd_struct *cmd,
+		  const struct cmd_context *cmdcxt, int argc, char **argv);
 
 	/*
 	 * Usage strings
@@ -54,6 +66,8 @@ struct cmd_struct {
 
 	/* CMD_* flags above */
 	int flags;
+
+	unsigned int cmd_format_flags;
 };
 
 /*
@@ -65,7 +79,8 @@ struct cmd_struct {
 	extern const struct cmd_struct __CMD_NAME(name)
 
 /* Define a command with all members specified */
-#define DEFINE_COMMAND(name, _token, _fn, _usagestr, _group, _flags)	\
+#define DEFINE_COMMAND(name, _token, _fn, _usagestr, _group, _flags,	\
+		       _cmd_format_flags)				\
 	const struct cmd_struct __CMD_NAME(name) =			\
 		{							\
 			.token = (_token),				\
@@ -73,6 +88,7 @@ struct cmd_struct {
 			.usagestr = (_usagestr),			\
 			.next = (_group),				\
 			.flags = (_flags),				\
+			.cmd_format_flags = (_cmd_format_flags),	\
 		}
 
 /*
@@ -82,7 +98,7 @@ struct cmd_struct {
  */
 #define DEFINE_SIMPLE_COMMAND(name, token)				\
 	DEFINE_COMMAND(name, token, cmd_ ##name,			\
-		       cmd_ ##name ##_usage, NULL, 0)
+		       cmd_ ##name ##_usage, NULL, 0, 0)
 
 /*
  * Define a command group callback.
@@ -91,7 +107,7 @@ struct cmd_struct {
  */
 #define DEFINE_GROUP_COMMAND(name, token)				\
 	DEFINE_COMMAND(name, token, cmd_ ##name,			\
-		       NULL, &(name ## _cmd_group), 0)
+		       NULL, &(name ## _cmd_group), 0, 0)
 
 /*
  * Define a command group callback when the name and the string are
@@ -108,13 +124,15 @@ struct cmd_group {
 };
 
 static inline int cmd_execute(const struct cmd_struct *cmd,
+			      const struct cmd_context *cmdcxt,
 			      int argc, char **argv)
 {
-	return cmd->fn(cmd, argc, argv);
+	return cmd->fn(cmd, cmdcxt, argc, argv);
 }
 
-int handle_command_group(const struct cmd_group *grp, int argc,
-			 char **argv);
+int handle_command_group(const struct cmd_group *grp,
+			 const struct cmd_context *cmdcxt,
+			 int argc, char **argv);
 
 extern const char * const generic_cmd_help_usage[];
 
diff --git a/help.c b/help.c
index 6ee93161..063e9740 100644
--- a/help.c
+++ b/help.c
@@ -28,6 +28,11 @@
 #define USAGE_LONG		2U
 #define USAGE_OPTIONS		4U
 #define USAGE_LISTING		8U
+#define USAGE_FORMAT		16U
+
+const char *cmd_outputs[CMD_OUTPUT_MAX] = {
+	"text",
+};
 
 static char argv0_buf[ARGV0_BUF_SIZE] = "btrfs";
 
@@ -126,6 +131,7 @@ void clean_args_no_options_relaxed(const struct cmd_struct *cmd,
 }
 
 static int do_usage_one_command(const char * const *usagestr,
+				unsigned int format_flags,
 				unsigned int flags, FILE *outf)
 {
 	int pad = 4;
@@ -193,12 +199,32 @@ static int do_usage_one_command(const char * const *usagestr,
 	while (*usagestr)
 		fprintf(outf, "%*s%s\n", pad, "", *usagestr++);
 
+	if (flags & USAGE_FORMAT) {
+		/* We always support text */
+		format_flags |= (1 << CMD_OUTPUT_TEXT);
+
+		fputs("\n\tThis command supports output in ", outf);
+		if (format_flags == (1 << CMD_OUTPUT_TEXT))
+			fputs("text mode only.\n", outf);
+		else {
+			int i;
+
+			fputs("the following formats:", outf);
+			for (i = 0; i < CMD_OUTPUT_MAX; i++) {
+				if (format_flags & (1 << i))
+					fprintf(outf, " %s", cmd_outputs[i]);
+			}
+			fputs("\n", outf);
+		}
+	}
+
 	return 0;
 }
 
 static int usage_command_internal(const char * const *usagestr,
-				  const char *token, bool full, bool lst,
-				  bool alias, FILE *outf)
+				  const char *token,
+				  unsigned int format_flags, bool full,
+				  bool lst, bool alias, FILE *outf)
 {
 	unsigned int flags = 0;
 	int ret;
@@ -206,11 +232,11 @@ static int usage_command_internal(const char * const *usagestr,
 	if (!alias)
 		flags |= USAGE_SHORT;
 	if (full)
-		flags |= USAGE_LONG | USAGE_OPTIONS;
+		flags |= USAGE_LONG | USAGE_OPTIONS | USAGE_FORMAT;
 	if (lst)
 		flags |= USAGE_LISTING;
 
-	ret = do_usage_one_command(usagestr, flags, outf);
+	ret = do_usage_one_command(usagestr, format_flags, flags, outf);
 	switch (ret) {
 	case -1:
 		fprintf(outf, "No usage for '%s'\n", token);
@@ -224,25 +250,28 @@ static int usage_command_internal(const char * const *usagestr,
 }
 
 static void usage_command_usagestr(const char * const *usagestr,
-				   const char *token, bool full, bool err)
+				   const char *token, unsigned int format_flags,
+				   bool full, bool err)
 {
 	FILE *outf = err ? stderr : stdout;
 	int ret;
 
-	ret = usage_command_internal(usagestr, token, full, false, false, outf);
+	ret = usage_command_internal(usagestr, token, format_flags,
+				     full, false, false, outf);
 	if (!ret)
 		fputc('\n', outf);
 }
 
 void usage_command(const struct cmd_struct *cmd, bool full, bool err)
 {
-	usage_command_usagestr(cmd->usagestr, cmd->token, full, err);
+	usage_command_usagestr(cmd->usagestr, cmd->token,
+			       cmd->cmd_format_flags, full, err);
 }
 
 __attribute__((noreturn))
 void usage(const struct cmd_struct *cmd)
 {
-	usage_command_usagestr(cmd->usagestr, NULL, true, true);
+	usage_command_usagestr(cmd->usagestr, NULL, 0, true, true);
 	exit(1);
 }
 
@@ -266,7 +295,8 @@ static void usage_command_group_internal(const struct cmd_group *grp, bool full,
 				do_sep = 0;
 			}
 
-			usage_command_internal(cmd->usagestr, cmd->token, full,
+			usage_command_internal(cmd->usagestr, cmd->token,
+					       cmd->cmd_format_flags, full,
 					       true, cmd->flags & CMD_ALIAS,
 					       outf);
 			if (cmd->flags & CMD_ALIAS)
@@ -377,7 +407,8 @@ void help_ambiguous_token(const char *arg, const struct cmd_group *grp)
 	exit(1);
 }
 
-void help_command_group(const struct cmd_group *grp, int argc, char **argv)
+void help_command_group(const struct cmd_group *grp, int argc,
+			char **argv)
 {
 	bool full = false;
 
diff --git a/help.h b/help.h
index 7468cf8b..5b338a49 100644
--- a/help.h
+++ b/help.h
@@ -55,6 +55,8 @@
 struct cmd_struct;
 struct cmd_group;
 
+extern const char *cmd_outputs[];
+
 __attribute__((noreturn))
 void usage(const struct cmd_struct *cmd);
 void usage_command(const struct cmd_struct *cmd, bool full, bool err);
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 17/18] btrfs-progs: handle command groups directly for common case
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (15 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 16/18] btrfs-progs: add support for output formats jeffm
@ 2018-05-16 21:38 ` jeffm
  2018-05-16 21:38 ` [PATCH 18/18] btrfs-progs: qgroups: don't print dead qgroups jeffm
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

Most command groups just pass their own command group to
handle_command_group.  We can remove the explicit definitions
of command group callbacks by passing the cmd_struct to
handle_command_group and allowing it to resolve the group from it.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 btrfs.c           | 14 +++++++-------
 cmds-balance.c    |  6 +++---
 cmds-device.c     |  5 -----
 cmds-filesystem.c |  6 ------
 cmds-inspect.c    |  5 -----
 cmds-property.c   |  6 ------
 cmds-qgroup.c     |  5 -----
 cmds-quota.c      |  5 -----
 cmds-replace.c    |  5 -----
 cmds-rescue.c     |  5 -----
 cmds-scrub.c      |  6 ------
 cmds-subvolume.c  |  5 -----
 commands.h        |  7 ++++---
 13 files changed, 14 insertions(+), 66 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 32b8e090..427e14c8 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -140,26 +140,26 @@ static void handle_help_options_next_level(const struct cmd_struct *cmd,
 	}
 }
 
-int handle_command_group(const struct cmd_group *grp,
+int handle_command_group(const struct cmd_struct *cmd,
 			 const struct cmd_context *cmdcxt,
 			 int argc, char **argv)
 
 {
-	const struct cmd_struct *cmd;
+	const struct cmd_struct *subcmd;
 
 	argc--;
 	argv++;
 	if (argc < 1) {
-		usage_command_group(grp, false, false);
+		usage_command_group(cmd->next, false, false);
 		exit(1);
 	}
 
-	cmd = parse_command_token(argv[0], grp);
+	subcmd = parse_command_token(argv[0], cmd->next);
 
-	handle_help_options_next_level(cmd, cmdcxt, argc, argv);
+	handle_help_options_next_level(subcmd, cmdcxt, argc, argv);
 
-	fixup_argv0(argv, cmd->token);
-	return cmd_execute(cmd, cmdcxt, argc, argv);
+	fixup_argv0(argv, subcmd->token);
+	return cmd_execute(subcmd, cmdcxt, argc, argv);
 }
 
 static const struct cmd_group btrfs_cmd_group;
diff --git a/cmds-balance.c b/cmds-balance.c
index c17b9ee3..e414ca27 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -943,7 +943,7 @@ static const struct cmd_group balance_cmd_group = {
 	}
 };
 
-static int cmd_balance(const struct cmd_struct *unused,
+static int cmd_balance(const struct cmd_struct *cmd,
 		       const struct cmd_context *cmdcxt, int argc, char **argv)
 {
 	if (argc == 2 && strcmp("start", argv[1]) != 0) {
@@ -956,7 +956,7 @@ static int cmd_balance(const struct cmd_struct *unused,
 		return do_balance(argv[1], &args, 0);
 	}
 
-	return handle_command_group(&balance_cmd_group, cmdcxt, argc, argv);
+	return handle_command_group(cmd, cmdcxt, argc, argv);
 }
 
-DEFINE_GROUP_COMMAND(balance, "balance");
+DEFINE_COMMAND(balance, "balance", cmd_balance, NULL, &balance_cmd_group, 0, 0);
diff --git a/cmds-device.c b/cmds-device.c
index ac9e82b1..f8c0ff20 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -630,9 +630,4 @@ static const struct cmd_group device_cmd_group = {
 	}
 };
 
-static int cmd_device(const struct cmd_struct *unused,
-		      const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&device_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(device);
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 6701b16f..24852ec6 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -1235,10 +1235,4 @@ static const struct cmd_group filesystem_cmd_group = {
 	}
 };
 
-static int cmd_filesystem(const struct cmd_struct *unused,
-			  const struct cmd_context *cmdcxt,
-			  int argc, char **argv)
-{
-	return handle_command_group(&filesystem_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(filesystem);
diff --git a/cmds-inspect.c b/cmds-inspect.c
index eecfd7f9..22c5a5d6 100644
--- a/cmds-inspect.c
+++ b/cmds-inspect.c
@@ -658,9 +658,4 @@ static const struct cmd_group inspect_cmd_group = {
 	}
 };
 
-static int cmd_inspect(const struct cmd_struct *unused,
-		       const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&inspect_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND(inspect, "inspect-internal");
diff --git a/cmds-property.c b/cmds-property.c
index 498fa456..58f6c48a 100644
--- a/cmds-property.c
+++ b/cmds-property.c
@@ -422,10 +422,4 @@ static const struct cmd_group property_cmd_group = {
 	}
 };
 
-static int cmd_property(const struct cmd_struct *unused,
-			const struct cmd_context *cmdcxt,
-			int argc, char **argv)
-{
-	return handle_command_group(&property_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(property);
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 9325b568..ce9aa1c6 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -541,9 +541,4 @@ static const struct cmd_group qgroup_cmd_group = {
 	}
 };
 
-static int cmd_qgroup(const struct cmd_struct *unused,
-		      const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&qgroup_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(qgroup);
diff --git a/cmds-quota.c b/cmds-quota.c
index 2a88d4c4..7b524123 100644
--- a/cmds-quota.c
+++ b/cmds-quota.c
@@ -219,9 +219,4 @@ static const struct cmd_group quota_cmd_group = {
 	}
 };
 
-static int cmd_quota(const struct cmd_struct *unused,
-		     const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&quota_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(quota);
diff --git a/cmds-replace.c b/cmds-replace.c
index 64c93537..8b2091c9 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -560,9 +560,4 @@ static const struct cmd_group replace_cmd_group = {
 	}
 };
 
-static int cmd_replace(const struct cmd_struct *unused,
-		       const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&replace_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(replace);
diff --git a/cmds-rescue.c b/cmds-rescue.c
index ec1ea222..364d6dd9 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -273,9 +273,4 @@ static const struct cmd_group rescue_cmd_group = {
 	}
 };
 
-static int cmd_rescue(const struct cmd_struct *unused,
-		      const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&rescue_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(rescue);
diff --git a/cmds-scrub.c b/cmds-scrub.c
index 41f9226e..bafec7df 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1805,10 +1805,4 @@ static const struct cmd_group scrub_cmd_group = {
 	}
 };
 
-static int cmd_scrub(const struct cmd_struct *unused,
-		     const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&scrub_cmd_group, cmdcxt, argc, argv);
-}
-
 DEFINE_GROUP_COMMAND_TOKEN(scrub);
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index be78d555..e5e5193b 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -1307,9 +1307,4 @@ static const struct cmd_group subvolume_cmd_group = {
 	}
 };
 
-int cmd_subvolume(const struct cmd_struct *unused,
-		  const struct cmd_context *cmdcxt, int argc, char **argv)
-{
-	return handle_command_group(&subvolume_cmd_group, cmdcxt, argc, argv);
-}
 DEFINE_GROUP_COMMAND_TOKEN(subvolume);
diff --git a/commands.h b/commands.h
index 83316c6d..5c15a16e 100644
--- a/commands.h
+++ b/commands.h
@@ -94,7 +94,8 @@ struct cmd_struct {
 /*
  * Define a command for the common case - just a name and string.
  * It's assumed that the callback is called cmd_<name> and the usage
- * array is named cmd_<name>_usage.
+ * array is named cmd_<name>_usage.  Text is the only supported output
+ * format.
  */
 #define DEFINE_SIMPLE_COMMAND(name, token)				\
 	DEFINE_COMMAND(name, token, cmd_ ##name,			\
@@ -106,7 +107,7 @@ struct cmd_struct {
  * struct cmd_group is called <name>_cmd_group.
  */
 #define DEFINE_GROUP_COMMAND(name, token)				\
-	DEFINE_COMMAND(name, token, cmd_ ##name,			\
+	DEFINE_COMMAND(name, token, handle_command_group,		\
 		       NULL, &(name ## _cmd_group), 0, 0)
 
 /*
@@ -130,7 +131,7 @@ static inline int cmd_execute(const struct cmd_struct *cmd,
 	return cmd->fn(cmd, cmdcxt, argc, argv);
 }
 
-int handle_command_group(const struct cmd_group *grp,
+int handle_command_group(const struct cmd_struct *cmd,
 			 const struct cmd_context *cmdcxt,
 			 int argc, char **argv);
 
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 18/18] btrfs-progs: qgroups: don't print dead qgroups
  2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
                   ` (16 preceding siblings ...)
  2018-05-16 21:38 ` [PATCH 17/18] btrfs-progs: handle command groups directly for common case jeffm
@ 2018-05-16 21:38 ` jeffm
  17 siblings, 0 replies; 20+ messages in thread
From: jeffm @ 2018-05-16 21:38 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Jeff Mahoney

From: Jeff Mahoney <jeffm@suse.com>

When qgroup items get left behind, we still print them in
'btrfs qgroup show' even though there is nothing to show.  Since we
now look up the pathname and that means we look up the subvolume,
we can filter out first-level qgroups that correspond to roots
that have been removed.  Specifying -v will still show them.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 qgroup.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/qgroup.c b/qgroup.c
index 647bc2f3..08e78887 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -313,6 +313,13 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	}
 }
 
+static bool qgroup_target_exists(const struct btrfs_qgroup *qgroup)
+{
+	if (btrfs_qgroup_level(qgroup->qgroupid) > 0)
+		return true;
+	return qgroup->pathname != NULL;
+}
+
 static void print_single_qgroup_table(struct btrfs_qgroup *qgroup, bool verbose)
 {
 	int i;
@@ -1369,7 +1376,8 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, bool verbose)
 	n = rb_first(&qgroup_lookup->root);
 	while (n) {
 		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
-		print_single_qgroup_table(entry, verbose);
+		if (qgroup_target_exists(entry) || verbose)
+			print_single_qgroup_table(entry, verbose);
 		n = rb_next(n);
 	}
 }
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output
  2018-05-16 21:38 ` [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output jeffm
@ 2018-05-18  4:55   ` Misono Tomohiro
  0 siblings, 0 replies; 20+ messages in thread
From: Misono Tomohiro @ 2018-05-18  4:55 UTC (permalink / raw)
  To: jeffm, linux-btrfs

On 2018/05/17 6:38, jeffm@suse.com wrote:
> From: Jeff Mahoney <jeffm@suse.com>
> 
> The btrfs qgroup show command currently only exports qgroup IDs,
> forcing the user to resolve which subvolume each corresponds to.
> 
> This patch adds pathname resolution to qgroup show so that when
> the -P option is used, the last column contains the pathname of
> the root of the subvolume it describes.  In the case of nested
> qgroups, it will show the number of member qgroups or the paths
> of the members if the -v option is used.
> 
> Pathname can also be used as a sort parameter.
> 
> Reviewed-by: Qu Wenruo <wqu@suse.com>
> Signed-off-by: Jeff Mahoney <jeffm@suse.com>
> ---
>  Documentation/btrfs-qgroup.asciidoc |   4 +
>  cmds-qgroup.c                       |  18 ++++-
>  kerncompat.h                        |   1 +
>  qgroup.c                            | 149 ++++++++++++++++++++++++++++++++----
>  qgroup.h                            |   4 +-
>  5 files changed, 157 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/btrfs-qgroup.asciidoc b/Documentation/btrfs-qgroup.asciidoc
> index 3108457c..360b3269 100644
> --- a/Documentation/btrfs-qgroup.asciidoc
> +++ b/Documentation/btrfs-qgroup.asciidoc
> @@ -97,10 +97,14 @@ print child qgroup id.
>  print limit of referenced size of qgroup.
>  -e::::
>  print limit of exclusive size of qgroup.
> +-P::::
> +print pathname to the root of the subvolume managed by qgroup.  For nested qgroups, the number of members will be printed unless -v is specified.
>  -F::::
>  list all qgroups which impact the given path(include ancestral qgroups)
>  -f::::
>  list all qgroups which impact the given path(exclude ancestral qgroups)
> +-v::::
> +Be more verbose.  Print pathnames of member qgroups when nested.
>  --raw::::
>  raw numbers in bytes, without the 'B' suffix.
>  --human-readable::::
> diff --git a/cmds-qgroup.c b/cmds-qgroup.c
> index 93206900..33053725 100644
> --- a/cmds-qgroup.c
> +++ b/cmds-qgroup.c
> @@ -282,8 +282,11 @@ static const char * const cmd_qgroup_show_usage[] = {
>  	"               (including ancestral qgroups)",
>  	"-f             list all qgroups which impact the given path",
>  	"               (excluding ancestral qgroups)",
> +	"-P             print first-level qgroups using pathname",
> +	"               - nested qgroups will be reported as a count",
> +	"-v             verbose, prints pathnames for all nested qgroups",
>  	HELPINFO_UNITS_LONG,
> -	"--sort=qgroupid,rfer,excl,max_rfer,max_excl",
> +	"--sort=qgroupid,rfer,excl,max_rfer,max_excl,pathname",
>  	"               list qgroups sorted by specified items",
>  	"               you can use '+' or '-' in front of each item.",
>  	"               (+:ascending, -:descending, ascending default)",
> @@ -302,6 +305,7 @@ static int cmd_qgroup_show(int argc, char **argv)
>  	unsigned unit_mode;
>  	int sync = 0;
>  	enum btrfs_util_error err;
> +	bool verbose = false;
>  
>  	struct btrfs_qgroup_comparer_set *comparer_set;
>  	struct btrfs_qgroup_filter_set *filter_set;
> @@ -319,10 +323,11 @@ static int cmd_qgroup_show(int argc, char **argv)
>  		static const struct option long_options[] = {
>  			{"sort", required_argument, NULL, GETOPT_VAL_SORT},
>  			{"sync", no_argument, NULL, GETOPT_VAL_SYNC},
> +			{"verbose", no_argument, NULL, 'v'},
>  			{ NULL, 0, NULL, 0 }
>  		};
>  
> -		c = getopt_long(argc, argv, "pcreFf", long_options, NULL);
> +		c = getopt_long(argc, argv, "pPcreFfv", long_options, NULL);
>  		if (c < 0)
>  			break;
>  		switch (c) {
> @@ -330,6 +335,10 @@ static int cmd_qgroup_show(int argc, char **argv)
>  			btrfs_qgroup_setup_print_column(
>  				BTRFS_QGROUP_PARENT);
>  			break;
> +		case 'P':
> +			btrfs_qgroup_setup_print_column(
> +				BTRFS_QGROUP_PATHNAME);
> +			break;
>  		case 'c':
>  			btrfs_qgroup_setup_print_column(
>  				BTRFS_QGROUP_CHILD);
> @@ -357,6 +366,9 @@ static int cmd_qgroup_show(int argc, char **argv)
>  		case GETOPT_VAL_SYNC:
>  			sync = 1;
>  			break;
> +		case 'v':
> +			verbose = true;
> +			break;
>  		default:
>  			usage(cmd_qgroup_show_usage);
>  		}
> @@ -398,7 +410,7 @@ static int cmd_qgroup_show(int argc, char **argv)
>  					BTRFS_QGROUP_FILTER_PARENT,
>  					qgroupid);
>  	}
> -	ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
> +	ret = btrfs_show_qgroups(fd, filter_set, comparer_set, verbose);
>  	close_file_or_dir(fd, dirstream);
>  	free(filter_set);
>  	free(comparer_set);
> diff --git a/kerncompat.h b/kerncompat.h
> index fa96715f..f97495ee 100644
> --- a/kerncompat.h
> +++ b/kerncompat.h
> @@ -29,6 +29,7 @@
>  #include <stddef.h>
>  #include <linux/types.h>
>  #include <stdint.h>
> +#include <stdbool.h>
>  
>  #include <features.h>
>  
> diff --git a/qgroup.c b/qgroup.c
> index 3269feb2..d8baca33 100644
> --- a/qgroup.c
> +++ b/qgroup.c
> @@ -21,6 +21,7 @@
>  #include "ctree.h"
>  #include "ioctl.h"
>  #include "utils.h"
> +#include "btrfsutil.h"
>  #include <errno.h>
>  
>  #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
> @@ -40,6 +41,9 @@ struct btrfs_qgroup {
>  	struct rb_node all_parent_node;
>  	u64 qgroupid;
>  
> +	/* NULL for qgroups with level > 0 */
> +	const char *pathname;
> +
>  	/*
>  	 * info_item
>  	 */
> @@ -133,6 +137,13 @@ static struct {
>  		.unit_mode	= 0,
>  		.max_len	= 5,
>  	},
> +	{
> +		.name		= "pathname",
> +		.column_name	= "pathname",
> +		.need_print	= 0,
> +		.unit_mode	= 0,
> +		.max_len	= 10,
> +	},
>  	{
>  		.name		= NULL,
>  		.column_name	= NULL,
> @@ -210,8 +221,50 @@ static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
>  		printf(" ");
>  }
>  
> +void print_pathname_column(struct btrfs_qgroup *qgroup, bool verbose)
> +{
> +	struct btrfs_qgroup_list *list = NULL;
> +
> +	fputs("  ", stdout);
> +	if (btrfs_qgroup_level(qgroup->qgroupid) > 0) {
> +		int count = 0;
> +

Shouldn't this be:
> +		list_for_each_entry(list, &qgroup->qgroups,
                                                 ->members
> +				    next_qgroup) {
                                    next_members
> +			if (verbose) {
> +				struct btrfs_qgroup *member = list->qgroup;
                                                                  ->member
to print child qgroups instead of parents?

> +				u64 qgroupid = member->qgroupid;
> +				u64 level = btrfs_qgroup_level(qgroupid);
> +				u64 sid = btrfs_qgroup_subvid(qgroupid);
> +
> +				if (count)
> +					fputs(" ", stdout);
> +				if (level == 0) {
> +					const char *path = member->pathname;
> +
> +					if (!path)
> +						path = "<missing>";
> +					fputs(path, stdout);
                               Maybe we should add <FS_TREE>/ here too.

> +				} else
> +					printf("%llu/%llu", level, sid);
> +			}
> +			count++;
> +		}
> +		if (!count)
> +			fputs("<empty>", stdout);
> +		else if (!verbose)
> +			printf("<%u member qgroup%c>", count,
> +			       count != 1 ? 's' : '\0');
> +	} else if (qgroup->pathname)
> +		printf("<FS_ROOT>%s%s", *qgroup->pathname ? "/" : "",
> +		       qgroup->pathname);
> +	else
> +		fputs("<missing>", stdout);
> +}
> +
>  static void print_qgroup_column(struct btrfs_qgroup *qgroup,
> -				enum btrfs_qgroup_column_enum column)
> +				enum btrfs_qgroup_column_enum column,
> +				bool verbose)
>  {
>  	int len;
>  	int unit_mode = btrfs_qgroup_columns[column].unit_mode;
> @@ -253,19 +306,22 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
>  		len = print_child_column(qgroup);
>  		print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len);
>  		break;
> +	case BTRFS_QGROUP_PATHNAME:
> +		print_pathname_column(qgroup, verbose);
> +		break;
>  	default:
>  		break;
>  	}
>  }
>  
> -static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
> +static void print_single_qgroup_table(struct btrfs_qgroup *qgroup, bool verbose)
>  {
>  	int i;
>  
>  	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
>  		if (!btrfs_qgroup_columns[i].need_print)
>  			continue;
> -		print_qgroup_column(qgroup, i);
> +		print_qgroup_column(qgroup, i, verbose);
>  
>  		if (i != BTRFS_QGROUP_ALL - 1)
>  			printf(" ");
> @@ -338,6 +394,47 @@ static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
>  	return is_descending ? -ret : ret;
>  }
>  
> +/* Sorts first-level qgroups by pathname and nested qgroups by qgroupid */
> +static int comp_entry_with_pathname(struct btrfs_qgroup *entry1,
> +				    struct btrfs_qgroup *entry2,
> +				    int is_descending)
> +{
> +	int ret = 0;
> +	const char *p1 = entry1->pathname;
> +	const char *p2 = entry2->pathname;
> +
> +	u64 level1 = btrfs_qgroup_level(entry1->qgroupid);
> +	u64 level2 = btrfs_qgroup_level(entry2->qgroupid);
> +
> +	if (level1 != level2) {
> +		if (entry1->qgroupid > entry2->qgroupid)
> +			ret = 1;
> +		else if (entry1->qgroupid < entry2->qgroupid)
> +			ret = -1;
> +	}
> +
> +	if (ret)
> +		goto out;
> +
> +	while (*p1 && *p2) {
> +		if (*p1 != *p2)
> +			break;
> +		p1++;
> +		p2++;
> +	}
> +
> +	if (*p1 == '/')
> +		ret = 1;
> +	else if (*p2 == '/')
> +		ret = -1;
> +	else if (*p1 > *p2)
> +		ret = 1;
> +	else if (*p1 < *p2)
> +		ret = -1;
> +out:
> +	return is_descending ? -ret : ret;
> +}
> +
>  static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
>  				struct btrfs_qgroup *entry2,
>  				int is_descending)
> @@ -404,6 +501,7 @@ static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
>  
>  static btrfs_qgroup_comp_func all_comp_funcs[] = {
>  	[BTRFS_QGROUP_COMP_QGROUPID]	= comp_entry_with_qgroupid,
> +	[BTRFS_QGROUP_COMP_PATHNAME]	= comp_entry_with_pathname,
>  	[BTRFS_QGROUP_COMP_RFER]	= comp_entry_with_rfer,
>  	[BTRFS_QGROUP_COMP_EXCL]	= comp_entry_with_excl,
>  	[BTRFS_QGROUP_COMP_MAX_RFER]	= comp_entry_with_max_rfer,
> @@ -412,6 +510,7 @@ static btrfs_qgroup_comp_func all_comp_funcs[] = {
>  
>  static char *all_sort_items[] = {
>  	[BTRFS_QGROUP_COMP_QGROUPID]	= "qgroupid",
> +	[BTRFS_QGROUP_COMP_PATHNAME]	= "pathname",
>  	[BTRFS_QGROUP_COMP_RFER]	= "rfer",
>  	[BTRFS_QGROUP_COMP_EXCL]	= "excl",
>  	[BTRFS_QGROUP_COMP_MAX_RFER]	= "max_rfer",
> @@ -588,7 +687,7 @@ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
>   * Return the pointer to the btrfs_qgroup if found or if inserted successfully.
>   * Return ERR_PTR if any error occurred.
>   */
> -static struct btrfs_qgroup *get_or_add_qgroup(
> +static struct btrfs_qgroup *get_or_add_qgroup(int fd,
>  		struct qgroup_lookup *qgroup_lookup, u64 qgroupid)
>  {
>  	struct btrfs_qgroup *bq;
> @@ -608,6 +707,23 @@ static struct btrfs_qgroup *get_or_add_qgroup(
>  	INIT_LIST_HEAD(&bq->qgroups);
>  	INIT_LIST_HEAD(&bq->members);
>  
> +	if (btrfs_qgroup_level(qgroupid) == 0) {
> +		enum btrfs_util_error uret;
> +		char *pathname;
> +
> +		uret = btrfs_util_subvolume_path_fd(fd, qgroupid, &pathname);
> +		if (uret == BTRFS_UTIL_OK)
> +			bq->pathname = pathname;
> +		/* Ignore stale qgroup items */
> +		else if (uret != BTRFS_UTIL_ERROR_SUBVOLUME_NOT_FOUND) {
> +			error("%s", btrfs_util_strerror(uret));
> +			if (uret == BTRFS_UTIL_ERROR_NO_MEMORY)
> +				return ERR_PTR(-ENOMEM);
> +			else
> +				return ERR_PTR(-EIO);
> +		}
> +	}
> +
>  	ret = qgroup_tree_insert(qgroup_lookup, bq);
>  	if (ret) {
>  		error("failed to insert %llu into tree: %s",
> @@ -619,12 +735,12 @@ static struct btrfs_qgroup *get_or_add_qgroup(
>  	return bq;
>  }
>  
> -static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
> -			      struct btrfs_qgroup_info_item *info)
> +static int update_qgroup_info(int fd, struct qgroup_lookup *qgroup_lookup,
> +			      u64 qgroupid, struct btrfs_qgroup_info_item *info)
>  {
>  	struct btrfs_qgroup *bq;
>  
> -	bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
> +	bq = get_or_add_qgroup(fd, qgroup_lookup, qgroupid);
>  	if (IS_ERR_OR_NULL(bq))
>  		return PTR_ERR(bq);
>  
> @@ -637,13 +753,13 @@ static int update_qgroup_info(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
>  	return 0;
>  }
>  
> -static int update_qgroup_limit(struct qgroup_lookup *qgroup_lookup,
> +static int update_qgroup_limit(int fd, struct qgroup_lookup *qgroup_lookup,
>  			       u64 qgroupid,
>  			       struct btrfs_qgroup_limit_item *limit)
>  {
>  	struct btrfs_qgroup *bq;
>  
> -	bq = get_or_add_qgroup(qgroup_lookup, qgroupid);
> +	bq = get_or_add_qgroup(fd, qgroup_lookup, qgroupid);
>  	if (IS_ERR_OR_NULL(bq))
>  		return PTR_ERR(bq);
>  
> @@ -712,6 +828,8 @@ static void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
>  		list_del(&list->next_member);
>  		free(list);
>  	}
> +	if (bq->pathname)
> +		free((void *)bq->pathname);
>  	free(bq);
>  }
>  
> @@ -1107,7 +1225,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
>  				info = (struct btrfs_qgroup_info_item *)
>  				       (args.buf + off);
>  
> -				ret = update_qgroup_info(qgroup_lookup,
> +				ret = update_qgroup_info(fd, qgroup_lookup,
>  							 qgroupid, info);
>  				break;
>  			case BTRFS_QGROUP_LIMIT_KEY:
> @@ -1115,7 +1233,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
>  				limit = (struct btrfs_qgroup_limit_item *)
>  					(args.buf + off);
>  
> -				ret = update_qgroup_limit(qgroup_lookup,
> +				ret = update_qgroup_limit(fd, qgroup_lookup,
>  							  qgroupid, limit);
>  				break;
>  			case BTRFS_QGROUP_RELATION_KEY:
> @@ -1159,7 +1277,7 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
>  	return ret;
>  }
>  
> -static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
> +static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, bool verbose)
>  {
>  
>  	struct rb_node *n;
> @@ -1170,14 +1288,15 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
>  	n = rb_first(&qgroup_lookup->root);
>  	while (n) {
>  		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
> -		print_single_qgroup_table(entry);
> +		print_single_qgroup_table(entry, verbose);
>  		n = rb_next(n);
>  	}
>  }
>  
>  int btrfs_show_qgroups(int fd,
>  		       struct btrfs_qgroup_filter_set *filter_set,
> -		       struct btrfs_qgroup_comparer_set *comp_set)
> +		       struct btrfs_qgroup_comparer_set *comp_set,
> +		       bool verbose)
>  {
>  
>  	struct qgroup_lookup qgroup_lookup;
> @@ -1189,7 +1308,7 @@ int btrfs_show_qgroups(int fd,
>  		return ret;
>  	__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
>  				  filter_set, comp_set);
> -	print_all_qgroups(&sort_tree);
> +	print_all_qgroups(&sort_tree, verbose);
>  
>  	__free_all_qgroups(&qgroup_lookup);
>  	return ret;
> diff --git a/qgroup.h b/qgroup.h
> index 875fbdf3..f7ab7de5 100644
> --- a/qgroup.h
> +++ b/qgroup.h
> @@ -59,11 +59,13 @@ enum btrfs_qgroup_column_enum {
>  	BTRFS_QGROUP_MAX_EXCL,
>  	BTRFS_QGROUP_PARENT,
>  	BTRFS_QGROUP_CHILD,
> +	BTRFS_QGROUP_PATHNAME,
>  	BTRFS_QGROUP_ALL,
>  };
>  
>  enum btrfs_qgroup_comp_enum {
>  	BTRFS_QGROUP_COMP_QGROUPID,
> +	BTRFS_QGROUP_COMP_PATHNAME,
>  	BTRFS_QGROUP_COMP_RFER,
>  	BTRFS_QGROUP_COMP_EXCL,
>  	BTRFS_QGROUP_COMP_MAX_RFER,
> @@ -80,7 +82,7 @@ enum btrfs_qgroup_filter_enum {
>  int btrfs_qgroup_parse_sort_string(const char *opt_arg,
>  				struct btrfs_qgroup_comparer_set **comps);
>  int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
> -		       struct btrfs_qgroup_comparer_set *);
> +		       struct btrfs_qgroup_comparer_set *, bool verbose);
>  void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
>  void btrfs_qgroup_setup_units(unsigned unit_mode);
>  struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
> 


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2018-05-18  4:55 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-16 21:38 [PATCH v3 00/18] btrfs-progs: qgroups-usability jeffm
2018-05-16 21:38 ` [PATCH 01/18] btrfs-progs: quota: Add -W option to rescan to wait without starting rescan jeffm
2018-05-16 21:38 ` [PATCH 02/18] btrfs-progs: qgroups: fix misleading index check jeffm
2018-05-16 21:38 ` [PATCH 03/18] btrfs-progs: constify pathnames passed as arguments jeffm
2018-05-16 21:38 ` [PATCH 04/18] btrfs-progs: btrfs-list: add rb_entry helpers for root_info jeffm
2018-05-16 21:38 ` [PATCH 05/18] btrfs-progs: qgroups: add pathname to show output jeffm
2018-05-18  4:55   ` Misono Tomohiro
2018-05-16 21:38 ` [PATCH 06/18] btrfs-progs: qgroups: introduce and use info and limit structures jeffm
2018-05-16 21:38 ` [PATCH 07/18] btrfs-progs: qgroups: introduce btrfs_qgroup_query jeffm
2018-05-16 21:38 ` [PATCH 08/18] btrfs-progs: subvolume: add quota info to btrfs sub show jeffm
2018-05-16 21:38 ` [PATCH 09/18] btrfs-progs: help: convert ints used as bools to bool jeffm
2018-05-16 21:38 ` [PATCH 10/18] btrfs-progs: reorder placement of help declarations for send/receive jeffm
2018-05-16 21:38 ` [PATCH 11/18] btrfs-progs: filesystem balance: split out special handling jeffm
2018-05-16 21:38 ` [PATCH 12/18] btrfs-progs: use cmd_struct as command entry point jeffm
2018-05-16 21:38 ` [PATCH 13/18] btrfs-progs: pass cmd_struct to command callback function jeffm
2018-05-16 21:38 ` [PATCH 14/18] btrfs-progs: pass cmd_struct to clean_args_no_options{,_relaxed} jeffm
2018-05-16 21:38 ` [PATCH 15/18] btrfs-progs: pass cmd_struct to usage() jeffm
2018-05-16 21:38 ` [PATCH 16/18] btrfs-progs: add support for output formats jeffm
2018-05-16 21:38 ` [PATCH 17/18] btrfs-progs: handle command groups directly for common case jeffm
2018-05-16 21:38 ` [PATCH 18/18] btrfs-progs: qgroups: don't print dead qgroups jeffm

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.