linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/9] enhance btrfs qgroup show command
@ 2013-09-23  6:17 Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 1/9] Btrfs-progs: restructure show_qgroups Wang Shilong
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

The patchset enhanced btrfs qgroup show command.

Firstly, we restructure show_qgroups, make it easy to add new features.
And then we add '-p' '-c', '-l',and '-e' options to print the parent
qgroup id, child qgroup id, max referenced size and max exclusive size
of qgroup respectively, add '-F' and '-f' option to list qgroups that
impact the given path.

Besides that, the users may want to sort qgroups according to some items.
For this case, we introduce '--sort' option. With this option, we can sort
the qgroup by qgroupid, rfer, excl, max_rfer and max_excl.

And finally, Since there are so many columns can be output, the users may
be confused about the output result, so i add '-t' option to print the result
as a table.

You can pull this patchset from the URL:
	git://github.com/wangshilong/Btrfs-progs.git qgroup

Changelog v1->v2:
	rebase the patchset on david's integration-20130920

Wang Shilong (9):
  Btrfs-progs: restructure show_qgroups
  Btrfs-progs: introduces '-p' option to print the ID of the parent
    qgroups
  Btrfs-progs: introduces '-c' option to print the ID of the child
    qgroups
  Btrfs-progs: introduce '-l' option to print max referenced size of
    qgroups
  Btrfs-progs: introduce '-e' option to print max exclusive size of
    qgroups
  Btrfs-progs: list all qgroups impact given path(include ancestral
    qgroups)
  Btrfs-progs: list all qgroups impact given path(exclude ancestral
    qgroups)
  Btrfs-progs: enhance btrfs qgroup show to sort qgroups
  Btrfs-progs: enhance btrfs qgroup to print the result as a table

 cmds-qgroup.c |  190 ++++-----
 ctree.h       |   11 +
 qgroup.c      | 1218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qgroup.h      |   71 ++++
 4 files changed, 1396 insertions(+), 94 deletions(-)

-- 
1.8.3.1


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

* [PATCH v2 1/9] Btrfs-progs: restructure show_qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 2/9] Btrfs-progs: introduces '-p' option to print the ID of the parent qgroups Wang Shilong
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

The current show_qgroups() just shows a little information, and it is hard to
add some functions which the users need in the future, so i restructure it, make
it easy to add new functions.

In order to improve the scalability of show_qgroups(), i add some important
structures:

	struct qgroup_lookup {
		struct rb_root root;
	}
 	/*
	*store qgroup's information
	*/
	struct btrfs_qgroup {
		struct rb_node  rb_node;
		u64 qgroupid;

		u64 generation;
		u64 rfer;
		u64 rfer_cmpr;
		u64 excl_cmpr;

		u64 flags;
		u64 max_rfer;
		u64 max_excl;
		u64 rsv_rfer;
		u64 rsv_excl;

		struct list_head qgroups;
		struct list_head members;
	}
	/*
	*glue structure to represent the relations
	*between qgroups
	*/
	struct btrfs_qgroup_list {
		struct list_head next_qgroups;
		struct list_head next_member;
		struct btrfs_qgroup *qgroup;
		struct btrfs_qgroup *member;
	}
The above 3 structures are used to manage all the information
of qgroups.

	struct {
		char *name;
		char *column_name;
		int need_print;
	} btrfs_qgroup_columns[]

We define a arrary to manage all the columns that can be
outputed, and use a member variant(->need_print) to control
the output of the relative column. Some columns are outputed
by default. But we can change it according to the requirement
of the users.

For example:
	if outputing max referenced size of qgroup is needed,the function
'btrfs_qgroup_setup_column()' will be called, and the parameter 'BTRFS_QGROUP_MAX_RFER'
(extend in the future) will be passsed to the function. After the function is done,
when showing qgroups, max referenced size of qgroup will be output.

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c |  91 +----------
 ctree.h       |  11 ++
 qgroup.c      | 509 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qgroup.h      |  10 ++
 4 files changed, 531 insertions(+), 90 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index ff2a1fa..d3c699f 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -106,95 +106,6 @@ static int qgroup_create(int create, int argc, char **argv)
 	return 0;
 }
 
-static void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
-{
-	printf("%llu/%llu %lld %lld\n", objectid >> 48,
-		objectid & ((1ll << 48) - 1),
-		btrfs_stack_qgroup_info_referenced(info),
-		btrfs_stack_qgroup_info_exclusive(info));
-}
-
-static int list_qgroups(int fd)
-{
-	int ret;
-	struct btrfs_ioctl_search_args args;
-	struct btrfs_ioctl_search_key *sk = &args.key;
-	struct btrfs_ioctl_search_header *sh;
-	unsigned long off = 0;
-	unsigned int i;
-	struct btrfs_qgroup_info_item *info;
-
-	memset(&args, 0, sizeof(args));
-
-	/* search in the quota tree */
-	sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
-
-	/*
-	 * set the min and max to backref keys.  The search will
-	 * only send back this type of key now.
-	 */
-	sk->max_type = BTRFS_QGROUP_INFO_KEY;
-	sk->min_type = BTRFS_QGROUP_INFO_KEY;
-	sk->max_objectid = 0;
-	sk->max_offset = (u64)-1;
-	sk->max_transid = (u64)-1;
-
-	/* just a big number, doesn't matter much */
-	sk->nr_items = 4096;
-
-	while (1) {
-		ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-		if (ret < 0)
-			return ret;
-
-		/* the ioctl returns the number of item it found in nr_items */
-		if (sk->nr_items == 0)
-			break;
-
-		off = 0;
-
-		/*
-		 * for each item, pull the key out of the header and then
-		 * read the root_ref item it contains
-		 */
-		for (i = 0; i < sk->nr_items; i++) {
-			sh = (struct btrfs_ioctl_search_header *)(args.buf +
-								  off);
-			off += sizeof(*sh);
-
-			if (sh->objectid != 0)
-				goto done;
-
-			if (sh->type != BTRFS_QGROUP_INFO_KEY)
-				goto done;
-
-			info = (struct btrfs_qgroup_info_item *)
-					(args.buf + off);
-			print_qgroup_info(sh->offset, info);
-
-			off += sh->len;
-
-			/*
-			 * record the mins in sk so we can make sure the
-			 * next search doesn't repeat this root
-			 */
-			sk->min_offset = sh->offset;
-		}
-		sk->nr_items = 4096;
-		/*
-		 * this iteration is done, step forward one qgroup for the next
-		 * ioctl
-		 */
-		if (sk->min_offset < (u64)-1)
-			sk->min_offset++;
-		else
-			break;
-	}
-
-done:
-	return ret;
-}
-
 static int parse_limit(const char *p, unsigned long long *s)
 {
 	char *endptr;
@@ -313,7 +224,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 		return 1;
 	}
 
-	ret = list_qgroups(fd);
+	ret = btrfs_show_qgroups(fd);
 	e = errno;
 	close_file_or_dir(fd, dirstream);
 	if (ret < 0)
diff --git a/ctree.h b/ctree.h
index 5b4c859..c90581a 100644
--- a/ctree.h
+++ b/ctree.h
@@ -2059,6 +2059,17 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_referenced, struct btrfs_qgroup_limit_item,
 BTRFS_SETGET_FUNCS(qgroup_limit_rsv_exclusive, struct btrfs_qgroup_limit_item,
 		   rsv_exclusive, 64);
 
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags,
+			 struct btrfs_qgroup_limit_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_referenced,
+			 struct btrfs_qgroup_limit_item, max_referenced, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_exclusive,
+			 struct btrfs_qgroup_limit_item, max_exclusive, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_referenced,
+			 struct btrfs_qgroup_limit_item, rsv_referenced, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_exclusive,
+			 struct btrfs_qgroup_limit_item, rsv_exclusive, 64);
+
 /* this returns the number of file bytes represented by the inline item.
  * If an item is compressed, this is the uncompressed size
  */
diff --git a/qgroup.c b/qgroup.c
index 86fe2b2..bd9658e 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -17,7 +17,516 @@
  */
 
 #include "qgroup.h"
+#include <sys/ioctl.h>
 #include "ctree.h"
+#include "ioctl.h"
+
+struct qgroup_lookup {
+	struct rb_root root;
+};
+
+struct btrfs_qgroup {
+	struct rb_node rb_node;
+	u64 qgroupid;
+
+	/*
+	 * info_item
+	 */
+	u64 generation;
+	u64 rfer;	/*referenced*/
+	u64 rfer_cmpr;	/*referenced compressed*/
+	u64 excl;	/*exclusive*/
+	u64 excl_cmpr;	/*exclusive compressed*/
+
+	/*
+	 *limit_item
+	 */
+	u64 flags;	/*which limits are set*/
+	u64 max_rfer;
+	u64 max_excl;
+	u64 rsv_rfer;
+	u64 rsv_excl;
+
+	/*qgroups this group is member of*/
+	struct list_head qgroups;
+	/*qgroups that are members of this group*/
+	struct list_head members;
+};
+
+/*
+ * glue structure to represent the relations
+ * between qgroups
+ */
+struct btrfs_qgroup_list {
+	struct list_head next_qgroup;
+	struct list_head next_member;
+	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup *member;
+};
+
+/*
+ * qgroupid,rfer,excl default to set
+ */
+struct {
+	char *name;
+	char *column_name;
+	int need_print;
+} btrfs_qgroup_columns[] = {
+	{
+		.name		= "qgroupid",
+		.column_name	= "Qgroupid",
+		.need_print	= 1,
+	},
+	{
+		.name		= "rfer",
+		.column_name	= "Rfer",
+		.need_print	= 1,
+	},
+	{
+		.name		= "excl",
+		.column_name	= "Excl",
+		.need_print	= 1,
+	},
+	{
+		.name		= NULL,
+		.column_name	= NULL,
+		.need_print	= 0,
+	},
+};
+
+void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
+{
+	int i;
+
+	BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
+
+	if (column < BTRFS_QGROUP_ALL) {
+		btrfs_qgroup_columns[column].need_print = 1;
+		return;
+	}
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++)
+		btrfs_qgroup_columns[i].need_print = 1;
+}
+
+static void print_qgroup_column(struct btrfs_qgroup *qgroup,
+				enum btrfs_qgroup_column_enum column)
+{
+	BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
+
+	switch (column) {
+
+	case BTRFS_QGROUP_QGROUPID:
+		printf("%llu/%llu", qgroup->qgroupid >> 48,
+		       ((1ll << 48) - 1) & qgroup->qgroupid);
+		break;
+	case BTRFS_QGROUP_RFER:
+		printf("%lld", qgroup->rfer);
+		break;
+	case BTRFS_QGROUP_EXCL:
+		printf("%lld", qgroup->excl);
+		break;
+	default:
+		break;
+	}
+}
+
+static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+		if (!btrfs_qgroup_columns[i].need_print)
+			continue;
+		print_qgroup_column(qgroup, i);
+
+		if (i != BTRFS_QGROUP_ALL - 1)
+			printf(" ");
+	}
+	printf("\n");
+}
+
+static void qgroup_lookup_init(struct qgroup_lookup *tree)
+{
+	tree->root.rb_node = NULL;
+}
+
+static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
+				    struct btrfs_qgroup *entry2,
+				    int is_descending)
+{
+
+	int ret;
+
+	if (entry1->qgroupid > entry2->qgroupid)
+		ret = 1;
+	else if (entry1->qgroupid < entry2->qgroupid)
+		ret = -1;
+	else
+		ret = 0;
+
+	return is_descending ? -ret : ret;
+}
+
+/*
+ * insert a new root into the tree.  returns the existing root entry
+ * if one is already there.  qgroupid is used
+ * as the key
+ */
+static int qgroup_tree_insert(struct qgroup_lookup *root_tree,
+			      struct btrfs_qgroup *ins)
+{
+
+	struct rb_node **p = &root_tree->root.rb_node;
+	struct rb_node *parent = NULL;
+	struct btrfs_qgroup *curr;
+	int ret;
+
+	while (*p) {
+		parent = *p;
+		curr = rb_entry(parent, struct btrfs_qgroup, rb_node);
+
+		ret = comp_entry_with_qgroupid(ins, curr, 0);
+		if (ret < 0)
+			p = &(*p)->rb_left;
+		else if (ret > 0)
+			p = &(*p)->rb_right;
+		else
+			return -EEXIST;
+	}
+	rb_link_node(&ins->rb_node, parent, p);
+	rb_insert_color(&ins->rb_node, &root_tree->root);
+	return 0;
+}
+
+/*
+ *find a given qgroupid in the tree. We return the smallest one,
+ *rb_next can be used to move forward looking for more if required
+ */
+static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
+					       u64 qgroupid)
+{
+	struct rb_node *n = root_tree->root.rb_node;
+	struct btrfs_qgroup *entry;
+	struct btrfs_qgroup tmp;
+	int ret;
+
+	tmp.qgroupid = qgroupid;
+
+	while (n) {
+		entry = rb_entry(n, struct btrfs_qgroup, rb_node);
+
+		ret = comp_entry_with_qgroupid(&tmp, entry, 0);
+		if (ret < 0)
+			n = n->rb_left;
+		else if (ret > 0)
+			n = n->rb_right;
+		else
+			return entry;
+
+	}
+	return NULL;
+}
+
+static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
+			 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
+			 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
+			 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
+			 struct btrfs_qgroup *child)
+{
+	struct btrfs_qgroup *bq;
+	struct btrfs_qgroup_list *list;
+
+	bq = qgroup_tree_search(qgroup_lookup, qgroupid);
+	if (!bq || bq->qgroupid != qgroupid)
+		return -ENOENT;
+
+	if (generation)
+		bq->generation = generation;
+	if (rfer)
+		bq->rfer = rfer;
+	if (rfer_cmpr)
+		bq->rfer_cmpr = rfer_cmpr;
+	if (excl)
+		bq->excl = excl;
+	if (excl_cmpr)
+		bq->excl_cmpr = excl_cmpr;
+	if (flags)
+		bq->flags = flags;
+	if (max_rfer)
+		bq->max_rfer = max_rfer;
+	if (max_excl)
+		bq->max_excl = max_excl;
+	if (rsv_rfer)
+		bq->rsv_rfer = rsv_rfer;
+	if (pa && child) {
+		list = malloc(sizeof(*list));
+		if (!list) {
+			fprintf(stderr, "memory allocation failed\n");
+			exit(1);
+		}
+		list->qgroup = pa;
+		list->member = child;
+		list_add_tail(&list->next_qgroup, &child->qgroups);
+		list_add_tail(&list->next_member, &pa->members);
+	}
+	return 0;
+}
+
+static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
+		      u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
+		      u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
+		      u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
+		      struct btrfs_qgroup *child)
+{
+	struct btrfs_qgroup *bq;
+	struct btrfs_qgroup_list *list;
+	int ret;
+
+	ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
+			    rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
+			    max_excl, rsv_rfer, rsv_excl, parent, child);
+	if (!ret)
+		return 0;
+
+	bq = malloc(sizeof(*bq));
+	if (!bq) {
+		printf("memory allocation failed\n");
+		exit(1);
+	}
+	memset(bq, 0, sizeof(*bq));
+	if (qgroupid) {
+		bq->qgroupid = qgroupid;
+		INIT_LIST_HEAD(&bq->qgroups);
+		INIT_LIST_HEAD(&bq->members);
+	}
+	if (generation)
+		bq->generation = generation;
+	if (rfer)
+		bq->rfer = rfer;
+	if (rfer_cmpr)
+		bq->rfer_cmpr = rfer_cmpr;
+	if (excl)
+		bq->excl = excl;
+	if (excl_cmpr)
+		bq->excl_cmpr = excl_cmpr;
+	if (flags)
+		bq->flags = flags;
+	if (max_rfer)
+		bq->max_rfer = max_rfer;
+	if (max_excl)
+		bq->max_excl = max_excl;
+	if (rsv_rfer)
+		bq->rsv_rfer = rsv_rfer;
+	if (parent && child) {
+		list = malloc(sizeof(*list));
+		if (!list) {
+			fprintf(stderr, "memory allocation failed\n");
+			exit(1);
+		}
+		list->qgroup = parent;
+		list->member = child;
+		list_add_tail(&list->next_qgroup, &child->qgroups);
+		list_add_tail(&list->next_member, &parent->members);
+	}
+	ret = qgroup_tree_insert(qgroup_lookup, bq);
+	if (ret) {
+		printf("failed to insert tree %llu\n",
+		       bq->qgroupid);
+		exit(1);
+	}
+	return ret;
+}
+
+void __free_btrfs_qgroup(struct btrfs_qgroup *bq)
+{
+	struct btrfs_qgroup_list *list;
+	while (!list_empty(&bq->qgroups)) {
+		list = list_entry((&bq->qgroups)->next,
+				  struct btrfs_qgroup_list,
+				  next_qgroup);
+		list_del(&list->next_qgroup);
+		list_del(&list->next_member);
+		free(list);
+	}
+	while (!list_empty(&bq->members)) {
+		list = list_entry((&bq->members)->next,
+				  struct btrfs_qgroup_list,
+				  next_member);
+		list_del(&list->next_qgroup);
+		list_del(&list->next_member);
+		free(list);
+	}
+	free(bq);
+}
+
+void __free_all_qgroups(struct qgroup_lookup *root_tree)
+{
+	struct btrfs_qgroup *entry;
+	struct rb_node *n;
+
+	n = rb_first(&root_tree->root);
+	while (n) {
+		entry = rb_entry(n, struct btrfs_qgroup, rb_node);
+		rb_erase(n, &root_tree->root);
+		__free_btrfs_qgroup(entry);
+
+		n = rb_first(&root_tree->root);
+	}
+}
+
+static int __qgroups_search(int fd, 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_header *sh;
+	unsigned long off = 0;
+	unsigned int i;
+	int e;
+	struct btrfs_qgroup_info_item *info;
+	struct btrfs_qgroup_limit_item *limit;
+	struct btrfs_qgroup *bq;
+	struct btrfs_qgroup *bq1;
+	u64 a1;
+	u64 a2;
+	u64 a3;
+	u64 a4;
+	u64 a5;
+
+	memset(&args, 0, sizeof(args));
+
+	sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
+	sk->max_type = BTRFS_QGROUP_RELATION_KEY;
+	sk->min_type = BTRFS_QGROUP_INFO_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);
+		e = errno;
+		if (ret < 0) {
+			fprintf(stderr,
+				"ERROR: can't perform the search - %s\n",
+				strerror(e));
+			return ret;
+		}
+		/* the ioctl returns the number of item it found in nr_items */
+		if (sk->nr_items == 0)
+			break;
+
+		off = 0;
+		/*
+		 * for each item, pull the key out of the header and then
+		 * read the root_ref item it contains
+		 */
+		for (i = 0; i < sk->nr_items; i++) {
+			sh = (struct btrfs_ioctl_search_header *)(args.buf +
+								  off);
+			off += sizeof(*sh);
+
+			if (sh->type == BTRFS_QGROUP_INFO_KEY) {
+				info = (struct btrfs_qgroup_info_item *)
+				       (args.buf + off);
+				a1 = btrfs_stack_qgroup_info_generation(info);
+				a2 = btrfs_stack_qgroup_info_referenced(info);
+				a3 =
+				  btrfs_stack_qgroup_info_referenced_compressed
+				  (info);
+				a4 = btrfs_stack_qgroup_info_exclusive(info);
+				a5 =
+				  btrfs_stack_qgroup_info_exclusive_compressed
+				  (info);
+				add_qgroup(qgroup_lookup, sh->offset, a1, a2,
+					   a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
+			} else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
+				limit = (struct btrfs_qgroup_limit_item *)
+				    (args.buf + off);
+
+				a1 = btrfs_stack_qgroup_limit_flags(limit);
+				a2 = btrfs_stack_qgroup_limit_max_referenced
+				     (limit);
+				a3 = btrfs_stack_qgroup_limit_max_exclusive
+				     (limit);
+				a4 = btrfs_stack_qgroup_limit_rsv_referenced
+				     (limit);
+				a5 = btrfs_stack_qgroup_limit_rsv_exclusive
+				     (limit);
+				add_qgroup(qgroup_lookup, sh->offset, 0, 0,
+					   0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
+			} else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
+				if (sh->offset < sh->objectid)
+					goto skip;
+				bq = qgroup_tree_search(qgroup_lookup,
+							sh->offset);
+				if (!bq)
+					goto skip;
+				bq1 = qgroup_tree_search(qgroup_lookup,
+							 sh->objectid);
+				if (!bq1)
+					goto skip;
+				add_qgroup(qgroup_lookup, sh->offset, 0, 0,
+					   0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
+			} else
+				goto done;
+skip:
+			off += sh->len;
+
+			/*
+			 * record the mins in sk so we can make sure the
+			 * next search doesn't repeat this root
+			 */
+			sk->min_type = sh->type;
+			sk->min_offset = sh->offset;
+			sk->min_objectid = sh->objectid;
+		}
+		sk->nr_items = 4096;
+		/*
+		 * this iteration is done, step forward one qgroup for the next
+		 * ioctl
+		 */
+		if (sk->min_offset < (u64)-1)
+			sk->min_offset++;
+		else
+			break;
+	}
+
+done:
+	return ret;
+}
+
+static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
+{
+
+	struct rb_node *n;
+	struct btrfs_qgroup *entry;
+
+	n = rb_first(&qgroup_lookup->root);
+	while (n) {
+		entry = rb_entry(n, struct btrfs_qgroup, rb_node);
+		print_single_qgroup_default(entry);
+		n = rb_next(n);
+	}
+}
+
+int btrfs_show_qgroups(int fd)
+{
+
+	struct qgroup_lookup qgroup_lookup;
+	int ret;
+
+	ret = __qgroups_search(fd, &qgroup_lookup);
+	if (ret)
+		return ret;
+
+	print_all_qgroups(&qgroup_lookup);
+	__free_all_qgroups(&qgroup_lookup);
+
+	return ret;
+}
 
 u64 parse_qgroupid(char *p)
 {
diff --git a/qgroup.h b/qgroup.h
index da6d113..8b34cd7 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -22,6 +22,16 @@
 #include "ioctl.h"
 #include "kerncompat.h"
 
+enum btrfs_qgroup_column_enum {
+	BTRFS_QGROUP_QGROUPID,
+	BTRFS_QGROUP_RFER,
+	BTRFS_QGROUP_EXCL,
+	BTRFS_QGROUP_ALL,
+};
+
+int  btrfs_show_qgroups(int fd);
+void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
+
 u64 parse_qgroupid(char *p);
 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p);
 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg);
-- 
1.8.3.1


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

* [PATCH v2 2/9] Btrfs-progs: introduces '-p' option to print the ID of the parent qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 1/9] Btrfs-progs: restructure show_qgroups Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 3/9] Btrfs-progs: introduces '-c' option to print the ID of the child qgroups Wang Shilong
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduces '-p' option to print the ID of the parent qgroups.
You may use it like:

	btrfs qgroup show -p <path>
For Example:
                qgroupid(2/0)
                /         \
               /           \
              /             \
        qgroupid(1/0)  qgroupid(1/1)
              \              /
               \            /
                qgroupid(0/1)

If we use the command:

	btrfs qgroup show -p <path>
The result will output
	0/1 -- -- 1/0,1/1
	1/0 -- -- 2/0
	1/1 -- -- 2/0
	2/0 -- -- --

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c | 23 ++++++++++++++++++++---
 qgroup.c      | 22 ++++++++++++++++++++++
 qgroup.h      |  1 +
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index d3c699f..96098c1 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,22 +202,39 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show <path>",
+	"btrfs qgroup show -p <path>",
 	"Show all subvolume quota groups.",
+	"-p		print parent qgroup id",
 	NULL
 };
 
 static int cmd_qgroup_show(int argc, char **argv)
 {
+	char *path;
 	int ret = 0;
 	int fd;
 	int e;
-	char *path = argv[1];
 	DIR *dirstream = NULL;
+	int c;
 
-	if (check_argc_exact(argc, 2))
+	optind = 1;
+	while (1) {
+		c = getopt(argc, argv, "p");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'p':
+			btrfs_qgroup_setup_print_column(
+				BTRFS_QGROUP_PARENT);
+			break;
+		default:
+			usage(cmd_qgroup_show_usage);
+		}
+	}
+	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_qgroup_show_usage);
 
+	path = argv[optind];
 	fd = open_file_or_dir(path, &dirstream);
 	if (fd < 0) {
 		fprintf(stderr, "ERROR: can't access '%s'\n", path);
diff --git a/qgroup.c b/qgroup.c
index bd9658e..0dbf28c 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -88,6 +88,11 @@ struct {
 		.need_print	= 1,
 	},
 	{
+		.name		= "parent",
+		.column_name	= "Parent",
+		.need_print	= 0,
+	},
+	{
 		.name		= NULL,
 		.column_name	= NULL,
 		.need_print	= 0,
@@ -108,6 +113,20 @@ void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
 		btrfs_qgroup_columns[i].need_print = 1;
 }
 
+static void print_parent_column(struct btrfs_qgroup *qgroup)
+{
+	struct btrfs_qgroup_list *list = NULL;
+
+	list_for_each_entry(list, &qgroup->qgroups, next_qgroup) {
+		printf("%llu/%llu", (list->qgroup)->qgroupid >> 48,
+		      ((1ll << 48) - 1) & (list->qgroup)->qgroupid);
+		if (!list_is_last(&list->next_qgroup, &qgroup->qgroups))
+			printf(",");
+	}
+	if (list_empty(&qgroup->qgroups))
+		printf("---");
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 				enum btrfs_qgroup_column_enum column)
 {
@@ -125,6 +144,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	case BTRFS_QGROUP_EXCL:
 		printf("%lld", qgroup->excl);
 		break;
+	case BTRFS_QGROUP_PARENT:
+		print_parent_column(qgroup);
+		break;
 	default:
 		break;
 	}
diff --git a/qgroup.h b/qgroup.h
index 8b34cd7..cefdfe1 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -26,6 +26,7 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_QGROUPID,
 	BTRFS_QGROUP_RFER,
 	BTRFS_QGROUP_EXCL,
+	BTRFS_QGROUP_PARENT,
 	BTRFS_QGROUP_ALL,
 };
 
-- 
1.8.3.1


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

* [PATCH v2 3/9] Btrfs-progs: introduces '-c' option to print the ID of the child qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 1/9] Btrfs-progs: restructure show_qgroups Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 2/9] Btrfs-progs: introduces '-p' option to print the ID of the parent qgroups Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 4/9] Btrfs-progs: introduce '-l' option to print max referenced size of qgroups Wang Shilong
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduces '-c' option to print the ID of the child qgroups.
You may use it like:
	btrfs qgroup show -c <path>

For Example:

                qgroupid(2/0)
                 /       \
                /         \
               /           \
            qgroupid(1/0) qgroupid(1/1)
               \            /
                \          /
		 qgroupid(0/1)

If we use the command:

	btrfs qgroup show -c <path>
The result will output
	0/1 -- -- --
	1/0 -- -- 0/1
	1/1 -- -- 0/1
	2/0 -- -- 1/0,1/1

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c |  9 +++++++--
 qgroup.c      | 22 ++++++++++++++++++++++
 qgroup.h      |  1 +
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 96098c1..147bedc 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,9 +202,10 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -p <path>",
+	"btrfs qgroup show -pc <path>",
 	"Show all subvolume quota groups.",
 	"-p		print parent qgroup id",
+	"-c		print child qgroup id",
 	NULL
 };
 
@@ -219,7 +220,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "p");
+		c = getopt(argc, argv, "pc");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -227,6 +228,10 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_PARENT);
 			break;
+		case 'c':
+			btrfs_qgroup_setup_print_column(
+				BTRFS_QGROUP_CHILD);
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
diff --git a/qgroup.c b/qgroup.c
index 0dbf28c..1592dd4 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -93,6 +93,11 @@ struct {
 		.need_print	= 0,
 	},
 	{
+		.name		= "child",
+		.column_name	= "Child",
+		.need_print	= 0,
+	},
+	{
 		.name		= NULL,
 		.column_name	= NULL,
 		.need_print	= 0,
@@ -127,6 +132,20 @@ static void print_parent_column(struct btrfs_qgroup *qgroup)
 		printf("---");
 }
 
+static void print_child_column(struct btrfs_qgroup *qgroup)
+{
+	struct btrfs_qgroup_list *list = NULL;
+
+	list_for_each_entry(list, &qgroup->members, next_member) {
+		printf("%llu/%llu", (list->member)->qgroupid >> 48,
+		      ((1ll << 48) - 1) & (list->member)->qgroupid);
+		if (!list_is_last(&list->next_member, &qgroup->members))
+			printf(",");
+	}
+	if (list_empty(&qgroup->members))
+		printf("---");
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 				enum btrfs_qgroup_column_enum column)
 {
@@ -147,6 +166,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	case BTRFS_QGROUP_PARENT:
 		print_parent_column(qgroup);
 		break;
+	case BTRFS_QGROUP_CHILD:
+		print_child_column(qgroup);
+		break;
 	default:
 		break;
 	}
diff --git a/qgroup.h b/qgroup.h
index cefdfe1..33682ae 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -27,6 +27,7 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_RFER,
 	BTRFS_QGROUP_EXCL,
 	BTRFS_QGROUP_PARENT,
+	BTRFS_QGROUP_CHILD,
 	BTRFS_QGROUP_ALL,
 };
 
-- 
1.8.3.1


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

* [PATCH v2 4/9] Btrfs-progs: introduce '-l' option to print max referenced size of qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (2 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 3/9] Btrfs-progs: introduces '-c' option to print the ID of the child qgroups Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 5/9] Btrfs-progs: introduce '-e' option to print max exclusive " Wang Shilong
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduces '-l' option to print max referenced size of qgroups.
You may use it like:

		btrfs qgroup show -l <path>

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c | 9 +++++++--
 qgroup.c      | 7 +++++++
 qgroup.h      | 1 +
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 147bedc..32537f9 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,10 +202,11 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -pc <path>",
+	"btrfs qgroup show -pcl <path>",
 	"Show all subvolume quota groups.",
 	"-p		print parent qgroup id",
 	"-c		print child qgroup id",
+	"-l		print max referenced size of qgroup",
 	NULL
 };
 
@@ -220,7 +221,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "pc");
+		c = getopt(argc, argv, "pcl");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -232,6 +233,10 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_CHILD);
 			break;
+		case 'l':
+			btrfs_qgroup_setup_print_column(
+				BTRFS_QGROUP_MAX_RFER);
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
diff --git a/qgroup.c b/qgroup.c
index 1592dd4..f9eb52d 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -87,6 +87,10 @@ struct {
 		.column_name	= "Excl",
 		.need_print	= 1,
 	},
+	{	.name		= "max_rfer",
+		.column_name	= "Max_rfer",
+		.need_print	= 0,
+	},
 	{
 		.name		= "parent",
 		.column_name	= "Parent",
@@ -166,6 +170,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	case BTRFS_QGROUP_PARENT:
 		print_parent_column(qgroup);
 		break;
+	case BTRFS_QGROUP_MAX_RFER:
+		printf("%llu", qgroup->max_rfer);
+		break;
 	case BTRFS_QGROUP_CHILD:
 		print_child_column(qgroup);
 		break;
diff --git a/qgroup.h b/qgroup.h
index 33682ae..168fac0 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -26,6 +26,7 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_QGROUPID,
 	BTRFS_QGROUP_RFER,
 	BTRFS_QGROUP_EXCL,
+	BTRFS_QGROUP_MAX_RFER,
 	BTRFS_QGROUP_PARENT,
 	BTRFS_QGROUP_CHILD,
 	BTRFS_QGROUP_ALL,
-- 
1.8.3.1


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

* [PATCH v2 5/9] Btrfs-progs: introduce '-e' option to print max exclusive size of qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (3 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 4/9] Btrfs-progs: introduce '-l' option to print max referenced size of qgroups Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 6/9] Btrfs-progs: list all qgroups impact given path(include ancestral qgroups) Wang Shilong
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduce '-e' option to print max exclusive size of qgroups.
You may use it like this:
		btrfs qgroup -e <path>

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c | 9 +++++++--
 qgroup.c      | 8 ++++++++
 qgroup.h      | 1 +
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 32537f9..0bfca33 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,11 +202,12 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -pcl <path>",
+	"btrfs qgroup show -pcle <path>",
 	"Show all subvolume quota groups.",
 	"-p		print parent qgroup id",
 	"-c		print child qgroup id",
 	"-l		print max referenced size of qgroup",
+	"-e		print max exclusive size of qgroup",
 	NULL
 };
 
@@ -221,7 +222,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "pcl");
+		c = getopt(argc, argv, "pcle");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -237,6 +238,10 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_MAX_RFER);
 			break;
+		case 'e':
+			btrfs_qgroup_setup_print_column(
+				BTRFS_QGROUP_MAX_EXCL);
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
diff --git a/qgroup.c b/qgroup.c
index f9eb52d..2cd37b1 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -92,6 +92,11 @@ struct {
 		.need_print	= 0,
 	},
 	{
+		.name		= "max_excl",
+		.column_name	= "Max_excl",
+		.need_print	= 0,
+	},
+	{
 		.name		= "parent",
 		.column_name	= "Parent",
 		.need_print	= 0,
@@ -173,6 +178,9 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	case BTRFS_QGROUP_MAX_RFER:
 		printf("%llu", qgroup->max_rfer);
 		break;
+	case BTRFS_QGROUP_MAX_EXCL:
+		printf("%llu", qgroup->max_excl);
+		break;
 	case BTRFS_QGROUP_CHILD:
 		print_child_column(qgroup);
 		break;
diff --git a/qgroup.h b/qgroup.h
index 168fac0..e7a65ba 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -27,6 +27,7 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_RFER,
 	BTRFS_QGROUP_EXCL,
 	BTRFS_QGROUP_MAX_RFER,
+	BTRFS_QGROUP_MAX_EXCL,
 	BTRFS_QGROUP_PARENT,
 	BTRFS_QGROUP_CHILD,
 	BTRFS_QGROUP_ALL,
-- 
1.8.3.1


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

* [PATCH v2 6/9] Btrfs-progs: list all qgroups impact given path(include ancestral qgroups)
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (4 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 5/9] Btrfs-progs: introduce '-e' option to print max exclusive " Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 7/9] Btrfs-progs: list all qgroups impact given path(exclude " Wang Shilong
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduces '-F' option which can help you filter the qgroups
by the path name, you may use it like:

	btrfs qgroup show -F <path>
For example:

                         qgroupid(2/0)
                          /     \
                         /       \
                        qgroupid(1/0)
                        /         \
                       /           \
                      /             \
                  qgroupid(0/1)   qgroupid(0/2)
                  sub1              sub2
                  /  \
                 /    \
		dir1  file1

If we use the command:
	btrfs qgroup show -F sub1/dir1
The result will output
	0/1	--	--
	1/0	--	--
	2/0	--	--

'-F' option help you list all qgroups impact given path.
(include ancestral qgroups).

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c |  24 +++++-
 qgroup.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 qgroup.h      |  28 ++++++-
 3 files changed, 281 insertions(+), 10 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 0bfca33..5480d2a 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,12 +202,14 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -pcle <path>",
-	"Show all subvolume quota groups.",
+	"btrfs qgroup show -pcleF <path>",
+	"Show subvolume quota groups.",
 	"-p		print parent qgroup id",
 	"-c		print child qgroup id",
 	"-l		print max referenced size of qgroup",
 	"-e		print max exclusive size of qgroup",
+	"-F		list all qgroups which impact the given path"
+	"(include ancestral qgroups)",
 	NULL
 };
 
@@ -219,10 +221,15 @@ static int cmd_qgroup_show(int argc, char **argv)
 	int e;
 	DIR *dirstream = NULL;
 	int c;
+	u64 qgroupid;
+	int filter_flag = 0;
+
+	struct btrfs_qgroup_filter_set *filter_set;
+	filter_set = btrfs_qgroup_alloc_filter_set();
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "pcle");
+		c = getopt(argc, argv, "pcleF");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -242,6 +249,9 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_MAX_EXCL);
 			break;
+		case 'F':
+			filter_flag |= 0x1;
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
@@ -256,7 +266,13 @@ static int cmd_qgroup_show(int argc, char **argv)
 		return 1;
 	}
 
-	ret = btrfs_show_qgroups(fd);
+	if (filter_flag) {
+		qgroupid = btrfs_get_path_rootid(fd);
+		btrfs_qgroup_setup_filter(&filter_set,
+				BTRFS_QGROUP_FILTER_ALL_PARENT,
+				qgroupid);
+	}
+	ret = btrfs_show_qgroups(fd, filter_set);
 	e = errno;
 	close_file_or_dir(fd, dirstream);
 	if (ret < 0)
diff --git a/qgroup.c b/qgroup.c
index 2cd37b1..306b638 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -21,12 +21,20 @@
 #include "ctree.h"
 #include "ioctl.h"
 
+#define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
+
 struct qgroup_lookup {
 	struct rb_root root;
 };
 
 struct btrfs_qgroup {
 	struct rb_node rb_node;
+	struct rb_node sort_node;
+	/*
+	 *all_parent_node is used to
+	 *filter a qgroup's all parent
+	 */
+	struct rb_node all_parent_node;
 	u64 qgroupid;
 
 	/*
@@ -113,6 +121,8 @@ struct {
 	},
 };
 
+static btrfs_qgroup_filter_func all_filter_funcs[];
+
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
 {
 	int i;
@@ -433,6 +443,205 @@ void __free_all_qgroups(struct qgroup_lookup *root_tree)
 	}
 }
 
+static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
+				    struct btrfs_qgroup *bq)
+{
+	struct rb_node **p = &sort_tree->root.rb_node;
+	struct rb_node *parent = NULL;
+	struct btrfs_qgroup *curr;
+	int ret;
+
+	while (*p) {
+		parent = *p;
+		curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node);
+
+		ret = comp_entry_with_qgroupid(bq, curr, 0);
+		if (ret < 0)
+			p = &(*p)->rb_left;
+		else if (ret > 0)
+			p = &(*p)->rb_right;
+		else
+			return -EEXIST;
+	}
+	rb_link_node(&bq->all_parent_node, parent, p);
+	rb_insert_color(&bq->all_parent_node, &sort_tree->root);
+	return 0;
+}
+
+static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
+{
+	struct qgroup_lookup lookup;
+	struct qgroup_lookup *ql = &lookup;
+	struct btrfs_qgroup_list *list;
+	struct rb_node *n;
+	struct btrfs_qgroup *qgroup =
+			 (struct btrfs_qgroup *)(unsigned long)data;
+
+	if (data == 0)
+		return 0;
+	if (bq->qgroupid == qgroup->qgroupid)
+		return 1;
+
+	qgroup_lookup_init(ql);
+	filter_all_parent_insert(ql, qgroup);
+	n = rb_first(&ql->root);
+	while (n) {
+		qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node);
+		if (!list_empty(&qgroup->qgroups)) {
+			list_for_each_entry(list, &qgroup->qgroups,
+					    next_qgroup) {
+				if ((list->qgroup)->qgroupid == bq->qgroupid)
+					return 1;
+				filter_all_parent_insert(ql, list->qgroup);
+			}
+		}
+		rb_erase(n, &ql->root);
+		n = rb_first(&ql->root);
+	}
+	return 0;
+}
+
+static btrfs_qgroup_filter_func all_filter_funcs[] = {
+	[BTRFS_QGROUP_FILTER_ALL_PARENT]	= filter_by_all_parent,
+};
+
+struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void)
+{
+	struct btrfs_qgroup_filter_set *set;
+	int size;
+
+	size = sizeof(struct btrfs_qgroup_filter_set) +
+	       BTRFS_QGROUP_NFILTERS_INCREASE *
+	       sizeof(struct btrfs_qgroup_filter);
+	set = malloc(size);
+	if (!set) {
+		fprintf(stderr, "memory allocation failed\n");
+		exit(1);
+	}
+	memset(set, 0, size);
+	set->total = BTRFS_QGROUP_NFILTERS_INCREASE;
+
+	return set;
+}
+
+void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set)
+{
+	free(filter_set);
+}
+
+int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
+			      enum btrfs_qgroup_filter_enum filter, u64 data)
+{
+	struct btrfs_qgroup_filter_set *set = *filter_set;
+	int size;
+
+	BUG_ON(!set);
+	BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX);
+	BUG_ON(set->nfilters > set->total);
+
+	if (set->nfilters == set->total) {
+		size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE;
+		size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter);
+
+		set = realloc(set, size);
+		if (!set) {
+			fprintf(stderr, "memory allocation failed\n");
+			exit(1);
+		}
+		memset(&set->filters[set->total], 0,
+		       BTRFS_QGROUP_NFILTERS_INCREASE *
+		       sizeof(struct btrfs_qgroup_filter));
+		set->total += BTRFS_QGROUP_NFILTERS_INCREASE;
+		*filter_set = set;
+	}
+	BUG_ON(set->filters[set->nfilters].filter_func);
+	set->filters[set->nfilters].filter_func = all_filter_funcs[filter];
+	set->filters[set->nfilters].data = data;
+	set->nfilters++;
+	return 0;
+}
+
+static int filter_qgroup(struct btrfs_qgroup *bq,
+			 struct btrfs_qgroup_filter_set *set)
+{
+	int i, ret;
+
+	if (!set || !set->nfilters)
+		return 1;
+	for (i = 0; i < set->nfilters; i++) {
+		if (!set->filters[i].filter_func)
+			break;
+		ret = set->filters[i].filter_func(bq, set->filters[i].data);
+		if (!ret)
+			return 0;
+	}
+	return 1;
+}
+
+static void pre_process_filter_set(struct qgroup_lookup *lookup,
+				   struct btrfs_qgroup_filter_set *set)
+{
+	int i;
+	struct btrfs_qgroup *qgroup_for_filter = NULL;
+
+	for (i = 0; i < set->nfilters; i++) {
+
+		if (set->filters[i].filter_func == filter_by_all_parent) {
+			qgroup_for_filter = qgroup_tree_search(lookup,
+					    set->filters[i].data);
+			set->filters[i].data =
+				 (u64)(unsigned long)qgroup_for_filter;
+		}
+	}
+}
+
+static int sort_tree_insert(struct qgroup_lookup *sort_tree,
+			    struct btrfs_qgroup *bq)
+{
+	struct rb_node **p = &sort_tree->root.rb_node;
+	struct rb_node *parent = NULL;
+	struct btrfs_qgroup *curr;
+	int ret;
+
+	while (*p) {
+		parent = *p;
+		curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
+
+		ret = comp_entry_with_qgroupid(bq, curr, 0);
+		if (ret < 0)
+			p = &(*p)->rb_left;
+		else if (ret > 0)
+			p = &(*p)->rb_right;
+		else
+			return -EEXIST;
+	}
+	rb_link_node(&bq->sort_node, parent, p);
+	rb_insert_color(&bq->sort_node, &sort_tree->root);
+	return 0;
+}
+
+static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups,
+				 struct qgroup_lookup *sort_tree,
+				 struct btrfs_qgroup_filter_set *filter_set)
+{
+	struct rb_node *n;
+	struct btrfs_qgroup *entry;
+	int ret;
+
+	qgroup_lookup_init(sort_tree);
+	pre_process_filter_set(all_qgroups, filter_set);
+
+	n = rb_last(&all_qgroups->root);
+	while (n) {
+		entry = rb_entry(n, struct btrfs_qgroup, rb_node);
+
+		ret = filter_qgroup(entry, filter_set);
+		if (ret)
+			sort_tree_insert(sort_tree, entry);
+
+		n = rb_prev(n);
+	}
+}
 static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 {
 	int ret;
@@ -565,28 +774,50 @@ 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, rb_node);
+		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
 		print_single_qgroup_default(entry);
 		n = rb_next(n);
 	}
 }
 
-int btrfs_show_qgroups(int fd)
+int btrfs_show_qgroups(int fd,
+		       struct btrfs_qgroup_filter_set *filter_set)
 {
 
 	struct qgroup_lookup qgroup_lookup;
+	struct qgroup_lookup sort_tree;
 	int ret;
 
 	ret = __qgroups_search(fd, &qgroup_lookup);
 	if (ret)
 		return ret;
+	__filter_all_qgroups(&qgroup_lookup, &sort_tree,
+			     filter_set);
+	print_all_qgroups(&sort_tree);
 
-	print_all_qgroups(&qgroup_lookup);
 	__free_all_qgroups(&qgroup_lookup);
-
+	btrfs_qgroup_free_filter_set(filter_set);
 	return ret;
 }
 
+u64 btrfs_get_path_rootid(int fd)
+{
+	int  ret;
+	struct btrfs_ioctl_ino_lookup_args args;
+
+	memset(&args, 0, sizeof(args));
+	args.objectid = BTRFS_FIRST_FREE_OBJECTID;
+
+	ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
+	if (ret < 0) {
+		fprintf(stderr,
+			"ERROR: can't perform the search -%s\n",
+			strerror(errno));
+		return ret;
+	}
+	return args.treeid;
+}
+
 u64 parse_qgroupid(char *p)
 {
 	char *s = strchr(p, '/');
diff --git a/qgroup.h b/qgroup.h
index e7a65ba..bcc2b4b 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -22,6 +22,21 @@
 #include "ioctl.h"
 #include "kerncompat.h"
 
+struct btrfs_qgroup;
+
+typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64);
+
+struct btrfs_qgroup_filter {
+	btrfs_qgroup_filter_func filter_func;
+	u64 data;
+};
+
+struct btrfs_qgroup_filter_set {
+	int total;
+	int nfilters;
+	struct btrfs_qgroup_filter filters[0];
+};
+
 enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_QGROUPID,
 	BTRFS_QGROUP_RFER,
@@ -33,9 +48,18 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_ALL,
 };
 
-int  btrfs_show_qgroups(int fd);
-void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
+enum btrfs_qgroup_filter_enum {
+	BTRFS_QGROUP_FILTER_ALL_PARENT,
+	BTRFS_QGROUP_FILTER_MAX,
+};
 
+u64 btrfs_get_path_rootid(int fd);
+int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *);
+void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
+struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
+void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set);
+int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
+			      enum btrfs_qgroup_filter_enum, u64 data);
 u64 parse_qgroupid(char *p);
 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p);
 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg);
-- 
1.8.3.1


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

* [PATCH v2 7/9] Btrfs-progs: list all qgroups impact given path(exclude ancestral qgroups)
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (5 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 6/9] Btrfs-progs: list all qgroups impact given path(include ancestral qgroups) Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 8/9] Btrfs-progs: enhance btrfs qgroup show to sort qgroups Wang Shilong
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduces '-f' option which can help you filter the qgroups
by the path name, you may use it like:

	btrfs qgroup show -f <path>
For example:

                         qgroupid(2/0)
                          /     \
                         /       \
                        qgroupid(1/0)
                        /         \
                       /           \
                      /             \
                  qgroupid(0/1)   qgroupid(0/2)
                  sub1              sub2
                  /  \
                 /    \
		dir1  file1

If we use the command:
	btrfs qgroup show -f sub1/dir1
The result will output
	0/1	--	--

'-f' option helps you list all qgroups impact given path.
(exclude ancestral qgroups)

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c | 18 ++++++++++++++----
 qgroup.c      | 16 +++++++++++++++-
 qgroup.h      |  1 +
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 5480d2a..bcf0487 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -210,6 +210,8 @@ static const char * const cmd_qgroup_show_usage[] = {
 	"-e		print max exclusive size of qgroup",
 	"-F		list all qgroups which impact the given path"
 	"(include ancestral qgroups)",
+	"-f		list all qgroups which impact the given path"
+	"(exclude ancestral qgroups)",
 	NULL
 };
 
@@ -229,7 +231,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "pcleF");
+		c = getopt(argc, argv, "pcleFf");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -252,6 +254,9 @@ static int cmd_qgroup_show(int argc, char **argv)
 		case 'F':
 			filter_flag |= 0x1;
 			break;
+		case 'f':
+			filter_flag |= 0x2;
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
@@ -268,9 +273,14 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	if (filter_flag) {
 		qgroupid = btrfs_get_path_rootid(fd);
-		btrfs_qgroup_setup_filter(&filter_set,
-				BTRFS_QGROUP_FILTER_ALL_PARENT,
-				qgroupid);
+		if (filter_flag & 0x1)
+			btrfs_qgroup_setup_filter(&filter_set,
+					BTRFS_QGROUP_FILTER_ALL_PARENT,
+					qgroupid);
+		if (filter_flag & 0x2)
+			btrfs_qgroup_setup_filter(&filter_set,
+					BTRFS_QGROUP_FILTER_PARENT,
+					qgroupid);
 	}
 	ret = btrfs_show_qgroups(fd, filter_set);
 	e = errno;
diff --git a/qgroup.c b/qgroup.c
index 306b638..28772d6 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -468,6 +468,18 @@ static int filter_all_parent_insert(struct qgroup_lookup *sort_tree,
 	return 0;
 }
 
+static int filter_by_parent(struct btrfs_qgroup *bq, u64 data)
+{
+	struct btrfs_qgroup *qgroup =
+		(struct btrfs_qgroup *)(unsigned long)data;
+
+	if (data == 0)
+		return 0;
+	if (qgroup->qgroupid == bq->qgroupid)
+		return 1;
+	return 0;
+}
+
 static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
 {
 	struct qgroup_lookup lookup;
@@ -502,6 +514,7 @@ static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data)
 }
 
 static btrfs_qgroup_filter_func all_filter_funcs[] = {
+	[BTRFS_QGROUP_FILTER_PARENT]		= filter_by_parent,
 	[BTRFS_QGROUP_FILTER_ALL_PARENT]	= filter_by_all_parent,
 };
 
@@ -586,7 +599,8 @@ static void pre_process_filter_set(struct qgroup_lookup *lookup,
 
 	for (i = 0; i < set->nfilters; i++) {
 
-		if (set->filters[i].filter_func == filter_by_all_parent) {
+		if (set->filters[i].filter_func == filter_by_all_parent
+		    || set->filters[i].filter_func == filter_by_parent) {
 			qgroup_for_filter = qgroup_tree_search(lookup,
 					    set->filters[i].data);
 			set->filters[i].data =
diff --git a/qgroup.h b/qgroup.h
index bcc2b4b..5fcdd8a 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -49,6 +49,7 @@ enum btrfs_qgroup_column_enum {
 };
 
 enum btrfs_qgroup_filter_enum {
+	BTRFS_QGROUP_FILTER_PARENT,
 	BTRFS_QGROUP_FILTER_ALL_PARENT,
 	BTRFS_QGROUP_FILTER_MAX,
 };
-- 
1.8.3.1


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

* [PATCH v2 8/9] Btrfs-progs: enhance btrfs qgroup show to sort qgroups
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (6 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 7/9] Btrfs-progs: list all qgroups impact given path(exclude " Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-09-23  6:17 ` [PATCH v2 9/9] Btrfs-progs: enhance btrfs qgroup to print the result as a table Wang Shilong
  2013-10-01 11:19 ` [PATCH v2 0/9] enhance btrfs qgroup show command David Sterba
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

You might want to list qgroups in order of some items, such as 'qgroupid', 'rfer'
and so on, you can use '--sort'. Now you can sort the qgroups by 'qgroupid',
'rfer','excl','max_rfer' and 'max_excl'.

For example:
	If you want to list qgroups in order of 'qgroupid'.
You can use the option like that:

	btrfs qgroup show --sort=+/-qgroupid <path>
Here, '+' means the result is sorted by ascending order. '-' is by descending
order. If you don't specify either '+' nor '-', the result is sorted by
default - ascending order.

If you want to combine sort items, you do it like that:
	btrfs qgroup show  --sort=-qgroupid,+rfer,max_rfer,excl <path>

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c |  25 +++++-
 qgroup.c      | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 qgroup.h      |  33 +++++++-
 3 files changed, 302 insertions(+), 12 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index bcf0487..780fb21 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,7 +202,8 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -pcleF <path>",
+	"btrfs qgroup show -pcleF "
+	"[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>",
 	"Show subvolume quota groups.",
 	"-p		print parent qgroup id",
 	"-c		print child qgroup id",
@@ -212,6 +213,11 @@ static const char * const cmd_qgroup_show_usage[] = {
 	"(include ancestral qgroups)",
 	"-f		list all qgroups which impact the given path"
 	"(exclude ancestral qgroups)",
+	"--sort=qgroupid,rfer,excl,max_rfer,max_excl",
+	"		list qgroups in order of qgroupid,"
+	"rfer,max_rfer or max_excl",
+	"		you can use '+' or '-' in front of each item.",
+	"		(+:ascending, -:descending, ascending default",
 	NULL
 };
 
@@ -226,12 +232,19 @@ static int cmd_qgroup_show(int argc, char **argv)
 	u64 qgroupid;
 	int filter_flag = 0;
 
+	struct btrfs_qgroup_comparer_set *comparer_set;
 	struct btrfs_qgroup_filter_set *filter_set;
 	filter_set = btrfs_qgroup_alloc_filter_set();
+	comparer_set = btrfs_qgroup_alloc_comparer_set();
+	struct option long_options[] = {
+		{"sort", 1, NULL, 'S'},
+		{0, 0, 0, 0}
+	};
 
 	optind = 1;
 	while (1) {
-		c = getopt(argc, argv, "pcleFf");
+		c = getopt_long(argc, argv, "pcleFf",
+				long_options, NULL);
 		if (c < 0)
 			break;
 		switch (c) {
@@ -257,6 +270,12 @@ static int cmd_qgroup_show(int argc, char **argv)
 		case 'f':
 			filter_flag |= 0x2;
 			break;
+		case 'S':
+			ret = btrfs_qgroup_parse_sort_string(optarg,
+							     &comparer_set);
+			if (ret)
+				usage(cmd_qgroup_show_usage);
+			break;
 		default:
 			usage(cmd_qgroup_show_usage);
 		}
@@ -282,7 +301,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 					BTRFS_QGROUP_FILTER_PARENT,
 					qgroupid);
 	}
-	ret = btrfs_show_qgroups(fd, filter_set);
+	ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
 	e = errno;
 	close_file_or_dir(fd, dirstream);
 	if (ret < 0)
diff --git a/qgroup.c b/qgroup.c
index 28772d6..84f5fc1 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -22,6 +22,7 @@
 #include "ioctl.h"
 
 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
+#define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
 
 struct qgroup_lookup {
 	struct rb_root root;
@@ -122,6 +123,7 @@ struct {
 };
 
 static btrfs_qgroup_filter_func all_filter_funcs[];
+static btrfs_qgroup_comp_func all_comp_funcs[];
 
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
 {
@@ -236,6 +238,188 @@ static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1,
 	return is_descending ? -ret : ret;
 }
 
+static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
+				struct btrfs_qgroup *entry2,
+				int is_descending)
+{
+	int ret;
+
+	if (entry1->rfer > entry2->rfer)
+		ret = 1;
+	else if (entry1->rfer < entry2->rfer)
+		ret = -1;
+	else
+		ret = 0;
+
+	return is_descending ? -ret : ret;
+}
+
+static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
+				struct btrfs_qgroup *entry2,
+				int is_descending)
+{
+	int ret;
+
+	if (entry1->excl > entry2->excl)
+		ret = 1;
+	else if (entry1->excl < entry2->excl)
+		ret = -1;
+	else
+		ret = 0;
+
+	return is_descending ? -ret : ret;
+}
+
+static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
+				    struct btrfs_qgroup *entry2,
+				    int is_descending)
+{
+	int ret;
+
+	if (entry1->max_rfer > entry2->max_rfer)
+		ret = 1;
+	else if (entry1->max_rfer < entry2->max_rfer)
+		ret = -1;
+	else
+		ret = 0;
+
+	return is_descending ? -ret : ret;
+}
+
+static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
+				    struct btrfs_qgroup *entry2,
+				    int is_descending)
+{
+	int ret;
+
+	if (entry1->max_excl > entry2->max_excl)
+		ret = 1;
+	else if (entry1->max_excl < entry2->max_excl)
+		ret = -1;
+	else
+		ret = 0;
+
+	return is_descending ? -ret : ret;
+}
+
+static btrfs_qgroup_comp_func all_comp_funcs[] = {
+	[BTRFS_QGROUP_COMP_QGROUPID]	= comp_entry_with_qgroupid,
+	[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,
+	[BTRFS_QGROUP_COMP_MAX_EXCL]	= comp_entry_with_max_excl
+};
+
+static char *all_sort_items[] = {
+	[BTRFS_QGROUP_COMP_QGROUPID]	= "qgroupid",
+	[BTRFS_QGROUP_COMP_RFER]	= "rfer",
+	[BTRFS_QGROUP_COMP_EXCL]	= "excl",
+	[BTRFS_QGROUP_COMP_MAX_RFER]	= "max_rfer",
+	[BTRFS_QGROUP_COMP_MAX_EXCL]	= "max_excl",
+	[BTRFS_QGROUP_COMP_MAX]		= NULL,
+};
+
+static int  btrfs_qgroup_get_sort_item(char *sort_name)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) {
+		if (strcmp(sort_name, all_sort_items[i]) == 0)
+			return i;
+	}
+	return -1;
+}
+
+struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void)
+{
+	struct btrfs_qgroup_comparer_set *set;
+	int size;
+	size = sizeof(struct btrfs_qgroup_comparer_set) +
+	       BTRFS_QGROUP_NCOMPS_INCREASE *
+	       sizeof(struct btrfs_qgroup_comparer);
+	set = malloc(size);
+	if (!set) {
+		fprintf(stderr, "memory allocation failed\n");
+		exit(1);
+	}
+
+	memset(set, 0, size);
+	set->total = BTRFS_QGROUP_NCOMPS_INCREASE;
+
+	return set;
+}
+
+void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set)
+{
+	free(comp_set);
+}
+
+int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set  **comp_set,
+				enum btrfs_qgroup_comp_enum comparer,
+				int is_descending)
+{
+	struct btrfs_qgroup_comparer_set *set = *comp_set;
+	int size;
+
+	BUG_ON(!set);
+	BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX);
+	BUG_ON(set->ncomps > set->total);
+
+	if (set->ncomps == set->total) {
+		size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE;
+		size = sizeof(*set) +
+		       size * sizeof(struct btrfs_qgroup_comparer);
+		set = realloc(set, size);
+		if (!set) {
+			fprintf(stderr, "memory allocation failed\n");
+			exit(1);
+		}
+
+		memset(&set->comps[set->total], 0,
+		       BTRFS_QGROUP_NCOMPS_INCREASE *
+		       sizeof(struct btrfs_qgroup_comparer));
+		set->total += BTRFS_QGROUP_NCOMPS_INCREASE;
+		*comp_set = set;
+	}
+
+	BUG_ON(set->comps[set->ncomps].comp_func);
+
+	set->comps[set->ncomps].comp_func = all_comp_funcs[comparer];
+	set->comps[set->ncomps].is_descending = is_descending;
+	set->ncomps++;
+	return 0;
+}
+
+static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2,
+		     struct btrfs_qgroup_comparer_set *set)
+{
+	int qgroupid_compared = 0;
+	int i, ret = 0;
+
+	if (!set || !set->ncomps)
+		goto comp_qgroupid;
+
+	for (i = 0; i < set->ncomps; i++) {
+		if (!set->comps[i].comp_func)
+			break;
+
+		ret = set->comps[i].comp_func(entry1, entry2,
+					      set->comps[i].is_descending);
+		if (ret)
+			return ret;
+
+		if (set->comps[i].comp_func == comp_entry_with_qgroupid)
+			qgroupid_compared = 1;
+	}
+
+	if (!qgroupid_compared) {
+comp_qgroupid:
+		ret = comp_entry_with_qgroupid(entry1, entry2, 0);
+	}
+
+	return ret;
+}
+
 /*
  * insert a new root into the tree.  returns the existing root entry
  * if one is already there.  qgroupid is used
@@ -610,7 +794,8 @@ static void pre_process_filter_set(struct qgroup_lookup *lookup,
 }
 
 static int sort_tree_insert(struct qgroup_lookup *sort_tree,
-			    struct btrfs_qgroup *bq)
+			    struct btrfs_qgroup *bq,
+			    struct btrfs_qgroup_comparer_set *comp_set)
 {
 	struct rb_node **p = &sort_tree->root.rb_node;
 	struct rb_node *parent = NULL;
@@ -621,7 +806,7 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree,
 		parent = *p;
 		curr = rb_entry(parent, struct btrfs_qgroup, sort_node);
 
-		ret = comp_entry_with_qgroupid(bq, curr, 0);
+		ret = sort_comp(bq, curr, comp_set);
 		if (ret < 0)
 			p = &(*p)->rb_left;
 		else if (ret > 0)
@@ -634,9 +819,10 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree,
 	return 0;
 }
 
-static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups,
+static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
 				 struct qgroup_lookup *sort_tree,
-				 struct btrfs_qgroup_filter_set *filter_set)
+				 struct btrfs_qgroup_filter_set *filter_set,
+				 struct btrfs_qgroup_comparer_set *comp_set)
 {
 	struct rb_node *n;
 	struct btrfs_qgroup *entry;
@@ -651,7 +837,7 @@ static void __filter_all_qgroups(struct qgroup_lookup *all_qgroups,
 
 		ret = filter_qgroup(entry, filter_set);
 		if (ret)
-			sort_tree_insert(sort_tree, entry);
+			sort_tree_insert(sort_tree, entry, comp_set);
 
 		n = rb_prev(n);
 	}
@@ -795,7 +981,8 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
 }
 
 int btrfs_show_qgroups(int fd,
-		       struct btrfs_qgroup_filter_set *filter_set)
+		       struct btrfs_qgroup_filter_set *filter_set,
+		       struct btrfs_qgroup_comparer_set *comp_set)
 {
 
 	struct qgroup_lookup qgroup_lookup;
@@ -805,8 +992,8 @@ int btrfs_show_qgroups(int fd,
 	ret = __qgroups_search(fd, &qgroup_lookup);
 	if (ret)
 		return ret;
-	__filter_all_qgroups(&qgroup_lookup, &sort_tree,
-			     filter_set);
+	__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
+				  filter_set, comp_set);
 	print_all_qgroups(&sort_tree);
 
 	__free_all_qgroups(&qgroup_lookup);
@@ -832,6 +1019,59 @@ u64 btrfs_get_path_rootid(int fd)
 	return args.treeid;
 }
 
+int btrfs_qgroup_parse_sort_string(char *opt_arg,
+				   struct btrfs_qgroup_comparer_set **comps)
+{
+	int order;
+	int flag;
+	char *p;
+	char **ptr_argv;
+	int what_to_sort;
+
+	while ((p = strtok(opt_arg, ",")) != NULL) {
+		flag = 0;
+		ptr_argv = all_sort_items;
+
+		while (*ptr_argv) {
+			if (strcmp(*ptr_argv, p) == 0) {
+				flag = 1;
+				break;
+			} else {
+				p++;
+				if (strcmp(*ptr_argv, p) == 0) {
+					flag = 1;
+					p--;
+					break;
+				}
+				p--;
+			}
+			ptr_argv++;
+		}
+
+		if (flag == 0)
+			return -1;
+
+		else {
+			if (*p == '+') {
+				order = 0;
+				p++;
+			} else if (*p == '-') {
+				order = 1;
+				p++;
+			} else
+				order = 0;
+
+			what_to_sort = btrfs_qgroup_get_sort_item(p);
+			if (what_to_sort < 0)
+				return -1;
+			btrfs_qgroup_setup_comparer(comps, what_to_sort, order);
+		}
+		opt_arg = NULL;
+	}
+
+	return 0;
+}
+
 u64 parse_qgroupid(char *p)
 {
 	char *s = strchr(p, '/');
diff --git a/qgroup.h b/qgroup.h
index 5fcdd8a..653cf1c 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -25,18 +25,32 @@
 struct btrfs_qgroup;
 
 typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64);
+typedef int (*btrfs_qgroup_comp_func)(struct btrfs_qgroup *,
+				      struct btrfs_qgroup *, int);
+
 
 struct btrfs_qgroup_filter {
 	btrfs_qgroup_filter_func filter_func;
 	u64 data;
 };
 
+struct btrfs_qgroup_comparer {
+	btrfs_qgroup_comp_func comp_func;
+	int is_descending;
+};
+
 struct btrfs_qgroup_filter_set {
 	int total;
 	int nfilters;
 	struct btrfs_qgroup_filter filters[0];
 };
 
+struct btrfs_qgroup_comparer_set {
+	int total;
+	int ncomps;
+	struct btrfs_qgroup_comparer comps[0];
+};
+
 enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_QGROUPID,
 	BTRFS_QGROUP_RFER,
@@ -48,19 +62,36 @@ enum btrfs_qgroup_column_enum {
 	BTRFS_QGROUP_ALL,
 };
 
+enum btrfs_qgroup_comp_enum {
+	BTRFS_QGROUP_COMP_QGROUPID,
+	BTRFS_QGROUP_COMP_RFER,
+	BTRFS_QGROUP_COMP_EXCL,
+	BTRFS_QGROUP_COMP_MAX_RFER,
+	BTRFS_QGROUP_COMP_MAX_EXCL,
+	BTRFS_QGROUP_COMP_MAX
+};
+
 enum btrfs_qgroup_filter_enum {
 	BTRFS_QGROUP_FILTER_PARENT,
 	BTRFS_QGROUP_FILTER_ALL_PARENT,
 	BTRFS_QGROUP_FILTER_MAX,
 };
 
+int btrfs_qgroup_parse_sort_string(char *opt_arg,
+				struct btrfs_qgroup_comparer_set **comps);
 u64 btrfs_get_path_rootid(int fd);
-int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *);
+int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
+		       struct btrfs_qgroup_comparer_set *);
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set);
 int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set,
 			      enum btrfs_qgroup_filter_enum, u64 data);
+struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void);
+void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set);
+int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set,
+				enum btrfs_qgroup_comp_enum comparer,
+				int is_descending);
 u64 parse_qgroupid(char *p);
 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p);
 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg);
-- 
1.8.3.1


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

* [PATCH v2 9/9] Btrfs-progs: enhance btrfs qgroup to print the result as a table
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (7 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 8/9] Btrfs-progs: enhance btrfs qgroup show to sort qgroups Wang Shilong
@ 2013-09-23  6:17 ` Wang Shilong
  2013-10-01 11:19 ` [PATCH v2 0/9] enhance btrfs qgroup show command David Sterba
  9 siblings, 0 replies; 13+ messages in thread
From: Wang Shilong @ 2013-09-23  6:17 UTC (permalink / raw)
  To: linux-btrfs

From: Wang Shilong <wangsl-fnst@cn.fujitsu.com>

This patch introduce '-t' option which can help you print the result
as a table.

You can use it like:
	btrfs qgroup show -t <path>
However, to table the result better, we make '-p' and '-c' not present
at the same time.If you still want to show both of them at the same time,
you may print the result without '-t' option.

For example:

	btrfs qgroup show -tpl <path>
The result will output as the follow format:

qgroupid rfer       excl       max_excl       parent
-------- ----       ----       --------       ------
0/265    1289752576 1289752576 0              ---
1/0      0          0          10999511627776 2/0,3/0
2/0      0          0          0              ---
3/0      0          0          0              ---

Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
---
 cmds-qgroup.c |  20 ++++++-
 qgroup.c      | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 qgroup.h      |   3 +-
 3 files changed, 191 insertions(+), 11 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 780fb21..1f71e3c 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -202,13 +202,14 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-	"btrfs qgroup show -pcleF "
+	"btrfs qgroup show -pcleFt "
 	"[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>",
 	"Show subvolume quota groups.",
 	"-p		print parent qgroup id",
 	"-c		print child qgroup id",
 	"-l		print max referenced size of qgroup",
 	"-e		print max exclusive size of qgroup",
+	"-t		print the result as a table",
 	"-F		list all qgroups which impact the given path"
 	"(include ancestral qgroups)",
 	"-f		list all qgroups which impact the given path"
@@ -231,6 +232,8 @@ static int cmd_qgroup_show(int argc, char **argv)
 	int c;
 	u64 qgroupid;
 	int filter_flag = 0;
+	int is_table_result = 0;
+	int table_better = 0;
 
 	struct btrfs_qgroup_comparer_set *comparer_set;
 	struct btrfs_qgroup_filter_set *filter_set;
@@ -243,16 +246,18 @@ static int cmd_qgroup_show(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		c = getopt_long(argc, argv, "pcleFf",
+		c = getopt_long(argc, argv, "pcleFft",
 				long_options, NULL);
 		if (c < 0)
 			break;
 		switch (c) {
 		case 'p':
+			table_better |= 0x1;
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_PARENT);
 			break;
 		case 'c':
+			table_better |= 0x2;
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_CHILD);
 			break;
@@ -264,6 +269,9 @@ static int cmd_qgroup_show(int argc, char **argv)
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_MAX_EXCL);
 			break;
+		case 't':
+			is_table_result = 1;
+			break;
 		case 'F':
 			filter_flag |= 0x1;
 			break;
@@ -301,7 +309,13 @@ static int cmd_qgroup_show(int argc, char **argv)
 					BTRFS_QGROUP_FILTER_PARENT,
 					qgroupid);
 	}
-	ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
+	if (is_table_result && table_better == 3) {
+		fprintf(stderr,
+			"ERROR: '-p' and '-c' can't used at the same time\n");
+		exit(1);
+	}
+	ret = btrfs_show_qgroups(fd, filter_set, comparer_set,
+				 is_table_result);
 	e = errno;
 	close_file_or_dir(fd, dirstream);
 	if (ret < 0)
diff --git a/qgroup.c b/qgroup.c
index 84f5fc1..eafb1bf 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -80,40 +80,48 @@ struct {
 	char *name;
 	char *column_name;
 	int need_print;
+	int max_len;
 } btrfs_qgroup_columns[] = {
 	{
 		.name		= "qgroupid",
 		.column_name	= "Qgroupid",
 		.need_print	= 1,
+		.max_len	= 8,
 	},
 	{
 		.name		= "rfer",
 		.column_name	= "Rfer",
 		.need_print	= 1,
+		.max_len	= 4,
 	},
 	{
 		.name		= "excl",
 		.column_name	= "Excl",
 		.need_print	= 1,
+		.max_len	= 4,
 	},
 	{	.name		= "max_rfer",
 		.column_name	= "Max_rfer",
 		.need_print	= 0,
+		.max_len	= 8,
 	},
 	{
 		.name		= "max_excl",
 		.column_name	= "Max_excl",
 		.need_print	= 0,
+		.max_len	= 8,
 	},
 	{
 		.name		= "parent",
 		.column_name	= "Parent",
 		.need_print	= 0,
+		.max_len	= 7,
 	},
 	{
 		.name		= "child",
 		.column_name	= "Child",
 		.need_print	= 0,
+		.max_len	= 5,
 	},
 	{
 		.name		= NULL,
@@ -167,8 +175,27 @@ static void print_child_column(struct btrfs_qgroup *qgroup)
 		printf("---");
 }
 
+static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
+					  u64 value)
+{
+	char tmp[100];
+	int len;
+
+	if (column == BTRFS_QGROUP_QGROUPID) {
+		sprintf(tmp, "%llu/%llu", value >> 48,
+			((1ll << 48) - 1) & value);
+	} else
+		sprintf(tmp, "%llu", value);
+	len = btrfs_qgroup_columns[column].max_len - strlen(tmp);
+	memset(tmp, 0, sizeof(tmp));
+	while (len--)
+		strcat(tmp, " ");
+	printf("%s", tmp);
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
-				enum btrfs_qgroup_column_enum column)
+				enum btrfs_qgroup_column_enum column,
+				int is_table_result)
 {
 	BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
 
@@ -177,21 +204,36 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	case BTRFS_QGROUP_QGROUPID:
 		printf("%llu/%llu", qgroup->qgroupid >> 48,
 		       ((1ll << 48) - 1) & qgroup->qgroupid);
+		if (is_table_result)
+			print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID,
+						qgroup->qgroupid);
 		break;
 	case BTRFS_QGROUP_RFER:
 		printf("%lld", qgroup->rfer);
+		if (is_table_result)
+			print_qgroup_column_add_blank(BTRFS_QGROUP_RFER,
+						qgroup->rfer);
 		break;
 	case BTRFS_QGROUP_EXCL:
 		printf("%lld", qgroup->excl);
+		if (is_table_result)
+			print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL,
+						qgroup->excl);
 		break;
 	case BTRFS_QGROUP_PARENT:
 		print_parent_column(qgroup);
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
 		printf("%llu", qgroup->max_rfer);
+		if (is_table_result)
+			print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER,
+						qgroup->max_rfer);
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
 		printf("%llu", qgroup->max_excl);
+		if (is_table_result)
+			print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL,
+						qgroup->max_excl);
 		break;
 	case BTRFS_QGROUP_CHILD:
 		print_child_column(qgroup);
@@ -208,7 +250,7 @@ static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
 	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, 0);
 
 		if (i != BTRFS_QGROUP_ALL - 1)
 			printf(" ");
@@ -216,6 +258,58 @@ static void print_single_qgroup_default(struct btrfs_qgroup *qgroup)
 	printf("\n");
 }
 
+static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+		if (!btrfs_qgroup_columns[i].need_print)
+			continue;
+		print_qgroup_column(qgroup, i, 1);
+
+		if (i != BTRFS_QGROUP_CHILD)
+			printf(" ");
+	}
+	printf("\n");
+}
+
+static void print_table_head()
+{
+	int i;
+	int len;
+	char barrier[20];
+
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+		if (!btrfs_qgroup_columns[i].need_print)
+			continue;
+		printf("%s", btrfs_qgroup_columns[i].name);
+		len = btrfs_qgroup_columns[i].max_len -
+		      strlen(btrfs_qgroup_columns[i].name);
+		memset(barrier, 0, sizeof(barrier));
+		while (len--)
+			strcat(barrier, " ");
+		printf("%s ", barrier);
+	}
+	printf("\n");
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+		if (!btrfs_qgroup_columns[i].need_print)
+			continue;
+
+		len = strlen(btrfs_qgroup_columns[i].name);
+		memset(barrier, 0, sizeof(barrier));
+		while (len--)
+			strcat(barrier, "-");
+		printf("%s", barrier);
+		len = btrfs_qgroup_columns[i].max_len -
+		      strlen(btrfs_qgroup_columns[i].name);
+		memset(barrier, 0, sizeof(barrier));
+		while (len--)
+			strcat(barrier, " ");
+		printf("%s ", barrier);
+	}
+	printf("\n");
+}
+
 static void qgroup_lookup_init(struct qgroup_lookup *tree)
 {
 	tree->root.rb_node = NULL;
@@ -819,6 +913,67 @@ static int sort_tree_insert(struct qgroup_lookup *sort_tree,
 	return 0;
 }
 
+static void __update_columns_max_len(struct btrfs_qgroup *bq,
+				     enum btrfs_qgroup_column_enum column)
+{
+	BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
+	char tmp[100];
+	int len;
+
+	switch (column) {
+
+	case BTRFS_QGROUP_QGROUPID:
+		sprintf(tmp, "%llu/%llu", (bq->qgroupid >> 48),
+			bq->qgroupid & ((1ll << 48) - 1));
+		len = strlen(tmp);
+		if (btrfs_qgroup_columns[column].max_len < len)
+			btrfs_qgroup_columns[column].max_len = len;
+		break;
+	case BTRFS_QGROUP_RFER:
+		sprintf(tmp, "%llu", bq->rfer);
+		len = strlen(tmp);
+		if (btrfs_qgroup_columns[column].max_len < len)
+			btrfs_qgroup_columns[column].max_len = len;
+		break;
+	case BTRFS_QGROUP_EXCL:
+		sprintf(tmp, "%llu", bq->excl);
+		len = strlen(tmp);
+		if (btrfs_qgroup_columns[column].max_len < len)
+			btrfs_qgroup_columns[column].max_len = len;
+		break;
+	case BTRFS_QGROUP_MAX_RFER:
+		sprintf(tmp, "%llu", bq->max_rfer);
+		len = strlen(tmp);
+		if (btrfs_qgroup_columns[column].max_len < len)
+			btrfs_qgroup_columns[column].max_len = len;
+		break;
+	case BTRFS_QGROUP_MAX_EXCL:
+		sprintf(tmp, "%llu", bq->max_excl);
+		len = strlen(tmp);
+		if (btrfs_qgroup_columns[column].max_len < len)
+			btrfs_qgroup_columns[column].max_len = len;
+		break;
+	case BTRFS_QGROUP_PARENT:
+		break;
+	case BTRFS_QGROUP_CHILD:
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void update_columns_max_len(struct btrfs_qgroup *bq)
+{
+	int i;
+
+	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
+		if (!btrfs_qgroup_columns[i].need_print)
+			continue;
+		__update_columns_max_len(bq, i);
+	}
+}
+
 static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
 				 struct qgroup_lookup *sort_tree,
 				 struct btrfs_qgroup_filter_set *filter_set,
@@ -836,9 +991,11 @@ static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups,
 		entry = rb_entry(n, struct btrfs_qgroup, rb_node);
 
 		ret = filter_qgroup(entry, filter_set);
-		if (ret)
+		if (ret) {
 			sort_tree_insert(sort_tree, entry, comp_set);
 
+			update_columns_max_len(entry);
+		}
 		n = rb_prev(n);
 	}
 }
@@ -966,23 +1123,31 @@ done:
 	return ret;
 }
 
-static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
+static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup,
+			      int is_table_result)
 {
 
 	struct rb_node *n;
 	struct btrfs_qgroup *entry;
 
+	if (is_table_result)
+		print_table_head();
+
 	n = rb_first(&qgroup_lookup->root);
 	while (n) {
 		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
-		print_single_qgroup_default(entry);
+		if (!is_table_result)
+			print_single_qgroup_default(entry);
+		else
+			print_single_qgroup_table(entry);
 		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,
+		       int is_table_result)
 {
 
 	struct qgroup_lookup qgroup_lookup;
@@ -994,7 +1159,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, is_table_result);
 
 	__free_all_qgroups(&qgroup_lookup);
 	btrfs_qgroup_free_filter_set(filter_set);
diff --git a/qgroup.h b/qgroup.h
index 653cf1c..4dd666d 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -81,7 +81,8 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg,
 				struct btrfs_qgroup_comparer_set **comps);
 u64 btrfs_get_path_rootid(int fd);
 int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
-		       struct btrfs_qgroup_comparer_set *);
+		       struct btrfs_qgroup_comparer_set *,
+		       int is_table_result);
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
 void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set);
-- 
1.8.3.1


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

* Re: [PATCH v2 0/9] enhance btrfs qgroup show command
  2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
                   ` (8 preceding siblings ...)
  2013-09-23  6:17 ` [PATCH v2 9/9] Btrfs-progs: enhance btrfs qgroup to print the result as a table Wang Shilong
@ 2013-10-01 11:19 ` David Sterba
  2013-10-01 12:25   ` Wang Shilong
  9 siblings, 1 reply; 13+ messages in thread
From: David Sterba @ 2013-10-01 11:19 UTC (permalink / raw)
  To: Wang Shilong; +Cc: linux-btrfs

On Mon, Sep 23, 2013 at 02:17:19PM +0800, Wang Shilong wrote:
> Firstly, we restructure show_qgroups, make it easy to add new features.
> And then we add '-p' '-c', '-l',and '-e' options to print the parent
> qgroup id, child qgroup id, max referenced size and max exclusive size
> of qgroup respectively, add '-F' and '-f' option to list qgroups that
> impact the given path.

Well done! I really like it.

Minor comments:

* -l sounds less intuitive, I suggest to use -r as for
  'referenced', given that there is -e for 'exclusive'.

* the size should be pretty-printed by default or in bytes if a
  commandline option is given

* in the long term, the tabular output would be much better as
  default, and the current terse output available via commandline option
  for batch processing

thanks,
david

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

* Re: [PATCH v2 0/9] enhance btrfs qgroup show command
  2013-10-01 11:19 ` [PATCH v2 0/9] enhance btrfs qgroup show command David Sterba
@ 2013-10-01 12:25   ` Wang Shilong
  2013-10-01 14:00     ` David Sterba
  0 siblings, 1 reply; 13+ messages in thread
From: Wang Shilong @ 2013-10-01 12:25 UTC (permalink / raw)
  To: dsterba; +Cc: Wang Shilong, linux-btrfs

Hi David,

> On Mon, Sep 23, 2013 at 02:17:19PM +0800, Wang Shilong wrote:
>> Firstly, we restructure show_qgroups, make it easy to add new features.
>> And then we add '-p' '-c', '-l',and '-e' options to print the parent
>> qgroup id, child qgroup id, max referenced size and max exclusive size
>> of qgroup respectively, add '-F' and '-f' option to list qgroups that
>> impact the given path.
> 
> Well done! I really like it.
> 
> Minor comments:
> 
> * -l sounds less intuitive, I suggest to use -r as for
>  'referenced', given that there is -e for 'exclusive'.

Yeah, here -l means limited size. Anyway, this is a little  obscure.
Maybe -r is better, but it may let user think it is a qgroup's referenced size
but not max referenced size..


> * the size should be pretty-printed by default or in bytes if a
>  commandline option is given

Agree, maybe i can add an options for example '-h'  here.

> 
> * in the long term, the tabular output would be much better as
>  default, and the current terse output available via commandline option
>  for batch processing

The main reason that i don't use table result as default is because there
are so many columns here, and my first table result will be a head name like:

rfer excl max_refer max_excl
----  -----  -----------   -------------

In order to keep compatibility with previous 'btrfs qgroup show', i add '-t'.

Thanks,
Wang
> 
> thanks,
> david
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v2 0/9] enhance btrfs qgroup show command
  2013-10-01 12:25   ` Wang Shilong
@ 2013-10-01 14:00     ` David Sterba
  0 siblings, 0 replies; 13+ messages in thread
From: David Sterba @ 2013-10-01 14:00 UTC (permalink / raw)
  To: Wang Shilong; +Cc: dsterba, Wang Shilong, linux-btrfs

On Tue, Oct 01, 2013 at 08:25:38PM +0800, Wang Shilong wrote:
> > * -l sounds less intuitive, I suggest to use -r as for
> >  'referenced', given that there is -e for 'exclusive'.
> 
> Yeah, here -l means limited size. Anyway, this is a little  obscure.
> Maybe -r is better, but it may let user think it is a qgroup's referenced size
> but not max referenced size..

The referenced and exclusive sizes are always printed, I think that's ok
to assign -r to the referenced limit. If we want to reserve -r for
something else, next option is to use -R and -E for the limits.

During the time I was testing it the 2 most frequent uses were '-t' or
'-tcle'.

> > * the size should be pretty-printed by default or in bytes if a
> >  commandline option is given
> 
> Agree, maybe i can add an options for example '-h'  here.

-h prints help. But we haven't solved selecting units in other commands
as well, so this should be possibly done consistently and in one go.

> > * in the long term, the tabular output would be much better as
> >  default, and the current terse output available via commandline option
> >  for batch processing
> 
> The main reason that i don't use table result as default is because there
> are so many columns here, and my first table result will be a head name like:
> 
> rfer excl max_refer max_excl
> ----  -----  -----------   -------------
> 
> In order to keep compatibility with previous 'btrfs qgroup show', i add '-t'.

That's fine for now.

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

end of thread, other threads:[~2013-10-01 14:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-23  6:17 [PATCH v2 0/9] enhance btrfs qgroup show command Wang Shilong
2013-09-23  6:17 ` [PATCH v2 1/9] Btrfs-progs: restructure show_qgroups Wang Shilong
2013-09-23  6:17 ` [PATCH v2 2/9] Btrfs-progs: introduces '-p' option to print the ID of the parent qgroups Wang Shilong
2013-09-23  6:17 ` [PATCH v2 3/9] Btrfs-progs: introduces '-c' option to print the ID of the child qgroups Wang Shilong
2013-09-23  6:17 ` [PATCH v2 4/9] Btrfs-progs: introduce '-l' option to print max referenced size of qgroups Wang Shilong
2013-09-23  6:17 ` [PATCH v2 5/9] Btrfs-progs: introduce '-e' option to print max exclusive " Wang Shilong
2013-09-23  6:17 ` [PATCH v2 6/9] Btrfs-progs: list all qgroups impact given path(include ancestral qgroups) Wang Shilong
2013-09-23  6:17 ` [PATCH v2 7/9] Btrfs-progs: list all qgroups impact given path(exclude " Wang Shilong
2013-09-23  6:17 ` [PATCH v2 8/9] Btrfs-progs: enhance btrfs qgroup show to sort qgroups Wang Shilong
2013-09-23  6:17 ` [PATCH v2 9/9] Btrfs-progs: enhance btrfs qgroup to print the result as a table Wang Shilong
2013-10-01 11:19 ` [PATCH v2 0/9] enhance btrfs qgroup show command David Sterba
2013-10-01 12:25   ` Wang Shilong
2013-10-01 14:00     ` David Sterba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).