diff mbox

[v2,RESEND] btrfs-progs: make btrfs qgroups show human readable sizes

Message ID 1421128419-17169-1-git-send-email-fancn.fnst@cn.fujitsu.com (mailing list archive)
State Superseded
Headers show

Commit Message

Fan Chengniang Jan. 13, 2015, 5:53 a.m. UTC
make btrfs qgroups show human readable sizes
using --human-readable option, example:

qgroupid rfer         excl         max_rfer     max_excl     parent  child
-------- ----         ----         --------     --------     ------  -----
0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265

Signed-off-by: Fan Chengniang <fancn.fnst@cn.fujitsu.com>
---
v2:
- change -h option to --human-readable
- merge need_print and human_readable into format
- add print_group_size function

 Documentation/btrfs-qgroup.txt |  2 ++
 cmds-qgroup.c                  | 10 +++++-
 qgroup.c                       | 69 ++++++++++++++++++++++++++++--------------
 qgroup.h                       |  1 +
 4 files changed, 58 insertions(+), 24 deletions(-)

Comments

David Sterba Jan. 14, 2015, 3:46 p.m. UTC | #1
On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
> make btrfs qgroups show human readable sizes
> using --human-readable option, example:

That's too long to type and the idea was to add all the long options
that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
--si and --iec. We can possibly make the human readable the default
because that's what I'd expect to see to have a quick overview and can
use the other options otherwise.

The geopt parser accepts short options if they're unique, so --kb or
even --k works as a very convenient shorcut for frequent commandline
use.

> qgroupid rfer         excl         max_rfer     max_excl     parent  child
> -------- ----         ----         --------     --------     ------  -----
> 0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
> 0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
> 0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
> 1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265

The values should be also aligned to the right.
--
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
Roman Mamedov Jan. 14, 2015, 6:20 p.m. UTC | #2
On Wed, 14 Jan 2015 16:46:33 +0100
David Sterba <dsterba@suse.cz> wrote:

> On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
> > make btrfs qgroups show human readable sizes
> > using --human-readable option, example:
> 
> That's too long to type and the idea was to add all the long options
> that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
> --si and --iec. We can possibly make the human readable the default
> because that's what I'd expect to see to have a quick overview and can
> use the other options otherwise.
> 
> The geopt parser accepts short options if they're unique, so --kb or
> even --k works as a very convenient shorcut for frequent commandline
> use.

FWIW both of the GNU coreutils "df" and "ls" use the "-h, --human-readable"
combination of options. Also the human-readable sizes are not the default format with those.
Why not follow the rule of the least surprise and just adopt the same behavior?
Qu Wenruo Jan. 15, 2015, 1:01 a.m. UTC | #3
-------- Original Message --------
Subject: Re: [PATCH v2 RESEND] btrfs-progs: make btrfs qgroups show 
human readable sizes
From: David Sterba <dsterba@suse.cz>
To: Fan Chengniang <fancn.fnst@cn.fujitsu.com>
Date: 2015?01?14? 23:46
> On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
>> make btrfs qgroups show human readable sizes
>> using --human-readable option, example:
> That's too long to type
It's completely OK to make the option shorter and make it consistent 
with other parts,
(BTW, fi df uses -h, no long option, why not keey consistent with it?)
but IMHO, isn't the bash-completion script a better solution for all the 
btrfs subcommands and options length?

Complicated commands like git have a quite good bash-completion script, 
and with it
option length is never a problem (except some case in git config, where 
some options can't be completed).

Thanks,
Qu
> and the idea was to add all the long options
> that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
> --si and --iec. We can possibly make the human readable the default
> because that's what I'd expect to see to have a quick overview and can
> use the other options otherwise.
>
> The geopt parser accepts short options if they're unique, so --kb or
> even --k works as a very convenient shorcut for frequent commandline
> use.
>
>> qgroupid rfer         excl         max_rfer     max_excl     parent  child
>> -------- ----         ----         --------     --------     ------  -----
>> 0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
>> 0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
>> 0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
>> 1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265
> The values should be also aligned to the right.
> --
> 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

--
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
Fan Chengniang Jan. 15, 2015, 1:17 a.m. UTC | #4
? 2015?01?14? 23:46, David Sterba ??:
> On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
>> make btrfs qgroups show human readable sizes
>> using --human-readable option, example:
> That's too long to type and the idea was to add all the long options
> that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
> --si and --iec. We can possibly make the human readable the default
> because that's what I'd expect to see to have a quick overview and can
> use the other options otherwise.
>
> The geopt parser accepts short options if they're unique, so --kb or
> even --k works as a very convenient shorcut for frequent commandline
> use.
I have sent a mail for your advise of adding options. In that mail, I 
asked whether I should use --human-readable and add --kbytes --mbytes ...
But you have not reply to me.
So, your advise is add --kbytes --mbytes ... and make human-readable 
default behaviour?
>> qgroupid rfer         excl         max_rfer     max_excl     parent  child
>> -------- ----         ----         --------     --------     ------  -----
>> 0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
>> 0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
>> 0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
>> 1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265
> The values should be also aligned to the right.
It is aligned to left before my patch. I just keep it.
--
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
David Sterba Jan. 15, 2015, 12:02 p.m. UTC | #5
On Wed, Jan 14, 2015 at 11:20:29PM +0500, Roman Mamedov wrote:
> On Wed, 14 Jan 2015 16:46:33 +0100
> David Sterba <dsterba@suse.cz> wrote:
> 
> > On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
> > > make btrfs qgroups show human readable sizes
> > > using --human-readable option, example:
> > 
> > That's too long to type and the idea was to add all the long options
> > that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
> > --si and --iec. We can possibly make the human readable the default
> > because that's what I'd expect to see to have a quick overview and can
> > use the other options otherwise.
> > 
> > The geopt parser accepts short options if they're unique, so --kb or
> > even --k works as a very convenient shorcut for frequent commandline
> > use.
> 
> FWIW both of the GNU coreutils "df" and "ls" use the "-h, --human-readable"
> combination of options. Also the human-readable sizes are not the default format with those.
> Why not follow the rule of the least surprise and just adopt the same behavior?

I was not aware of the existing long option, makes sense to add them as
an alias of -h/-H.

I'm not sure what to do about the default output. 'ls' prints raw bytes,
'df' prints a raw number that's in Kilobytes, without a suffix. To
follow principle of least surprise in the context of btrfs-progs is to
print the human readable by default, like 'fi df/show' has been doing.

My rationale behind the default is to give a quick overview to user, I
type 'df -h' all the time and haven't used a plain 'df' since long. The
ability to quickly recognize and comprehend numbers goes down after 5-6
digits, while the numbers + largest suffix are within that limit.
--
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
David Sterba Jan. 15, 2015, 12:05 p.m. UTC | #6
On Thu, Jan 15, 2015 at 09:01:37AM +0800, Qu Wenruo wrote:
> > On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
> >> make btrfs qgroups show human readable sizes
> >> using --human-readable option, example:
> > That's too long to type
> It's completely OK to make the option shorter and make it consistent 
> with other parts,
> (BTW, fi df uses -h, no long option, why not keey consistent with it?)

I'm for adding the --human-readable variants where applicable.

> but IMHO, isn't the bash-completion script a better solution for all the 
> btrfs subcommands and options length?
> 
> Complicated commands like git have a quite good bash-completion script, 
> and with it
> option length is never a problem (except some case in git config, where 
> some options can't be completed).

A shell completion would be great of course, it's in the project ideas.
There's a starting point http://www.spinics.net/lists/linux-btrfs/msg15899.html .
--
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
David Sterba Jan. 15, 2015, 12:30 p.m. UTC | #7
On Thu, Jan 15, 2015 at 09:17:01AM +0800, Fan Chengniang/??? wrote:
> 
> ? 2015?01?14? 23:46, David Sterba ??:
> > On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
> >> make btrfs qgroups show human readable sizes
> >> using --human-readable option, example:
> > That's too long to type and the idea was to add all the long options
> > that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
> > --si and --iec. We can possibly make the human readable the default
> > because that's what I'd expect to see to have a quick overview and can
> > use the other options otherwise.
> >
> > The geopt parser accepts short options if they're unique, so --kb or
> > even --k works as a very convenient shorcut for frequent commandline
> > use.
> I have sent a mail for your advise of adding options. In that mail, I 
> asked whether I should use --human-readable and add --kbytes --mbytes ...
> But you have not reply to me.

So you've sent a v2 where we can see if our ideas match or not and
continue from there. Timely replies are not always feasible, I get a lot
of mails. Patch iterations are normal, nothing new here.

> So, your advise is add --kbytes --mbytes ... and make human-readable 
> default behaviour?
> >> qgroupid rfer         excl         max_rfer     max_excl     parent  child
> >> -------- ----         ----         --------     --------     ------  -----
> >> 0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
> >> 0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
> >> 0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
> >> 1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265
> > The values should be also aligned to the right.
> It is aligned to left before my patch. I just keep it.

Ok, take it as a hint for another patch.
--
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
??? Jan. 15, 2015, 1:50 p.m. UTC | #8
? 2015?01?15? 20:30, David Sterba ??:
> On Thu, Jan 15, 2015 at 09:17:01AM +0800, Fan Chengniang/??? wrote:
>> ? 2015?01?14? 23:46, David Sterba ??:
>>> On Tue, Jan 13, 2015 at 01:53:39PM +0800, Fan Chengniang wrote:
>>>> make btrfs qgroups show human readable sizes
>>>> using --human-readable option, example:
>>> That's too long to type and the idea was to add all the long options
>>> that force the specific unit base, ie. --kbytes/--mbytes/..., --raw,
>>> --si and --iec. We can possibly make the human readable the default
>>> because that's what I'd expect to see to have a quick overview and can
>>> use the other options otherwise.
>>>
>>> The geopt parser accepts short options if they're unique, so --kb or
>>> even --k works as a very convenient shorcut for frequent commandline
>>> use.
>> I have sent a mail for your advise of adding options. In that mail, I
>> asked whether I should use --human-readable and add --kbytes --mbytes ...
>> But you have not reply to me.
> So you've sent a v2 where we can see if our ideas match or not and
> continue from there. Timely replies are not always feasible, I get a lot
> of mails. Patch iterations are normal, nothing new here.
Sorry to you because of my words. I didn't consider you have a lot of 
mails. I will take your advice and improve my patch.
This is my personal mail address.
>> So, your advise is add --kbytes --mbytes ... and make human-readable
>> default behaviour?
>>>> qgroupid rfer         excl         max_rfer     max_excl     parent  child
>>>> -------- ----         ----         --------     --------     ------  -----
>>>> 0/5      299.58MiB    299.58MiB    400.00MiB    0.00B        1/1     ---
>>>> 0/265    299.58MiB    16.00KiB     0.00B        320.00MiB    1/1     ---
>>>> 0/266    299.58MiB    16.00KiB     350.00MiB    0.00B        ---     ---
>>>> 1/1      599.16MiB    299.59MiB    800.00MiB    0.00B        ---     0/5,0/265
>>> The values should be also aligned to the right.
>> It is aligned to left before my patch. I just keep it.
> Ok, take it as a hint for another patch.
I have combined them to one patch. Maybe I should seperate them.
> --
> 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

--
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
Duncan Jan. 15, 2015, 8:41 p.m. UTC | #9
David Sterba posted on Thu, 15 Jan 2015 13:05:46 +0100 as excerpted:

> A shell completion would be great of course, it's in the project ideas.
> There's a starting point
> http://www.spinics.net/lists/linux-btrfs/msg15899.html .

FWIW, in case anyone is interested...

What I did here is a bit different; shell completion would be better, but 
while I know bash, I don't know bash/shell completion so I couldn't write 
that without learning it.

What I did is a btrfs wrapper script (which I simply called 'b', a 
previously here-unused single letter command) that based on the first 
parameter or two and the number of parameters, decides if what's there 
matches a valid btrfs subcommand and whether it looks complete or not, 
and if it's valid but incomplete, echoes the appropriate btrfs <sub> help 
command and prompts for more input.

So just 'b' gives me:

------------------------------------------------------------
b: btrfs helper (common commands only)
------------------------------------------------------------
btrfs cmd (Just Enter for help):
b(alance) c(heck) d(ev) f(ilesystem) i(nspect) p(roperty)
qg(roup) qu(ota) rec(eive) rep(lace) resc(ue) rest(ore)
sc(rub) se(nd) su(bvolume) v(ersion):

There it waits for further input.

If I then add an 'f', or if I had typed 'b f' (or 'b fi' or
'b filesystem', the script checks status of btrfs <cmd> --help to see if 
it's valid or not), I get this:

f
------------------------------------------------------------
btrfs filesystem action (Just Enter for help):
de(frag) df l(abel) r(esize) sh(ow) sy(nc) u(sage):

Further input.

If I then add 'df' (or if I had typed 'b fi df'), I get:

df
------------------------------------------------------------
usage: btrfs filesystem df [options] <path>

    Show space usage information for a mount point

    -b|--raw           raw numbers in bytes
    -h                 human friendly numbers, base 1024 (default)
    -H                 human friendly numbers, base 1000
    --iec              use 1024 as a base (KiB, MiB, GiB, TiB)
    --si               use 1000 as a base (kB, MB, GB, TB)
    -k|--kbytes        show sizes in KiB, or kB with --si
    -m|--mbytes        show sizes in MiB, or MB with --si
    -g|--gbytes        show sizes in GiB, or GB with --si
    -t|--tbytes        show sizes in TiB, or TB with --si

------------------------------------------------------------
btrfs filesystem df usage is printed above.
Please enter additional parameters here:

Further input.

At this point it doesn't check further input, instead simply echoing back 
what will be the final command and prompting whether to run it or not.  
If I simply type '/'...

/
------------------------------------------------------------
btrfs filesystem df /
Final check: OK to run above command (y/N)?


Note the default to N...

If at that point I simply enter (or if I hit anything else besides y/Y), 
of course it doesn't run the command, it simply exits.  However, the 
built command was printed above, making it simple enough to select/paste 
(assuming gpm or a terminal window in X, thus mouse selection).

If I hit 'y', it executes the command.

Meanwhile, if there's more than two parameters and the first two 
validate, the script assumes the user knows what they are doing and 
simply executes it as-is.

b fi df /
------------------------------------------------------------
b: btrfs helper (common commands only)
------------------------------------------------------------
Data, RAID1: total=3.00GiB, used=1.74GiB
System, RAID1: total=32.00MiB, used=16.00KiB
Metadata, RAID1: total=768.00MiB, used=299.89MiB
GlobalReserve, single: total=48.00MiB, used=0.00B

b fi df invalid
------------------------------------------------------------
b: btrfs helper (common commands only)
------------------------------------------------------------
ERROR: can't access 'invalid'

b fxxx df /

This one's interesting.  The script checks the status of
btrfs fxxx --help and determines that btrfs doesn't consider the fxxx 
valid, so it simply prints the full btrfs --help output, running it thru 
$PAGER (if unset, less if it's executable, else no pager) due to length.


Anyone interested in a script such as this?  Absent a bash completion 
script, I found it /tremendously/ helpful with btrfs command basics, and 
because it prompts with the final command before execution, it helps in 
learning the commands as well.  I still use it for commands I don't use 
frequently enough to have memorized.  While it's a bit of a hack, thus my 
not posting it previously, if anyone else would find such a script 
useful, I could post it.

I don't have hosting for it but I suppose it could go on the wiki if 
enough other folks find it useful.  It's 125 lines including comments ATM.
diff mbox

Patch

diff --git a/Documentation/btrfs-qgroup.txt b/Documentation/btrfs-qgroup.txt
index 3e13373..d8ed028 100644
--- a/Documentation/btrfs-qgroup.txt
+++ b/Documentation/btrfs-qgroup.txt
@@ -73,6 +73,8 @@  print max exclusive size of qgroup.
 list all qgroups which impact the given path(include ancestral qgroups)
 -f::::
 list all qgroups which impact the given path(exclude ancestral qgroups)
+--human-readable::::
+print sizes in human readable format (e.g., 1KiB 234MiB 2GiB).
 --sort=[\+/-]<attr>[,[+/-]<attr>]...::::
 list qgroups in order of <attr>.
 +
diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 957fbc9..ba6f19b 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -216,6 +216,8 @@  static const char * const cmd_qgroup_show_usage[] = {
 	"(include ancestral qgroups)",
 	"-f		list all qgroups which impact the given path"
 	"(exclude ancestral qgroups)",
+	"--human-readable",
+	"		print sizes in human readable format (e.g., 1KiB 234MiB 2GiB)",
 	"--sort=qgroupid,rfer,excl,max_rfer,max_excl",
 	"		list qgroups in order of qgroupid,"
 	"rfer,max_rfer or max_excl",
@@ -234,6 +236,7 @@  static int cmd_qgroup_show(int argc, char **argv)
 	int c;
 	u64 qgroupid;
 	int filter_flag = 0;
+	int option_index = 0;
 
 	struct btrfs_qgroup_comparer_set *comparer_set;
 	struct btrfs_qgroup_filter_set *filter_set;
@@ -241,16 +244,21 @@  static int cmd_qgroup_show(int argc, char **argv)
 	comparer_set = btrfs_qgroup_alloc_comparer_set();
 	struct option long_options[] = {
 		{"sort", 1, NULL, 'S'},
+		{"human-readable", 0, NULL, 0},
 		{0, 0, 0, 0}
 	};
 
 	optind = 1;
 	while (1) {
 		c = getopt_long(argc, argv, "pcreFf",
-				long_options, NULL);
+				long_options, &option_index);
 		if (c < 0)
 			break;
 		switch (c) {
+		case 0:
+			if (option_index == 1)
+				btrfs_qgroup_setup_human_readable();
+			break;
 		case 'p':
 			btrfs_qgroup_setup_print_column(
 				BTRFS_QGROUP_PARENT);
diff --git a/qgroup.c b/qgroup.c
index 1a4866c..ce87fe4 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -20,10 +20,14 @@ 
 #include <sys/ioctl.h>
 #include "ctree.h"
 #include "ioctl.h"
+#include "utils.h"
 
 #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX)
 #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX)
 
+#define BTRFS_QGROUP_FORMAT_PRINT 1
+#define BTRFS_QGROUP_FORMAT_HUMAN (1U << 1)
+
 struct qgroup_lookup {
 	struct rb_root root;
 };
@@ -79,54 +83,54 @@  struct btrfs_qgroup_list {
 static struct {
 	char *name;
 	char *column_name;
-	int need_print;
+	unsigned int format;
 	int max_len;
 } btrfs_qgroup_columns[] = {
 	{
 		.name		= "qgroupid",
 		.column_name	= "Qgroupid",
-		.need_print	= 1,
+		.format		= BTRFS_QGROUP_FORMAT_PRINT,
 		.max_len	= 8,
 	},
 	{
 		.name		= "rfer",
 		.column_name	= "Rfer",
-		.need_print	= 1,
-		.max_len	= 4,
+		.format		= BTRFS_QGROUP_FORMAT_PRINT,
+		.max_len	= 12,
 	},
 	{
 		.name		= "excl",
 		.column_name	= "Excl",
-		.need_print	= 1,
-		.max_len	= 4,
+		.format		= BTRFS_QGROUP_FORMAT_PRINT,
+		.max_len	= 12,
 	},
 	{	.name		= "max_rfer",
 		.column_name	= "Max_rfer",
-		.need_print	= 0,
-		.max_len	= 8,
+		.format		= 0,
+		.max_len	= 12,
 	},
 	{
 		.name		= "max_excl",
 		.column_name	= "Max_excl",
-		.need_print	= 0,
-		.max_len	= 8,
+		.format		= 0,
+		.max_len	= 12,
 	},
 	{
 		.name		= "parent",
 		.column_name	= "Parent",
-		.need_print	= 0,
+		.format		= 0,
 		.max_len	= 7,
 	},
 	{
 		.name		= "child",
 		.column_name	= "Child",
-		.need_print	= 0,
+		.format		= 0,
 		.max_len	= 5,
 	},
 	{
 		.name		= NULL,
 		.column_name	= NULL,
-		.need_print	= 0,
+		.format		= 0,
 	},
 };
 
@@ -140,11 +144,19 @@  void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column)
 	BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL);
 
 	if (column < BTRFS_QGROUP_ALL) {
-		btrfs_qgroup_columns[column].need_print = 1;
+		btrfs_qgroup_columns[column].format |= BTRFS_QGROUP_FORMAT_PRINT;
 		return;
 	}
 	for (i = 0; i < BTRFS_QGROUP_ALL; i++)
-		btrfs_qgroup_columns[i].need_print = 1;
+		btrfs_qgroup_columns[i].format |= BTRFS_QGROUP_FORMAT_PRINT;
+}
+
+void btrfs_qgroup_setup_human_readable(void)
+{
+	btrfs_qgroup_columns[BTRFS_QGROUP_RFER].format |= BTRFS_QGROUP_FORMAT_HUMAN;
+	btrfs_qgroup_columns[BTRFS_QGROUP_EXCL].format |= BTRFS_QGROUP_FORMAT_HUMAN;
+	btrfs_qgroup_columns[BTRFS_QGROUP_MAX_RFER].format |= BTRFS_QGROUP_FORMAT_HUMAN;
+	btrfs_qgroup_columns[BTRFS_QGROUP_MAX_EXCL].format |= BTRFS_QGROUP_FORMAT_HUMAN;
 }
 
 static int print_parent_column(struct btrfs_qgroup *qgroup)
@@ -189,6 +201,17 @@  static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
 		printf(" ");
 }
 
+static int print_qgroup_size(u64 size, unsigned int format)
+{
+	int len;
+	if (format & BTRFS_QGROUP_FORMAT_HUMAN)
+		len = printf("%s", pretty_size(size));
+	else
+		len = printf("%llu", size);
+
+	return len;
+}
+
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 				enum btrfs_qgroup_column_enum column)
 {
@@ -203,11 +226,11 @@  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("%llu", qgroup->rfer);
+		len = print_qgroup_size(qgroup->rfer, btrfs_qgroup_columns[column].format);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, len);
 		break;
 	case BTRFS_QGROUP_EXCL:
-		len = printf("%llu", qgroup->excl);
+		len = print_qgroup_size(qgroup->excl, btrfs_qgroup_columns[column].format);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, len);
 		break;
 	case BTRFS_QGROUP_PARENT:
@@ -215,11 +238,11 @@  static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 		print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
-		len = printf("%llu", qgroup->max_rfer);
+		len = print_qgroup_size(qgroup->max_rfer, btrfs_qgroup_columns[column].format);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER, len);
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
-		len = printf("%llu", qgroup->max_excl);
+		len = print_qgroup_size(qgroup->max_excl, btrfs_qgroup_columns[column].format);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL, len);
 		break;
 	case BTRFS_QGROUP_CHILD:
@@ -236,7 +259,7 @@  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)
+		if (!(btrfs_qgroup_columns[i].format & BTRFS_QGROUP_FORMAT_PRINT))
 			continue;
 		print_qgroup_column(qgroup, i);
 
@@ -252,7 +275,7 @@  static void print_table_head()
 	int len;
 
 	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
-		if (!btrfs_qgroup_columns[i].need_print)
+		if (!(btrfs_qgroup_columns[i].format & BTRFS_QGROUP_FORMAT_PRINT))
 			continue;
 		printf("%s", btrfs_qgroup_columns[i].name);
 		len = btrfs_qgroup_columns[i].max_len -
@@ -263,7 +286,7 @@  static void print_table_head()
 	}
 	printf("\n");
 	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
-		if (!btrfs_qgroup_columns[i].need_print)
+		if (!(btrfs_qgroup_columns[i].format & BTRFS_QGROUP_FORMAT_PRINT))
 			continue;
 
 		len = strlen(btrfs_qgroup_columns[i].name);
@@ -957,7 +980,7 @@  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)
+		if (!(btrfs_qgroup_columns[i].format & BTRFS_QGROUP_FORMAT_PRINT))
 			continue;
 		__update_columns_max_len(bq, i);
 	}
diff --git a/qgroup.h b/qgroup.h
index 653cf1c..cc8ae29 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -83,6 +83,7 @@  u64 btrfs_get_path_rootid(int fd);
 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);
+void btrfs_qgroup_setup_human_readable(void);
 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,