All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
@ 2014-02-13 19:18 Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 1/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
                   ` (9 more replies)
  0 siblings, 10 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:18 UTC (permalink / raw)
  To: linux-btrfs, Josef Bacik; +Cc: Hugo Mills, Kostia Khlebopros

Hi all, 

This is the 4th attempt of my patches related to show how the data
are stored in a btrfs filesystem. I rebased all the patches on the v3.13
btrfs-progs. 

These patches update the btrfs fi df command and add two new commands:
- btrfs filesystem disk-usage <path>
- btrfs device disk-usage <path>

The command "btrfs filesystem df" now shows only the disk usage/available.

$ sudo btrfs filesystem df /mnt/btrfs1/
Disk size:		 400.00GB
Disk allocated:		   8.04GB
Disk unallocated:	 391.97GB
Used:			  11.29MB
Free (Estimated):	 250.45GB	(Max: 396.99GB, min: 201.00GB)
Data to disk ratio:	     63 %

The "Free (Estimated)" tries to give an estimation of the free space
on the basis of the chunks usage. Max and min are the maximum allowable
space (if the next chunk are allocated as SINGLE) or the minimum one (
if the next chunks are allocated as DUP/RAID1/RAID10).

The other two commands show the chunks in the disks.

$ sudo btrfs filesystem disk-usage /mnt/btrfs1/
Data,Single: Size:8.00MB, Used:0.00
   /dev/vdb	    8.00MB

Data,RAID6: Size:2.00GB, Used:11.25MB
   /dev/vdb	    1.00GB
   /dev/vdc	    1.00GB
   /dev/vdd	    1.00GB
   /dev/vde	    1.00GB

Metadata,Single: Size:8.00MB, Used:0.00
   /dev/vdb	    8.00MB

Metadata,RAID5: Size:3.00GB, Used:36.00KB
   /dev/vdb	    1.00GB
   /dev/vdc	    1.00GB
   /dev/vdd	    1.00GB
   /dev/vde	    1.00GB

System,Single: Size:4.00MB, Used:0.00
   /dev/vdb	    4.00MB

System,RAID5: Size:12.00MB, Used:4.00KB
   /dev/vdb	    4.00MB
   /dev/vdc	    4.00MB
   /dev/vdd	    4.00MB
   /dev/vde	    4.00MB

Unallocated:
   /dev/vdb	   97.98GB
   /dev/vdc	   98.00GB
   /dev/vdd	   98.00GB
   /dev/vde	   98.00GB

or in tabular format

$ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/
         Data   Data    Metadata Metadata System System             
         Single RAID6   Single   RAID5    Single RAID5   Unallocated
                                                                    
/dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB     97.98GB
/dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
/dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
/dev/vde      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
         ====== ======= ======== ======== ====== ======= ===========
Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB 12.00MB    391.97GB
Used       0.00 11.25MB     0.00  36.00KB   0.00  4.00KB            

These are the most complete output, where it is possible to know which
disk a chunk uses and the usage of every chunk.

Finally the last command shows which chunks a disk hosts:

$ sudo ./btrfs device disk-usage /mnt/btrfs1/
/dev/vdb	  100.00GB
   Data,Single:              8.00MB
   Data,RAID6:               1.00GB
   Metadata,Single:          8.00MB
   Metadata,RAID5:           1.00GB
   System,Single:            4.00MB
   System,RAID5:             4.00MB
   Unallocated:             97.98GB

/dev/vdc	  100.00GB
   Data,RAID6:               1.00GB
   Metadata,RAID5:           1.00GB
   System,RAID5:             4.00MB
   Unallocated:             98.00GB

/dev/vdd	  100.00GB
   Data,RAID6:               1.00GB
   Metadata,RAID5:           1.00GB
   System,RAID5:             4.00MB
   Unallocated:             98.00GB

/dev/vde	  100.00GB
   Data,RAID6:               1.00GB
   Metadata,RAID5:           1.00GB
   System,RAID5:             4.00MB
   Unallocated:             98.00GB

More or less are the same information above, only grouped by disk.
Unfortunately I don't have any information about the chunk usage per disk basis.

Comments are welcome.
The code is pullable from
        https://github.com/kreijack/btrfs-progs.git
branch
        dfdu

Finally I have to point out that the command btrfs fi df previous didn't require 
the root capability, now with my patches it is required, because I need 
to know some info about the chunks so I need to use the 
"BTRFS_IOC_TREE_SEARCH".

I think that there are the following possibilities:
1) accept this regresssion
2) remove the command "btrfs fi df" and leave only "btrfs fi disk-usage" and
   "btrfs dev disk-usage"
3) adding a new ioctl which could be used without root capability. Of course
   this ioctl would return only a subset of the BTRFS_IOC_TREE_SEARCH info

I think that the 3) would be the "long term" solution. I am not happy about
the 1), so as "short term solution" I think that we should go with the 2).
What do you think ?

Below the description of the patches.

--


BR
G.Baroncelli

Changelog:
v1 2013/02/18 First issue
v2 2013/02/23 Fix uncorrct "not enough memory" handling in patch #1.
              Thanks to Zac to highlight it.
v3 2013/03/10 - Rebased on the latest mason git repository
              - Small fix in the comment
              - Increase the buffer in the function df_pretty_sizes() to
		avoid buffer pverwflow (thanks to Zach to highlight it)
	      - adding the sla_pretty_sizes() function to remove the call
	        of string_list_add() from df_pretty_sizes.
v4 2014/02/13 - Rebased to v3.12
              - Replace MB/GB/TB with MiB/GiB/TiB
              - correct some small bug related to mixing same raid level
                with different disk number
              -removing the string_list_add() function




-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 1/8] Enhance the command btrfs filesystem df.
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
@ 2014-02-13 19:19 ` Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 2/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:19 UTC (permalink / raw)
  To: linux-btrfs


Enhance the command "btrfs filesystem df" to show space usage information
for a mount point(s). It shows also an estimation of the space available,
on the basis of the current one used.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 Makefile             |   3 +-
 cmds-fi-disk_usage.c | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |  25 +++
 cmds-filesystem.c    |  91 +--------
 ctree.h              |  17 +-
 utils.c              |  13 ++
 utils.h              |   2 +
 7 files changed, 575 insertions(+), 92 deletions(-)
 create mode 100644 cmds-fi-disk_usage.c
 create mode 100644 cmds-fi-disk_usage.h

diff --git a/Makefile b/Makefile
index 0874a41..db470b6 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
 cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
 	       cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \
 	       cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \
-	       cmds-restore.o cmds-rescue.o chunk-recover.o super-recover.o
+	       cmds-restore.o cmds-rescue.o chunk-recover.o super-recover.o \
+	       cmds-fi-disk_usage.o
 libbtrfs_objects = send-stream.o send-utils.o rbtree.o btrfs-list.o crc32c.o \
 		   uuid-tree.o
 libbtrfs_headers = send-stream.h send-utils.h send.h rbtree.h btrfs-list.h \
diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
new file mode 100644
index 0000000..4012c78
--- /dev/null
+++ b/cmds-fi-disk_usage.c
@@ -0,0 +1,516 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "utils.h"
+#include "kerncompat.h"
+#include "ctree.h"
+
+#include "commands.h"
+
+#include "version.h"
+
+#define DF_HUMAN_UNIT		(1<<0)
+
+/*
+ * To store the size information about the chunks:
+ * the chunks info are grouped by the tuple (type, devid, num_stripes),
+ * i.e. if two chunks are of the same type (RAID1, DUP...), are on the
+ * same disk, have the same stripes then their sizes are grouped
+ */
+struct chunk_info {
+	u64	type;
+	u64	size;
+	u64	devid;
+	u64	num_stripes;
+};
+
+/*
+ * Pretty print the size
+ * PAY ATTENTION: it return a statically buffer
+ */
+static char *df_pretty_sizes(u64 size, int mode)
+{
+	static char buf[30];
+
+	if (mode & DF_HUMAN_UNIT)
+		(void)pretty_size_snprintf(size, buf, sizeof(buf));
+	else
+		sprintf(buf, "%llu", size);
+
+	return buf;
+}
+
+/*
+ * Add the chunk info to the chunk_info list
+ */
+static int add_info_to_list(struct chunk_info **info_ptr,
+			int *info_count,
+			struct btrfs_chunk *chunk)
+{
+
+	u64 type = btrfs_stack_chunk_type(chunk);
+	u64 size = btrfs_stack_chunk_length(chunk);
+	int num_stripes = btrfs_stack_chunk_num_stripes(chunk);
+	int j;
+
+	for (j = 0 ; j < num_stripes ; j++) {
+		int i;
+		struct chunk_info *p = 0;
+		struct btrfs_stripe *stripe;
+		u64    devid;
+
+		stripe = btrfs_stripe_nr(chunk, j);
+		devid = btrfs_stack_stripe_devid(stripe);
+
+		for (i = 0 ; i < *info_count ; i++)
+			if ((*info_ptr)[i].type == type &&
+			    (*info_ptr)[i].devid == devid &&
+			    (*info_ptr)[i].num_stripes == num_stripes ) {
+				p = (*info_ptr) + i;
+				break;
+			}
+
+		if (!p) {
+			int size = sizeof(struct btrfs_chunk) * (*info_count+1);
+			struct chunk_info *res = realloc(*info_ptr, size);
+
+			if (!res) {
+				fprintf(stderr, "ERROR: not enough memory\n");
+				return -1;
+			}
+
+			*info_ptr = res;
+			p = res + *info_count;
+			(*info_count)++;
+
+			p->devid = devid;
+			p->type = type;
+			p->size = 0;
+			p->num_stripes = num_stripes;
+		}
+
+		p->size += size;
+
+	}
+
+	return 0;
+
+}
+
+/*
+ *  Helper to sort the chunk type
+ */
+static int cmp_chunk_block_group(u64 f1, u64 f2)
+{
+
+	u64 mask;
+
+	if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) ==
+		(f2 & BTRFS_BLOCK_GROUP_TYPE_MASK))
+			mask = BTRFS_BLOCK_GROUP_PROFILE_MASK;
+	else if (f2 & BTRFS_BLOCK_GROUP_SYSTEM)
+			return -1;
+	else if (f1 & BTRFS_BLOCK_GROUP_SYSTEM)
+			return +1;
+	else
+			mask = BTRFS_BLOCK_GROUP_TYPE_MASK;
+
+	if ((f1 & mask) > (f2 & mask))
+		return +1;
+	else if ((f1 & mask) < (f2 & mask))
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * Helper to sort the chunk
+ */
+static int cmp_chunk_info(const void *a, const void *b)
+{
+	return cmp_chunk_block_group(
+		((struct chunk_info *)a)->type,
+		((struct chunk_info *)b)->type);
+}
+
+/*
+ * This function load all the chunk info from the 'fd' filesystem
+ */
+static int load_chunk_info(int fd,
+			  struct chunk_info **info_ptr,
+			  int *info_count)
+{
+
+	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;
+	int i, e;
+
+
+	memset(&args, 0, sizeof(args));
+
+	/*
+	 * there may be more than one ROOT_ITEM key if there are
+	 * snapshots pending deletion, we have to loop through
+	 * them.
+	 */
+
+
+	sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID;
+
+	sk->min_objectid = 0;
+	sk->max_objectid = (u64)-1;
+	sk->max_type = 0;
+	sk->min_type = (u8)-1;
+	sk->min_offset = 0;
+	sk->max_offset = (u64)-1;
+	sk->min_transid = 0;
+	sk->max_transid = (u64)-1;
+	sk->nr_items = 4096;
+
+	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 -99;
+		}
+		/* the ioctl returns the number of item it found in nr_items */
+
+		if (sk->nr_items == 0)
+			break;
+
+		off = 0;
+		for (i = 0; i < sk->nr_items; i++) {
+			struct btrfs_chunk *item;
+			sh = (struct btrfs_ioctl_search_header *)(args.buf +
+								  off);
+
+			off += sizeof(*sh);
+			item = (struct btrfs_chunk *)(args.buf + off);
+
+			if (add_info_to_list(info_ptr, info_count, item)) {
+				*info_ptr = 0;
+				free(*info_ptr);
+				return -100;
+			}
+
+			off += sh->len;
+
+			sk->min_objectid = sh->objectid;
+			sk->min_type = sh->type;
+			sk->min_offset = sh->offset+1;
+
+		}
+		if (!sk->min_offset)	/* overflow */
+			sk->min_type++;
+		else
+			continue;
+
+		if (!sk->min_type)
+			sk->min_objectid++;
+		 else
+			continue;
+
+		if (!sk->min_objectid)
+			break;
+	}
+
+	qsort(*info_ptr, *info_count, sizeof(struct chunk_info),
+		cmp_chunk_info);
+
+	return 0;
+
+}
+
+/*
+ * Helper to sort the struct btrfs_ioctl_space_info
+ */
+static int cmp_btrfs_ioctl_space_info(const void *a, const void *b)
+{
+	return cmp_chunk_block_group(
+		((struct btrfs_ioctl_space_info *)a)->flags,
+		((struct btrfs_ioctl_space_info *)b)->flags);
+}
+
+/*
+ * This function load all the information about the space usage
+ */
+static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path)
+{
+	struct btrfs_ioctl_space_args *sargs = 0, *sargs_orig = 0;
+	int e, ret, count;
+
+	sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
+	if (!sargs) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return NULL;
+	}
+
+	sargs->space_slots = 0;
+	sargs->total_spaces = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
+	e = errno;
+	if (ret) {
+		fprintf(stderr,
+			"ERROR: couldn't get space info on '%s' - %s\n",
+			path, strerror(e));
+		free(sargs);
+		return NULL;
+	}
+	if (!sargs->total_spaces) {
+		free(sargs);
+		printf("No chunks found\n");
+		return NULL;
+	}
+
+	count = sargs->total_spaces;
+
+	sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
+			(count * sizeof(struct btrfs_ioctl_space_info)));
+	if (!sargs) {
+		free(sargs_orig);
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return NULL;
+	}
+
+	sargs->space_slots = count;
+	sargs->total_spaces = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
+	e = errno;
+
+	if (ret) {
+		fprintf(stderr,
+			"ERROR: couldn't get space info on '%s' - %s\n",
+			path, strerror(e));
+		free(sargs);
+		return NULL;
+	}
+
+	qsort(&(sargs->spaces), count, sizeof(struct btrfs_ioctl_space_info),
+		cmp_btrfs_ioctl_space_info);
+
+	return sargs;
+}
+
+/*
+ * This function computes the space occuped by a *single* RAID5/RAID6 chunk.
+ * The computation is performed on the basis of the number of stripes
+ * which compose the chunk, which could be different from the number of disks
+ * if a disk is added later.
+ */
+static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used)
+{
+	struct chunk_info *info_ptr=0, *p;
+	int info_count=0;
+	int ret;
+
+	*raid5_used = *raid6_used =0;
+
+	ret = load_chunk_info(fd, &info_ptr, &info_count);
+	if( ret < 0)
+		return ret;
+
+	for ( p = info_ptr; info_count ; info_count--, p++ ) {
+		if (p->type & BTRFS_BLOCK_GROUP_RAID5)
+			(*raid5_used) += p->size / (p->num_stripes -1);
+		if (p->type & BTRFS_BLOCK_GROUP_RAID6)
+			(*raid6_used) += p->size / (p->num_stripes -2);
+	}
+
+	return 0;
+
+}
+
+static int _cmd_disk_free(int fd, char *path, int mode)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int i;
+	int ret = 0;
+	int e, width;
+	u64 total_disk;		/* filesystem size == sum of
+				   disks sizes */
+	u64 total_chunks;	/* sum of chunks sizes on disk(s) */
+	u64 total_used;		/* logical space used */
+	u64 total_free;		/* logical space un-used */
+	double K;
+	u64 raid5_used, raid6_used;
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	total_disk = disk_size(path);
+	e = errno;
+	if (total_disk == 0) {
+		fprintf(stderr,
+			"ERROR: couldn't get space info on '%s' - %s\n",
+			path, strerror(e));
+
+		ret = 19;
+		goto exit;
+	}
+	if (get_raid56_used(fd, &raid5_used, &raid6_used) < 0) {
+		fprintf(stderr,
+			"ERROR: couldn't get space info on '%s'\n",
+			path );
+		ret = 20;
+		goto exit;
+	}
+
+	total_chunks = total_used = total_free = 0;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		float ratio = 1;
+		u64 allocated;
+		u64 flags = sargs->spaces[i].flags;
+
+		/*
+		 * The raid5/raid6 ratio depends by the stripes number
+		 * used by every chunk. It is computed separately
+		 */
+		if (flags & BTRFS_BLOCK_GROUP_RAID0)
+			ratio = 1;
+		else if (flags & BTRFS_BLOCK_GROUP_RAID1)
+			ratio = 2;
+		else if (flags & BTRFS_BLOCK_GROUP_RAID5)
+			ratio = 0;
+		else if (flags & BTRFS_BLOCK_GROUP_RAID6)
+			ratio = 0;
+		else if (flags & BTRFS_BLOCK_GROUP_DUP)
+			ratio = 2;
+		else if (flags & BTRFS_BLOCK_GROUP_RAID10)
+			ratio = 2;
+		else
+			ratio = 1;
+
+		allocated = sargs->spaces[i].total_bytes * ratio;
+
+		total_chunks += allocated;
+		total_used += sargs->spaces[i].used_bytes;
+		total_free += (sargs->spaces[i].total_bytes -
+					sargs->spaces[i].used_bytes);
+
+	}
+
+	/* add the raid5/6 allocated space */
+	total_chunks += raid5_used + raid6_used;
+
+	K = ((double)total_used + (double)total_free) /	(double)total_chunks;
+
+	if (mode & DF_HUMAN_UNIT)
+		width = 10;
+	else
+		width = 18;
+
+	printf("Disk size:\t\t%*s\n", width,
+		df_pretty_sizes(total_disk, mode));
+	printf("Disk allocated:\t\t%*s\n", width,
+		df_pretty_sizes(total_chunks, mode));
+	printf("Disk unallocated:\t%*s\n", width,
+		df_pretty_sizes(total_disk-total_chunks, mode));
+	printf("Used:\t\t\t%*s\n", width,
+		df_pretty_sizes(total_used, mode));
+	printf("Free (Estimated):\t%*s\t(",
+		width,
+		df_pretty_sizes((u64)(K*total_disk-total_used), mode));
+	printf("Max: %s, ",
+		df_pretty_sizes(total_disk-total_chunks+total_free, mode));
+	printf("min: %s)\n",
+		df_pretty_sizes((total_disk-total_chunks)/2+total_free, mode));
+	printf("Data to disk ratio:\t%*.0f %%\n",
+		width-2, K*100);
+
+exit:
+
+	if (sargs)
+		free(sargs);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_df_usage[] = {
+	"btrfs filesystem df [-b] <path> [<path>..]",
+	"Show space usage information for a mount point(s).",
+	"",
+	"-b\tSet byte as unit",
+	NULL
+};
+
+int cmd_filesystem_df(int argc, char **argv)
+{
+
+	int	flags = DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "b");
+		if (c < 0)
+			break;
+
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		default:
+			usage(cmd_filesystem_df_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_df_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		DIR *dirstream = NULL;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i], &dirstream);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_disk_free(fd, argv[i], flags);
+		close_file_or_dir(fd, dirstream);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
+
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
new file mode 100644
index 0000000..9f68bb3
--- /dev/null
+++ b/cmds-fi-disk_usage.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __CMDS_FI_DISK_USAGE__
+#define __CMDS_FI_DISK_USAGE__
+
+extern const char * const cmd_filesystem_df_usage[];
+int cmd_filesystem_df(int argc, char **argv);
+
+#endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 1c1926b..fc85eef 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -36,6 +36,7 @@
 #include "volumes.h"
 #include "version.h"
 #include "commands.h"
+#include "cmds-fi-disk_usage.h"
 #include "list_sort.h"
 
 
@@ -111,49 +112,6 @@ static const char * const filesystem_cmd_group_usage[] = {
 	NULL
 };
 
-static const char * const cmd_df_usage[] = {
-	"btrfs filesystem df <path>",
-	"Show space usage information for a mount point",
-	NULL
-};
-
-static char *group_type_str(u64 flag)
-{
-	switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) {
-	case BTRFS_BLOCK_GROUP_DATA:
-		return "Data";
-	case BTRFS_BLOCK_GROUP_SYSTEM:
-		return "System";
-	case BTRFS_BLOCK_GROUP_METADATA:
-		return "Metadata";
-	case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA:
-		return "Data+Metadata";
-	default:
-		return "unknown";
-	}
-}
-
-static char *group_profile_str(u64 flag)
-{
-	switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
-	case 0:
-		return "single";
-	case BTRFS_BLOCK_GROUP_RAID0:
-		return "RAID0";
-	case BTRFS_BLOCK_GROUP_RAID1:
-		return "RAID1";
-	case BTRFS_BLOCK_GROUP_RAID5:
-		return "RAID5";
-	case BTRFS_BLOCK_GROUP_RAID6:
-		return "RAID6";
-	case BTRFS_BLOCK_GROUP_DUP:
-		return "DUP";
-	case BTRFS_BLOCK_GROUP_RAID10:
-		return "RAID10";
-	default:
-		return "unknown";
-	}
-}
 
 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
 {
@@ -203,51 +161,6 @@ static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
 	return 0;
 }
 
-static void print_df(struct btrfs_ioctl_space_args *sargs)
-{
-	u64 i;
-	struct btrfs_ioctl_space_info *sp = sargs->spaces;
-
-	for (i = 0; i < sargs->total_spaces; i++, sp++) {
-		printf("%s, %s: total=%s, used=%s\n",
-			group_type_str(sp->flags),
-			group_profile_str(sp->flags),
-			pretty_size(sp->total_bytes),
-			pretty_size(sp->used_bytes));
-	}
-}
-
-static int cmd_df(int argc, char **argv)
-{
-	struct btrfs_ioctl_space_args *sargs = NULL;
-	int ret;
-	int fd;
-	char *path;
-	DIR  *dirstream = NULL;
-
-	if (check_argc_exact(argc, 2))
-		usage(cmd_df_usage);
-
-	path = argv[1];
-
-	fd = open_file_or_dir(path, &dirstream);
-	if (fd < 0) {
-		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
-		return 1;
-	}
-	ret = get_df(fd, &sargs);
-
-	if (!ret && sargs) {
-		print_df(sargs);
-		free(sargs);
-	} else {
-		fprintf(stderr, "ERROR: get_df failed %s\n", strerror(-ret));
-	}
-
-	close_file_or_dir(fd, dirstream);
-	return !!ret;
-}
-
 static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
 {
 	char uuidbuf[37];
@@ -878,7 +791,7 @@ static int cmd_label(int argc, char **argv)
 
 const struct cmd_group filesystem_cmd_group = {
 	filesystem_cmd_group_usage, NULL, {
-		{ "df", cmd_df, cmd_df_usage, NULL, 0 },
+		{ "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
 		{ "show", cmd_show, cmd_show_usage, NULL, 0 },
 		{ "sync", cmd_sync, cmd_sync_usage, NULL, 0 },
 		{ "defragment", cmd_defrag, cmd_defrag_usage, NULL, 0 },
diff --git a/ctree.h b/ctree.h
index 2117374..ff7ffee 100644
--- a/ctree.h
+++ b/ctree.h
@@ -830,9 +830,22 @@ struct btrfs_csum_item {
 #define BTRFS_BLOCK_GROUP_RAID1		(1ULL << 4)
 #define BTRFS_BLOCK_GROUP_DUP		(1ULL << 5)
 #define BTRFS_BLOCK_GROUP_RAID10	(1ULL << 6)
-#define BTRFS_BLOCK_GROUP_RAID5    (1ULL << 7)
-#define BTRFS_BLOCK_GROUP_RAID6    (1ULL << 8)
+#define BTRFS_BLOCK_GROUP_RAID5    	(1ULL << 7)
+#define BTRFS_BLOCK_GROUP_RAID6    	(1ULL << 8)
 #define BTRFS_BLOCK_GROUP_RESERVED	BTRFS_AVAIL_ALLOC_BIT_SINGLE
+#define BTRFS_NR_RAID_TYPES             7
+
+#define BTRFS_BLOCK_GROUP_TYPE_MASK     (BTRFS_BLOCK_GROUP_DATA |    \
+					 BTRFS_BLOCK_GROUP_SYSTEM |  \
+					 BTRFS_BLOCK_GROUP_METADATA)
+
+#define BTRFS_BLOCK_GROUP_PROFILE_MASK  (BTRFS_BLOCK_GROUP_RAID0 |   \
+					 BTRFS_BLOCK_GROUP_RAID1 |   \
+					 BTRFS_BLOCK_GROUP_RAID5 |   \
+					 BTRFS_BLOCK_GROUP_RAID6 |   \
+					 BTRFS_BLOCK_GROUP_DUP |     \
+					 BTRFS_BLOCK_GROUP_RAID10)
+
 
 #define BTRFS_BLOCK_GROUP_TYPE_MASK	(BTRFS_BLOCK_GROUP_DATA |    \
 					 BTRFS_BLOCK_GROUP_SYSTEM |  \
diff --git a/utils.c b/utils.c
index f499023..760db6b 100644
--- a/utils.c
+++ b/utils.c
@@ -38,6 +38,8 @@
 #include <linux/kdev_t.h>
 #include <limits.h>
 #include <blkid/blkid.h>
+#include <sys/vfs.h>
+
 #include "kerncompat.h"
 #include "radix-tree.h"
 #include "ctree.h"
@@ -2108,3 +2110,14 @@ int lookup_ino_rootid(int fd, u64 *rootid)
 
 	return 0;
 }
+
+u64 disk_size(char *path)
+{
+	struct statfs	sfs;
+
+	if (statfs(path, &sfs) < 0)
+		return 0;
+	else
+		return sfs.f_bsize * sfs.f_blocks;
+
+}
diff --git a/utils.h b/utils.h
index 6f4b10c..0f7939c 100644
--- a/utils.h
+++ b/utils.h
@@ -20,6 +20,7 @@
 #define __UTILS__
 
 #include <sys/stat.h>
+#include "kerncompat.h"
 #include "ctree.h"
 #include <dirent.h>
 
@@ -95,4 +96,5 @@ int lookup_ino_rootid(int fd, u64 *rootid);
 int btrfs_scan_lblkid(int update_kernel);
 int get_btrfs_mount(const char *dev, char *mp, size_t mp_size);
 
+u64 disk_size(char *path);
 #endif
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 2/8] Create the man page entry for the command btrfs fi df
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 1/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
@ 2014-02-13 19:19 ` Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 3/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:19 UTC (permalink / raw)
  To: linux-btrfs


Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 man/btrfs.8.in | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index b620348..4acf16d 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -35,6 +35,9 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem label\fP [\fI<device>\fP|\fI<mount_point>\fP] [\fI<newlabel>\fP]
 .PP
+\fBbtrfs\fP \fBfilesystem df\fP\fI [-b] \fIpath [path..]\fR\fP
+.PP
+\fBbtrfs\fP \fBfilesystem balance\fP\fI <path> \fP
 .PP
 \fBbtrfs\fP \fB[filesystem] balance start\fP [\fIoptions\fP] \fI<path>\fP
 .PP
@@ -370,6 +373,55 @@ force reducing of metadata integrity
 
 \fB[filesystem] balance pause\fR\fI <path>\fR
 Pause running balance.
+
+.RE
+.TP
+
+\fBfilesystem df\fP [-b] \fIpath [path..]\fR
+
+Show space usage information for a mount point.
+
+\fB-b\fP Set byte as unit
+
+The command \fBbtrfs filesystem df\fP is used to query how many space on the 
+disk(s) are used and an estimation of the free
+space of the filesystem.
+The output of the command \fBbtrfs filesystem df\fP shows:
+
+.RS
+.IP \fBDisk\ size\fP
+the total size of the disks which compose the filesystem.
+
+.IP \fBDisk\ allocated\fP
+the size of the area of the disks used by the chunks.
+
+.IP \fBDisk\ unallocated\fP 
+the size of the area of the disks which is free (i.e.
+the differences of the values above).
+
+.IP \fBUsed\fP
+the portion of the logical space used by the file and metadata.
+
+.IP \fBFree\ (estimated)\fP
+the estimated free space available: i.e. how many space can be used
+by the user. The evaluation 
+cannot be rigorous because it depends by the allocation policy (DUP, Single,
+RAID1...) of the metadata and data chunks. If every chunk is stored as
+"Single" the sum of the \fBfree (estimated)\fP space and the \fBused\fP 
+space  is equal to the \fBdisk size\fP.
+Otherwise if all the chunk are mirrored (raid1 or raid10) or duplicated
+the sum of the \fBfree (estimated)\fP space and the \fBused\fP space is
+half of the \fBdisk size\fP. Normally the \fBfree (estimated)\fP is between
+these two limits.
+
+.IP \fBData\ to\ disk\ ratio\fP
+the ratio betwen the \fBlogical size\fP (i.e. the space available by
+the chunks) and the \fBdisk allocated\fP (by the chunks). Normally it is 
+lower than 100% because the metadata is duplicated for security reasons.
+If all the data and metadata are duplicated (or have a profile like RAID1)
+the \fBData\ to\ disk\ ratio\fP could be 50%.
+
+.RE
 .TP
 
 \fB[filesystem] balance cancel\fR\fI <path>\fR
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 3/8] Add helpers functions to handle the printing of data in tabular format.
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 1/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 2/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
@ 2014-02-13 19:19 ` Goffredo Baroncelli
  2014-02-13 19:19 ` [PATCH 4/8] Allow use of get_device_info() Goffredo Baroncelli
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:19 UTC (permalink / raw)
  To: linux-btrfs

This patch adds some functions to manage the printing of the data in
tabular format.

The function
	struct string_table *table_create(int columns, int rows)
creates an (empty) table.

The functions
	char *table_printf(struct string_table *tab, int column,
		int row, char *fmt, ...)
	char *table_vprintf(struct string_table *tab, int column,
		int row, char *fmt, va_list ap)
populate the table with text. To align the text to the left, the text
shall be prefixed with '<', otherwise the text shall be prefixed by a
'>'. If the first character is a '=', the the text is replace by a
sequence of '=' to fill the column width.

The function
	void table_free(struct string_table *)
frees all the data associated to the table.

The function
	void table_dump(struct string_table *tab)
prints the table on stdout.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 Makefile       |   2 +-
 string_table.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string_table.h |  36 +++++++++++++
 3 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 string_table.c
 create mode 100644 string_table.h

diff --git a/Makefile b/Makefile
index db470b6..5738379 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ CFLAGS = -g -O1 -fno-strict-aliasing
 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
 	  root-tree.o dir-item.o file-item.o inode-item.o inode-map.o \
 	  extent-cache.o extent_io.o volumes.o utils.o repair.o \
-	  qgroup.o raid6.o free-space-cache.o list_sort.o
+	  qgroup.o raid6.o free-space-cache.o list_sort.o string_table.o 
 cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \
 	       cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \
 	       cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \
diff --git a/string_table.c b/string_table.c
new file mode 100644
index 0000000..016356c
--- /dev/null
+++ b/string_table.c
@@ -0,0 +1,156 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "string_table.h"
+
+/*
+ *  This function create an array of char * which will represent a table
+ */
+struct string_table *table_create(int columns, int rows)
+{
+	struct string_table *p;
+	int size;
+
+	size = sizeof( struct string_table ) +
+		rows * columns* sizeof(char *);
+	p = calloc(1, size);
+
+	if (!p) return NULL;
+
+	p->ncols = columns;
+	p->nrows = rows;
+
+	return p;
+}
+
+/*
+ * This function is like a vprintf, but store the results in a cell of
+ * the table.
+ * If fmt  starts with '<', the text is left aligned; if fmt starts with
+ * '>' the text is right aligned. If fmt is equal to '=' the text will
+ * be replaced by a '=====' dimensioned on the basis of the column width
+ */
+char *table_vprintf(struct string_table *tab, int column, int row,
+			  char *fmt, va_list ap)
+{
+	int idx = tab->ncols*row+column;
+	char *msg = calloc(100, sizeof(char));
+
+	if (!msg)
+		return NULL;
+
+	if (tab->cells[idx])
+		free(tab->cells[idx]);
+	tab->cells[idx] = msg;
+	vsnprintf(msg, 99, fmt, ap);
+
+	return msg;
+}
+
+
+/*
+ * This function is like a printf, but store the results in a cell of
+ * the table.
+ */
+char *table_printf(struct string_table *tab, int column, int row,
+			  char *fmt, ...)
+{
+	va_list ap;
+	char *ret;
+
+	va_start(ap, fmt);
+	ret = table_vprintf(tab, column, row, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+/*
+ * This function dumps the table. Every "=" string will be replaced by
+ * a "=======" length as the column
+ */
+void table_dump(struct string_table *tab)
+{
+	int	sizes[tab->ncols];
+	int	i, j;
+
+	for (i = 0 ; i < tab->ncols ; i++) {
+		sizes[i] = 0;
+		for (j = 0 ; j < tab->nrows ; j++) {
+			int idx = i + j*tab->ncols;
+			int s;
+
+			if (!tab->cells[idx])
+				continue;
+
+			s = strlen(tab->cells[idx]) - 1;
+			if (s < 1 || tab->cells[idx][0] == '=')
+				continue;
+
+			if (s > sizes[i])
+				sizes[i] = s;
+		}
+	}
+
+
+	for (j = 0 ; j < tab->nrows ; j++) {
+		for (i = 0 ; i < tab->ncols ; i++) {
+
+			int idx = i + j*tab->ncols;
+			char *s = tab->cells[idx];
+
+			if (!s|| !strlen(s)) {
+				printf("%*s", sizes[i], "");
+			} else if (s && s[0] == '=') {
+				int k = sizes[i];
+				while(k--)
+					putchar('=');
+			} else {
+				printf("%*s",
+					s[0] == '<' ? -sizes[i] : sizes[i],
+					s+1);
+			}
+			if (i != (tab->ncols - 1))
+				putchar(' ');
+		}
+		putchar('\n');
+	}
+
+}
+
+/*
+ *  Deallocate a tabular and all its content
+ */
+
+void table_free(struct string_table *tab)
+{
+
+	int	i, count;
+
+	count = tab->ncols * tab->nrows;
+
+	for (i=0 ; i < count ; i++)
+		if (tab->cells[i])
+			free(tab->cells[i]);
+
+	free(tab);
+
+}
diff --git a/string_table.h b/string_table.h
new file mode 100644
index 0000000..83c4425
--- /dev/null
+++ b/string_table.h
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef STRING_TABLE_H
+#define STRING_TABLE_H
+
+struct string_table {
+
+	int	ncols, nrows;
+	char	*cells[];
+
+};
+
+
+struct string_table *table_create(int columns, int rows);
+char *table_printf(struct string_table *tab, int column, int row,
+			  char *fmt, ...);
+char *table_vprintf(struct string_table *tab, int column, int row,
+			  char *fmt, va_list ap);
+void table_dump(struct string_table *tab);
+void table_free(struct string_table *);
+
+#endif
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 4/8] Allow use of get_device_info()
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (2 preceding siblings ...)
  2014-02-13 19:19 ` [PATCH 3/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
@ 2014-02-13 19:19 ` Goffredo Baroncelli
  2014-02-20 18:13   ` David Sterba
  2014-02-13 19:19 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:19 UTC (permalink / raw)
  To: linux-btrfs


Allow the use of get_device_info()  for different units.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 utils.c | 2 +-
 utils.h | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/utils.c b/utils.c
index 760db6b..69295b5 100644
--- a/utils.c
+++ b/utils.c
@@ -1591,7 +1591,7 @@ void close_file_or_dir(int fd, DIR *dirstream)
 		close(fd);
 }
 
-static int get_device_info(int fd, u64 devid,
+int get_device_info(int fd, u64 devid,
 		struct btrfs_ioctl_dev_info_args *di_args)
 {
 	int ret;
diff --git a/utils.h b/utils.h
index 0f7939c..58fb4a7 100644
--- a/utils.h
+++ b/utils.h
@@ -97,4 +97,6 @@ int btrfs_scan_lblkid(int update_kernel);
 int get_btrfs_mount(const char *dev, char *mp, size_t mp_size);
 
 u64 disk_size(char *path);
+int get_device_info(int fd, u64 devid,
+		struct btrfs_ioctl_dev_info_args *di_args);
 #endif
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (3 preceding siblings ...)
  2014-02-13 19:19 ` [PATCH 4/8] Allow use of get_device_info() Goffredo Baroncelli
@ 2014-02-13 19:19 ` Goffredo Baroncelli
  2014-02-13 19:28   ` Roman Mamedov
  2014-02-13 19:20 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:19 UTC (permalink / raw)
  To: linux-btrfs

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-fi-disk_usage.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |   3 +
 cmds-filesystem.c    |   3 +
 utils.c              |  63 ++++++++
 utils.h              |   3 +
 5 files changed, 500 insertions(+)

diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 4012c78..16b3ab2 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -20,10 +20,12 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include "utils.h"
 #include "kerncompat.h"
 #include "ctree.h"
+#include "string_table.h"
 
 #include "commands.h"
 
@@ -44,6 +46,13 @@ struct chunk_info {
 	u64	num_stripes;
 };
 
+/* to store information about the disks */
+struct disk_info {
+	u64	devid;
+	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
+	u64	size;
+};
+
 /*
  * Pretty print the size
  * PAY ATTENTION: it return a statically buffer
@@ -514,3 +523,422 @@ int cmd_filesystem_df(int argc, char **argv)
 	return 0;
 }
 
+/*
+ *  Helper to sort the disk_info structure
+ */
+static int cmp_disk_info(const void *a, const void *b)
+{
+	return strcmp(((struct disk_info *)a)->path,
+			((struct disk_info *)b)->path);
+}
+
+/*
+ *  This function load the disk_info structure and put them in an array
+ */
+static int load_disks_info(int fd,
+			   struct disk_info **disks_info_ptr,
+			   int *disks_info_count)
+{
+
+	int ret, i, ndevs;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+	struct disk_info *info;
+
+	*disks_info_count = 0;
+	*disks_info_ptr = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		fprintf(stderr, "ERROR: cannot get filesystem info\n");
+		return -1;
+	}
+
+	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
+	if (!info) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return -1;
+	}
+
+	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
+
+		BUG_ON(ndevs >= fi_args.num_devices);
+		ret = get_device_info(fd, i, &dev_info);
+
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			fprintf(stderr,
+			    "ERROR: cannot get info about device devid=%d\n",
+			    i);
+			free(info);
+			return -1;
+		}
+
+		info[ndevs].devid = dev_info.devid;
+		strcpy(info[ndevs].path, (char *)dev_info.path);
+		info[ndevs].size = get_partition_size((char *)dev_info.path);
+		++ndevs;
+	}
+
+	BUG_ON(ndevs != fi_args.num_devices);
+	qsort(info, fi_args.num_devices,
+		sizeof(struct disk_info), cmp_disk_info);
+
+	*disks_info_count = fi_args.num_devices;
+	*disks_info_ptr = info;
+
+	return 0;
+
+}
+
+/*
+ *  This function computes the size of a chunk in a disk
+ */
+static u64 calc_chunk_size(struct chunk_info *ci)
+{
+	if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
+		return ci->size / ci->num_stripes;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
+		return ci->size / (ci->num_stripes -1);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
+		return ci->size / (ci->num_stripes -2);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
+		return ci->size / ci->num_stripes;
+	return ci->size;
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in tabular format
+ */
+static void _cmd_filesystem_disk_usage_tabular(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *chunks_info_ptr,
+					int chunks_info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+	u64 total_unused = 0;
+	struct string_table *matrix = 0;
+	int  ncols, nrows;
+
+	ncols = sargs->total_spaces + 2;
+	nrows = 2 + 1 + disks_info_count + 1 + 2;
+
+	matrix = table_create(ncols, nrows);
+	if (!matrix) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return;
+	}
+
+	/* header */
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+
+		u64 flags = sargs->spaces[i].flags;
+		description = group_type_str(flags);
+
+		table_printf(matrix, 1+i, 0, "<%s", description);
+	}
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		r_mode = group_profile_str(flags);
+
+		table_printf(matrix, 1+i, 1, "<%s", r_mode);
+	}
+
+	table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
+
+	/* body */
+	for (i = 0 ; i < disks_info_count ; i++) {
+		int k, col;
+		char *p;
+
+		u64  total_allocated = 0, unused;
+
+		p = strrchr(disks_info_ptr[i].path, '/');
+		if (!p)
+			p = disks_info_ptr[i].path;
+		else
+			p++;
+
+		table_printf(matrix, 0, i+3, "<%s",
+				disks_info_ptr[i].path);
+
+		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
+			u64	flags = sargs->spaces[k].flags;
+			u64 devid = disks_info_ptr[i].devid;
+			int	j;
+			u64 size = 0;
+
+			for (j = 0 ; j < chunks_info_count ; j++) {
+				if (chunks_info_ptr[j].type != flags )
+						continue;
+				if (chunks_info_ptr[j].devid != devid)
+						continue;
+
+				size += calc_chunk_size(chunks_info_ptr+j);
+			}
+
+			if (size)
+				table_printf(matrix, col, i+3,
+					">%s", df_pretty_sizes(size, mode));
+			else
+				table_printf(matrix, col, i+3, ">-");
+
+			total_allocated += size;
+			col++;
+		}
+
+		unused = get_partition_size(disks_info_ptr[i].path) -
+				total_allocated;
+
+		table_printf(matrix, sargs->total_spaces + 1, i + 3,
+			       ">%s", df_pretty_sizes(unused, mode));
+		total_unused += unused;
+
+	}
+
+	for (i = 0; i <= sargs->total_spaces; i++)
+		table_printf(matrix, i + 1, disks_info_count + 3, "=");
+
+
+	/* footer */
+	table_printf(matrix, 0, disks_info_count + 4, "<Total");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1 + i, disks_info_count + 4,
+			">%s",
+			df_pretty_sizes(sargs->spaces[i].total_bytes, mode));
+
+	table_printf(matrix, sargs->total_spaces+1, disks_info_count+4,
+		">%s", df_pretty_sizes(total_unused, mode));
+
+	table_printf(matrix, 0, disks_info_count+5, "<Used");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1+i, disks_info_count+5, ">%s",
+			df_pretty_sizes(sargs->spaces[i].used_bytes, mode));
+
+
+	table_dump(matrix);
+	table_free(matrix);
+
+}
+
+/*
+ *  This function prints the unused space per every disk
+ */
+static void print_unused(struct chunk_info *info_ptr,
+			  int info_count,
+			  struct disk_info *disks_info_ptr,
+			  int disks_info_count,
+			  int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+
+		for (j = 0 ; j < info_count ; j++)
+			if (info_ptr[j].devid == disks_info_ptr[i].devid)
+				total += calc_chunk_size(info_ptr+j);
+
+		printf("   %s\t%10s\n",
+			disks_info_ptr[i].path,
+			df_pretty_sizes(disks_info_ptr[i].size - total, mode));
+
+	}
+
+}
+
+/*
+ *  This function prints the allocated chunk per every disk
+ */
+static void print_chunk_disks(u64 chunk_type,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				struct disk_info *disks_info_ptr,
+				int disks_info_count,
+				int mode)
+{
+	int i;
+
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+
+		for (j = 0 ; j < chunks_info_count ; j++) {
+
+			if (chunks_info_ptr[j].type != chunk_type)
+				continue;
+			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
+				continue;
+
+			total += calc_chunk_size(&(chunks_info_ptr[j]));
+			//total += chunks_info_ptr[j].size;
+		}
+
+		if (total > 0)
+			printf("   %s\t%10s\n",
+				disks_info_ptr[i].path,
+				df_pretty_sizes(total, mode));
+	}
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in linear format
+ */
+static void _cmd_filesystem_disk_usage_linear(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *info_ptr,
+					int info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		description= group_type_str(flags);
+		r_mode = group_profile_str(flags);
+
+		printf("%s,%s: Size:%s, ",
+			description,
+			r_mode,
+			df_pretty_sizes(sargs->spaces[i].total_bytes ,
+			    mode));
+		printf("Used:%s\n",
+			df_pretty_sizes(sargs->spaces[i].used_bytes,
+					mode));
+		print_chunk_disks(flags, info_ptr, info_count,
+				disks_info_ptr, disks_info_count,
+				mode);
+		printf("\n");
+
+	}
+
+	printf("Unallocated:\n");
+	print_unused(info_ptr, info_count,
+			disks_info_ptr, disks_info_count,
+			mode);
+
+
+
+}
+
+static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+	int ret = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (tabular)
+		_cmd_filesystem_disk_usage_tabular(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+	else
+		_cmd_filesystem_disk_usage_linear(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+
+exit:
+
+	if (sargs)
+		free(sargs);
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_disk_usage_usage[] = {
+	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
+	"Show in which disk the chunks are allocated.",
+	"",
+	"-b\tSet byte as unit",
+	"-t\tShow data in tabular format",
+	NULL
+};
+
+int cmd_filesystem_disk_usage(int argc, char **argv)
+{
+
+	int	flags =	DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+	int	tabular = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "bt");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		case 't':
+			tabular = 1;
+			break;
+		default:
+			usage(cmd_filesystem_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		DIR	*dirstream = NULL;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i], &dirstream);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
+		close_file_or_dir(fd, dirstream);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index 9f68bb3..c7459b1 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -22,4 +22,7 @@
 extern const char * const cmd_filesystem_df_usage[];
 int cmd_filesystem_df(int argc, char **argv);
 
+extern const char * const cmd_filesystem_disk_usage_usage[];
+int cmd_filesystem_disk_usage(int argc, char **argv);
+
 #endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index fc85eef..d4cab63 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -798,6 +798,9 @@ const struct cmd_group filesystem_cmd_group = {
 		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
 		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
 		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
+		{ "disk-usage", cmd_filesystem_disk_usage,
+			cmd_filesystem_disk_usage_usage, NULL, 0 },
+
 		NULL_CMD_STRUCT
 	}
 };
diff --git a/utils.c b/utils.c
index 69295b5..8b27552 100644
--- a/utils.c
+++ b/utils.c
@@ -2121,3 +2121,66 @@ u64 disk_size(char *path)
 		return sfs.f_bsize * sfs.f_blocks;
 
 }
+
+u64 get_partition_size(char *dev)
+{
+	u64 result;
+	int fd = open(dev, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
+		close(fd);
+		return 0;
+	}
+	close(fd);
+
+	return result;
+}
+
+
+
+
+/*
+ *  Convert a chunk type to a chunk description
+ */
+const char *group_type_str(u64 flag)
+{
+	switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) {
+	case BTRFS_BLOCK_GROUP_DATA:
+		return "Data";
+	case BTRFS_BLOCK_GROUP_SYSTEM:
+		return "System";
+	case BTRFS_BLOCK_GROUP_METADATA:
+		return "Metadata";
+	case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA:
+		return "Data+Metadata";
+	default:
+		return "unknown";
+	}
+}
+
+/*
+ *  Convert a chunk type to a chunk profile description
+ */
+const char *group_profile_str(u64 flag)
+{
+	switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
+	case 0:
+		return "single";
+	case BTRFS_BLOCK_GROUP_RAID0:
+		return "RAID0";
+	case BTRFS_BLOCK_GROUP_RAID1:
+		return "RAID1";
+	case BTRFS_BLOCK_GROUP_RAID5:
+		return "RAID5";
+	case BTRFS_BLOCK_GROUP_RAID6:
+		return "RAID6";
+	case BTRFS_BLOCK_GROUP_DUP:
+		return "DUP";
+	case BTRFS_BLOCK_GROUP_RAID10:
+		return "RAID10";
+	default:
+		return "unknown";
+	}
+}
diff --git a/utils.h b/utils.h
index 58fb4a7..8469d4a 100644
--- a/utils.h
+++ b/utils.h
@@ -99,4 +99,7 @@ int get_btrfs_mount(const char *dev, char *mp, size_t mp_size);
 u64 disk_size(char *path);
 int get_device_info(int fd, u64 devid,
 		struct btrfs_ioctl_dev_info_args *di_args);
+u64 get_partition_size(char *dev);
+const char * group_type_str(u64 flags);
+const char * group_profile_str(u64 flags);
 #endif
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 6/8] Create entry in man page for btrfs filesystem disk-usage
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (4 preceding siblings ...)
  2014-02-13 19:19 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
@ 2014-02-13 19:20 ` Goffredo Baroncelli
  2014-02-13 19:20 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:20 UTC (permalink / raw)
  To: linux-btrfs

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 man/btrfs.8.in | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 4acf16d..4b7e771 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -35,6 +35,9 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem label\fP [\fI<device>\fP|\fI<mount_point>\fP] [\fI<newlabel>\fP]
 .PP
+\fBbtrfs\fP \fBfilesystem filesystem disk-usage [-t][-b]\fP\fI <path> 
+[path..]\fP
+.PP
 \fBbtrfs\fP \fBfilesystem df\fP\fI [-b] \fIpath [path..]\fR\fP
 .PP
 \fBbtrfs\fP \fBfilesystem balance\fP\fI <path> \fP
@@ -341,6 +344,17 @@ the same starting disk cylinder as before.
 \fBfilesystem label\fP [\fI<dev>\fP|\fI<mount_point>\fP] [\fInewlabel\fP]\fP
 Show or update the label of a filesystem. \fI[<device>|<mountpoint>]\fR is used
 to identify the filesystem. 
+.TP
+\fBfilesystem disk-usage\fP [-t][-b] \fIpath [path..]\fR
+
+Show in which disk the chunks are allocated.
+
+\fB-b\fP Set byte as unit
+
+\fB-t\fP Show data in tabular format
+
+.TP
+
 If a \fInewlabel\fR optional argument is passed, the label is changed. The
 following constraints exist for a label:
 .IP
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 7/8] Add btrfs device disk-usage command
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (5 preceding siblings ...)
  2014-02-13 19:20 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
@ 2014-02-13 19:20 ` Goffredo Baroncelli
  2014-02-13 19:23   ` Roman Mamedov
  2014-02-13 19:20 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:20 UTC (permalink / raw)
  To: linux-btrfs


Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-device.c        |   3 ++
 cmds-fi-disk_usage.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |   3 ++
 3 files changed, 142 insertions(+)

diff --git a/cmds-device.c b/cmds-device.c
index bc4a8dc..f25dbfa 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -28,6 +28,7 @@
 #include "ctree.h"
 #include "ioctl.h"
 #include "utils.h"
+#include "cmds-fi-disk_usage.h"
 
 #include "commands.h"
 
@@ -401,6 +402,8 @@ const struct cmd_group device_cmd_group = {
 		{ "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 },
 		{ "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 },
 		{ "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 },
+		{ "disk-usage", cmd_device_disk_usage,
+			cmd_device_disk_usage_usage, NULL, 0 },
 		NULL_CMD_STRUCT
 	}
 };
diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 16b3ab2..e4eb72b 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -942,3 +942,139 @@ int cmd_filesystem_disk_usage(int argc, char **argv)
 
 	return 0;
 }
+
+static void print_disk_chunks(int fd,
+				u64 devid,
+				u64 total_size,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				int mode)
+{
+	int i;
+	u64 allocated = 0;
+
+	for (i = 0 ; i < chunks_info_count ; i++) {
+		const char *description;
+		const char *r_mode;
+		u64 flags;
+		u64 size;
+
+		if (chunks_info_ptr[i].devid != devid)
+			continue;
+
+		flags = chunks_info_ptr[i].type;
+
+		description = group_type_str(flags);
+		r_mode = group_profile_str(flags);
+		size = calc_chunk_size(chunks_info_ptr+i);
+		printf("   %s,%s:%*s%10s\n",
+			description,
+			r_mode,
+			(int)(20 - strlen(description) - strlen(r_mode)), "",
+			df_pretty_sizes(size, mode));
+
+		allocated += size;
+
+	}
+	printf("   Unallocated: %*s%10s\n",
+		(int)(20 - strlen("Unallocated")), "",
+		df_pretty_sizes(total_size - allocated, mode));
+
+}
+
+static int _cmd_device_disk_usage(int fd, char *path, int mode)
+{
+	int i;
+	int ret = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	for (i = 0 ; i < disks_info_count ; i++) {
+		printf("%s\t%10s\n", disks_info_ptr[i].path,
+			df_pretty_sizes(disks_info_ptr[i].size, mode));
+
+		print_disk_chunks(fd, disks_info_ptr[i].devid,
+				disks_info_ptr[i].size,
+				info_ptr, info_count,
+				mode);
+		printf("\n");
+
+	}
+
+
+exit:
+
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_device_disk_usage_usage[] = {
+	"btrfs device disk-usage [-b] <path> [<path>..]",
+	"Show which chunks are in a device.",
+	"",
+	"-b\tSet byte as unit",
+	NULL
+};
+
+int cmd_device_disk_usage(int argc, char **argv)
+{
+
+	int	flags = DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "b");
+
+		if (c < 0)
+			break;
+
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		default:
+			usage(cmd_device_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_device_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		DIR	*dirstream = NULL;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i], &dirstream);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_device_disk_usage(fd, argv[i], flags);
+		close_file_or_dir(fd, dirstream);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index c7459b1..c315004 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -25,4 +25,7 @@ int cmd_filesystem_df(int argc, char **argv);
 extern const char * const cmd_filesystem_disk_usage_usage[];
 int cmd_filesystem_disk_usage(int argc, char **argv);
 
+extern const char * const cmd_device_disk_usage_usage[];
+int cmd_device_disk_usage(int argc, char **argv);
+
 #endif
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage.
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (6 preceding siblings ...)
  2014-02-13 19:20 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
@ 2014-02-13 19:20 ` Goffredo Baroncelli
  2014-02-17 18:41 ` [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df David Sterba
  2014-02-20 18:08 ` David Sterba
  9 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:20 UTC (permalink / raw)
  To: linux-btrfs


Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 man/btrfs.8.in | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 4b7e771..0984504 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -59,6 +59,9 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBdevice scan\fP [\fI--all-devices\fP|\fI<device> \P[\fI<device>...\fP]
 .PP
+\fBbtrfs\fP \fBdevice disk-usage\fP\fI [-b] <path> [<path>...] \fP
+.PP
+.PP
 \fBbtrfs\fP \fBdevice ready\fP\fI <device>\fP
 .PP
 \fBbtrfs\fP \fBdevice stats\fP [-z] {\fI<path>\fP|\fI<device>\fP}
@@ -474,6 +477,14 @@ Remove device(s) from a filesystem identified by \fI<path>\fR.
 .TP
 
 \fBdevice scan\fR [--all-devices|\fI<device> \fP[\fI<device>...\fP]\fR
+.TP
+
+\fBdevice disk-usage\fR\fI [-b] <path> [<path>..] <path>\fR
+Show which chunks are in a device.
+
+\fB-b\fP set byte as unit.
+.TP
+
 If one or more devices are passed, these are scanned for a btrfs filesystem. 
 If no devices are passed, \fBbtrfs\fR uses block devices containing btrfs
 filesystem as listed by blkid.
-- 
1.8.5.3



-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 7/8] Add btrfs device disk-usage command
  2014-02-13 19:20 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
@ 2014-02-13 19:23   ` Roman Mamedov
  2014-02-13 19:44     ` Goffredo Baroncelli
  0 siblings, 1 reply; 34+ messages in thread
From: Roman Mamedov @ 2014-02-13 19:23 UTC (permalink / raw)
  To: kreijack; +Cc: kreijack, linux-btrfs

[-- Attachment #1: Type: text/plain, Size: 1405 bytes --]

On Thu, 13 Feb 2014 20:20:12 +0100
Goffredo Baroncelli <kreijack@libero.it> wrote:

> 
> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
> ---
>  cmds-device.c        |   3 ++
>  cmds-fi-disk_usage.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  cmds-fi-disk_usage.h |   3 ++
>  3 files changed, 142 insertions(+)
> 
> diff --git a/cmds-device.c b/cmds-device.c
> index bc4a8dc..f25dbfa 100644
> --- a/cmds-device.c
> +++ b/cmds-device.c
> @@ -28,6 +28,7 @@
>  #include "ctree.h"
>  #include "ioctl.h"
>  #include "utils.h"
> +#include "cmds-fi-disk_usage.h"
>  
>  #include "commands.h"
>  
> @@ -401,6 +402,8 @@ const struct cmd_group device_cmd_group = {
>  		{ "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 },
>  		{ "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 },
>  		{ "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 },
> +		{ "disk-usage", cmd_device_disk_usage,
> +			cmd_device_disk_usage_usage, NULL, 0 },
>  		NULL_CMD_STRUCT

Why not just name it "du"? Think about the current handy feature of shortening
commands by only specifying parts of the keywords. "btrfs dev du" would seem
more intuitive than calling it as "btrfs dev disk" or "btrfs dev disk-u".

Or simply "usage", because "...device disk..." is redundant, device is already
a disk, so it can easily be "btrfs device usage".

-- 
With respect,
Roman

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 19:19 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
@ 2014-02-13 19:28   ` Roman Mamedov
  2014-02-13 19:49     ` Goffredo Baroncelli
  0 siblings, 1 reply; 34+ messages in thread
From: Roman Mamedov @ 2014-02-13 19:28 UTC (permalink / raw)
  To: kreijack; +Cc: kreijack, linux-btrfs

[-- Attachment #1: Type: text/plain, Size: 13404 bytes --]

On Thu, 13 Feb 2014 20:19:50 +0100
Goffredo Baroncelli <kreijack@libero.it> wrote:

> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
> ---
>  cmds-fi-disk_usage.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  cmds-fi-disk_usage.h |   3 +
>  cmds-filesystem.c    |   3 +
>  utils.c              |  63 ++++++++
>  utils.h              |   3 +
>  5 files changed, 500 insertions(+)
> 
> diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
> index 4012c78..16b3ab2 100644
> --- a/cmds-fi-disk_usage.c
> +++ b/cmds-fi-disk_usage.c
> @@ -20,10 +20,12 @@
>  #include <unistd.h>
>  #include <sys/ioctl.h>
>  #include <errno.h>
> +#include <stdarg.h>
>  
>  #include "utils.h"
>  #include "kerncompat.h"
>  #include "ctree.h"
> +#include "string_table.h"
>  
>  #include "commands.h"
>  
> @@ -44,6 +46,13 @@ struct chunk_info {
>  	u64	num_stripes;
>  };
>  
> +/* to store information about the disks */
> +struct disk_info {
> +	u64	devid;
> +	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
> +	u64	size;
> +};
> +
>  /*
>   * Pretty print the size
>   * PAY ATTENTION: it return a statically buffer
> @@ -514,3 +523,422 @@ int cmd_filesystem_df(int argc, char **argv)
>  	return 0;
>  }
>  
> +/*
> + *  Helper to sort the disk_info structure
> + */
> +static int cmp_disk_info(const void *a, const void *b)
> +{
> +	return strcmp(((struct disk_info *)a)->path,
> +			((struct disk_info *)b)->path);
> +}
> +
> +/*
> + *  This function load the disk_info structure and put them in an array
> + */
> +static int load_disks_info(int fd,
> +			   struct disk_info **disks_info_ptr,
> +			   int *disks_info_count)
> +{
> +
> +	int ret, i, ndevs;
> +	struct btrfs_ioctl_fs_info_args fi_args;
> +	struct btrfs_ioctl_dev_info_args dev_info;
> +	struct disk_info *info;
> +
> +	*disks_info_count = 0;
> +	*disks_info_ptr = 0;
> +
> +	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
> +	if (ret < 0) {
> +		fprintf(stderr, "ERROR: cannot get filesystem info\n");
> +		return -1;
> +	}
> +
> +	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
> +	if (!info) {
> +		fprintf(stderr, "ERROR: not enough memory\n");
> +		return -1;
> +	}
> +
> +	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
> +
> +		BUG_ON(ndevs >= fi_args.num_devices);
> +		ret = get_device_info(fd, i, &dev_info);
> +
> +		if (ret == -ENODEV)
> +			continue;
> +		if (ret) {
> +			fprintf(stderr,
> +			    "ERROR: cannot get info about device devid=%d\n",
> +			    i);
> +			free(info);
> +			return -1;
> +		}
> +
> +		info[ndevs].devid = dev_info.devid;
> +		strcpy(info[ndevs].path, (char *)dev_info.path);
> +		info[ndevs].size = get_partition_size((char *)dev_info.path);
> +		++ndevs;
> +	}
> +
> +	BUG_ON(ndevs != fi_args.num_devices);
> +	qsort(info, fi_args.num_devices,
> +		sizeof(struct disk_info), cmp_disk_info);
> +
> +	*disks_info_count = fi_args.num_devices;
> +	*disks_info_ptr = info;
> +
> +	return 0;
> +
> +}
> +
> +/*
> + *  This function computes the size of a chunk in a disk
> + */
> +static u64 calc_chunk_size(struct chunk_info *ci)
> +{
> +	if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
> +		return ci->size / ci->num_stripes;
> +	else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
> +		return ci->size ;
> +	else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
> +		return ci->size ;
> +	else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
> +		return ci->size / (ci->num_stripes -1);
> +	else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
> +		return ci->size / (ci->num_stripes -2);
> +	else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
> +		return ci->size / ci->num_stripes;
> +	return ci->size;
> +}
> +
> +/*
> + *  This function print the results of the command btrfs fi disk-usage
> + *  in tabular format
> + */
> +static void _cmd_filesystem_disk_usage_tabular(int mode,
> +					struct btrfs_ioctl_space_args *sargs,
> +					struct chunk_info *chunks_info_ptr,
> +					int chunks_info_count,
> +					struct disk_info *disks_info_ptr,
> +					int disks_info_count)
> +{
> +	int i;
> +	u64 total_unused = 0;
> +	struct string_table *matrix = 0;
> +	int  ncols, nrows;
> +
> +	ncols = sargs->total_spaces + 2;
> +	nrows = 2 + 1 + disks_info_count + 1 + 2;
> +
> +	matrix = table_create(ncols, nrows);
> +	if (!matrix) {
> +		fprintf(stderr, "ERROR: not enough memory\n");
> +		return;
> +	}
> +
> +	/* header */
> +	for (i = 0; i < sargs->total_spaces; i++) {
> +		const char *description;
> +
> +		u64 flags = sargs->spaces[i].flags;
> +		description = group_type_str(flags);
> +
> +		table_printf(matrix, 1+i, 0, "<%s", description);
> +	}
> +
> +	for (i = 0; i < sargs->total_spaces; i++) {
> +		const char *r_mode;
> +
> +		u64 flags = sargs->spaces[i].flags;
> +		r_mode = group_profile_str(flags);
> +
> +		table_printf(matrix, 1+i, 1, "<%s", r_mode);
> +	}
> +
> +	table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
> +
> +	/* body */
> +	for (i = 0 ; i < disks_info_count ; i++) {
> +		int k, col;
> +		char *p;
> +
> +		u64  total_allocated = 0, unused;
> +
> +		p = strrchr(disks_info_ptr[i].path, '/');
> +		if (!p)
> +			p = disks_info_ptr[i].path;
> +		else
> +			p++;
> +
> +		table_printf(matrix, 0, i+3, "<%s",
> +				disks_info_ptr[i].path);
> +
> +		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
> +			u64	flags = sargs->spaces[k].flags;
> +			u64 devid = disks_info_ptr[i].devid;
> +			int	j;
> +			u64 size = 0;
> +
> +			for (j = 0 ; j < chunks_info_count ; j++) {
> +				if (chunks_info_ptr[j].type != flags )
> +						continue;
> +				if (chunks_info_ptr[j].devid != devid)
> +						continue;
> +
> +				size += calc_chunk_size(chunks_info_ptr+j);
> +			}
> +
> +			if (size)
> +				table_printf(matrix, col, i+3,
> +					">%s", df_pretty_sizes(size, mode));
> +			else
> +				table_printf(matrix, col, i+3, ">-");
> +
> +			total_allocated += size;
> +			col++;
> +		}
> +
> +		unused = get_partition_size(disks_info_ptr[i].path) -
> +				total_allocated;
> +
> +		table_printf(matrix, sargs->total_spaces + 1, i + 3,
> +			       ">%s", df_pretty_sizes(unused, mode));
> +		total_unused += unused;
> +
> +	}
> +
> +	for (i = 0; i <= sargs->total_spaces; i++)
> +		table_printf(matrix, i + 1, disks_info_count + 3, "=");
> +
> +
> +	/* footer */
> +	table_printf(matrix, 0, disks_info_count + 4, "<Total");
> +	for (i = 0; i < sargs->total_spaces; i++)
> +		table_printf(matrix, 1 + i, disks_info_count + 4,
> +			">%s",
> +			df_pretty_sizes(sargs->spaces[i].total_bytes, mode));
> +
> +	table_printf(matrix, sargs->total_spaces+1, disks_info_count+4,
> +		">%s", df_pretty_sizes(total_unused, mode));
> +
> +	table_printf(matrix, 0, disks_info_count+5, "<Used");
> +	for (i = 0; i < sargs->total_spaces; i++)
> +		table_printf(matrix, 1+i, disks_info_count+5, ">%s",
> +			df_pretty_sizes(sargs->spaces[i].used_bytes, mode));
> +
> +
> +	table_dump(matrix);
> +	table_free(matrix);
> +
> +}
> +
> +/*
> + *  This function prints the unused space per every disk
> + */
> +static void print_unused(struct chunk_info *info_ptr,
> +			  int info_count,
> +			  struct disk_info *disks_info_ptr,
> +			  int disks_info_count,
> +			  int mode)
> +{
> +	int i;
> +	for (i = 0 ; i < disks_info_count ; i++) {
> +
> +		int	j;
> +		u64	total = 0;
> +
> +		for (j = 0 ; j < info_count ; j++)
> +			if (info_ptr[j].devid == disks_info_ptr[i].devid)
> +				total += calc_chunk_size(info_ptr+j);
> +
> +		printf("   %s\t%10s\n",
> +			disks_info_ptr[i].path,
> +			df_pretty_sizes(disks_info_ptr[i].size - total, mode));
> +
> +	}
> +
> +}
> +
> +/*
> + *  This function prints the allocated chunk per every disk
> + */
> +static void print_chunk_disks(u64 chunk_type,
> +				struct chunk_info *chunks_info_ptr,
> +				int chunks_info_count,
> +				struct disk_info *disks_info_ptr,
> +				int disks_info_count,
> +				int mode)
> +{
> +	int i;
> +
> +	for (i = 0 ; i < disks_info_count ; i++) {
> +
> +		int	j;
> +		u64	total = 0;
> +
> +		for (j = 0 ; j < chunks_info_count ; j++) {
> +
> +			if (chunks_info_ptr[j].type != chunk_type)
> +				continue;
> +			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
> +				continue;
> +
> +			total += calc_chunk_size(&(chunks_info_ptr[j]));
> +			//total += chunks_info_ptr[j].size;
> +		}
> +
> +		if (total > 0)
> +			printf("   %s\t%10s\n",
> +				disks_info_ptr[i].path,
> +				df_pretty_sizes(total, mode));
> +	}
> +}
> +
> +/*
> + *  This function print the results of the command btrfs fi disk-usage
> + *  in linear format
> + */
> +static void _cmd_filesystem_disk_usage_linear(int mode,
> +					struct btrfs_ioctl_space_args *sargs,
> +					struct chunk_info *info_ptr,
> +					int info_count,
> +					struct disk_info *disks_info_ptr,
> +					int disks_info_count)
> +{
> +	int i;
> +
> +	for (i = 0; i < sargs->total_spaces; i++) {
> +		const char *description;
> +		const char *r_mode;
> +
> +		u64 flags = sargs->spaces[i].flags;
> +		description= group_type_str(flags);
> +		r_mode = group_profile_str(flags);
> +
> +		printf("%s,%s: Size:%s, ",
> +			description,
> +			r_mode,
> +			df_pretty_sizes(sargs->spaces[i].total_bytes ,
> +			    mode));
> +		printf("Used:%s\n",
> +			df_pretty_sizes(sargs->spaces[i].used_bytes,
> +					mode));
> +		print_chunk_disks(flags, info_ptr, info_count,
> +				disks_info_ptr, disks_info_count,
> +				mode);
> +		printf("\n");
> +
> +	}
> +
> +	printf("Unallocated:\n");
> +	print_unused(info_ptr, info_count,
> +			disks_info_ptr, disks_info_count,
> +			mode);
> +
> +
> +
> +}
> +
> +static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
> +{
> +	struct btrfs_ioctl_space_args *sargs = 0;
> +	int info_count = 0;
> +	struct chunk_info *info_ptr = 0;
> +	struct disk_info *disks_info_ptr = 0;
> +	int disks_info_count = 0;
> +	int ret = 0;
> +
> +	if (load_chunk_info(fd, &info_ptr, &info_count) ||
> +	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
> +		ret = -1;
> +		goto exit;
> +	}
> +
> +	if ((sargs = load_space_info(fd, path)) == NULL) {
> +		ret = -1;
> +		goto exit;
> +	}
> +
> +	if (tabular)
> +		_cmd_filesystem_disk_usage_tabular(mode, sargs,
> +					info_ptr, info_count,
> +					disks_info_ptr, disks_info_count);
> +	else
> +		_cmd_filesystem_disk_usage_linear(mode, sargs,
> +					info_ptr, info_count,
> +					disks_info_ptr, disks_info_count);
> +
> +exit:
> +
> +	if (sargs)
> +		free(sargs);
> +	if (disks_info_ptr)
> +		free(disks_info_ptr);
> +	if (info_ptr)
> +		free(info_ptr);
> +
> +	return ret;
> +}
> +
> +const char * const cmd_filesystem_disk_usage_usage[] = {
> +	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
> +	"Show in which disk the chunks are allocated.",
> +	"",
> +	"-b\tSet byte as unit",
> +	"-t\tShow data in tabular format",
> +	NULL
> +};
> +
> +int cmd_filesystem_disk_usage(int argc, char **argv)
> +{
> +
> +	int	flags =	DF_HUMAN_UNIT;
> +	int	i, more_than_one = 0;
> +	int	tabular = 0;
> +
> +	optind = 1;
> +	while (1) {
> +		char	c = getopt(argc, argv, "bt");
> +		if (c < 0)
> +			break;
> +		switch (c) {
> +		case 'b':
> +			flags &= ~DF_HUMAN_UNIT;
> +			break;
> +		case 't':
> +			tabular = 1;
> +			break;
> +		default:
> +			usage(cmd_filesystem_disk_usage_usage);
> +		}
> +	}
> +
> +	if (check_argc_min(argc - optind, 1)) {
> +		usage(cmd_filesystem_disk_usage_usage);
> +		return 21;
> +	}
> +
> +	for (i = optind; i < argc ; i++) {
> +		int r, fd;
> +		DIR	*dirstream = NULL;
> +		if (more_than_one)
> +			printf("\n");
> +
> +		fd = open_file_or_dir(argv[i], &dirstream);
> +		if (fd < 0) {
> +			fprintf(stderr, "ERROR: can't access to '%s'\n",
> +				argv[1]);
> +			return 12;
> +		}
> +		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
> +		close_file_or_dir(fd, dirstream);
> +
> +		if (r)
> +			return r;
> +		more_than_one = 1;
> +
> +	}
> +
> +	return 0;
> +}
> diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
> index 9f68bb3..c7459b1 100644
> --- a/cmds-fi-disk_usage.h
> +++ b/cmds-fi-disk_usage.h
> @@ -22,4 +22,7 @@
>  extern const char * const cmd_filesystem_df_usage[];
>  int cmd_filesystem_df(int argc, char **argv);
>  
> +extern const char * const cmd_filesystem_disk_usage_usage[];
> +int cmd_filesystem_disk_usage(int argc, char **argv);
> +
>  #endif
> diff --git a/cmds-filesystem.c b/cmds-filesystem.c
> index fc85eef..d4cab63 100644
> --- a/cmds-filesystem.c
> +++ b/cmds-filesystem.c
> @@ -798,6 +798,9 @@ const struct cmd_group filesystem_cmd_group = {
>  		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
>  		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
>  		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
> +		{ "disk-usage", cmd_filesystem_disk_usage,
> +			cmd_filesystem_disk_usage_usage, NULL, 0 },
> +

Same here, I'd suggest "du" or "usage".
As currently in the patch it's not shorthand-friendly, you basically propose
that people wishing a shorter invocation use it as "btrfs fi di" or "btrfs fi
disk", which seems awkward and not intuitive.

-- 
With respect,
Roman

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 7/8] Add btrfs device disk-usage command
  2014-02-13 19:23   ` Roman Mamedov
@ 2014-02-13 19:44     ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:44 UTC (permalink / raw)
  To: Roman Mamedov; +Cc: linux-btrfs

Hi Roman,
On 02/13/2014 08:23 PM, Roman Mamedov wrote:
> On Thu, 13 Feb 2014 20:20:12 +0100
> Goffredo Baroncelli <kreijack@libero.it> wrote:
> 
>>
>> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
>> ---
[...]

> 
> Why not just name it "du"? Think about the current handy feature of shortening
> commands by only specifying parts of the keywords. "btrfs dev du" would seem
> more intuitive than calling it as "btrfs dev disk" or "btrfs dev disk-u".
> 
> Or simply "usage", because "...device disk..." is redundant, device is already
> a disk, so it can easily be "btrfs device usage".

Yes, I agree about "usage"
GB


-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 19:28   ` Roman Mamedov
@ 2014-02-13 19:49     ` Goffredo Baroncelli
  2014-02-13 20:22       ` Duncan
  2014-02-13 21:00       ` Roman Mamedov
  0 siblings, 2 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-13 19:49 UTC (permalink / raw)
  To: Roman Mamedov; +Cc: linux-btrfs

Hi Roman

On 02/13/2014 08:28 PM, Roman Mamedov wrote:
> On Thu, 13 Feb 2014 20:19:50 +0100
> Goffredo Baroncelli <kreijack@libero.it> wrote:
> 
[...]
>> diff --git a/cmds-filesystem.c b/cmds-filesystem.c
>> index fc85eef..d4cab63 100644
>> --- a/cmds-filesystem.c
>> +++ b/cmds-filesystem.c
>> @@ -798,6 +798,9 @@ const struct cmd_group filesystem_cmd_group = {
>>  		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
>>  		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
>>  		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
>> +		{ "disk-usage", cmd_filesystem_disk_usage,
>> +			cmd_filesystem_disk_usage_usage, NULL, 0 },
>> +
> 
> Same here, I'd suggest "du" or "usage".
> As currently in the patch it's not shorthand-friendly, you basically propose
> that people wishing a shorter invocation use it as "btrfs fi di" or "btrfs fi
> disk", which seems awkward and not intuitive.

Thanks for the comments, however I don't like du not usage; but you are right 
when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ? The short form would be 

	btrfs fi chunk

which is coherent with the data displayed

Regards
Goffredo

P.S.
Please the next time, cut the email lines which are not relevant to your
replay


-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 19:49     ` Goffredo Baroncelli
@ 2014-02-13 20:22       ` Duncan
  2014-02-13 21:00       ` Roman Mamedov
  1 sibling, 0 replies; 34+ messages in thread
From: Duncan @ 2014-02-13 20:22 UTC (permalink / raw)
  To: linux-btrfs

Goffredo Baroncelli posted on Thu, 13 Feb 2014 20:49:08 +0100 as
excerpted:

> Thanks for the comments, however I don't like du not usage; but you are
> right when you don't like "disk-usage". What about "btrfs filesystem
> chunk-usage" ? The short form would be
> 
> 	btrfs fi chunk
> 
> which is coherent with the data displayed

That makes much more sense from a different perspective as well.  "Disk" 
sounds so 20th-century spinning rust..., and at least to me, "du" isn't 
as intuitive or commonly used as "df", so while "df" seems natural to me, 
while I understand where "du" comes from, it still makes me go "huh?" as 
I wouldn't expect to see it in the btrfs context.

So btrfs filesystem chunk(-usage), please. =:^)

-- 
Duncan - List replies preferred.   No HTML msgs.
"Every nonfree program has a lord, a master --
and if you use the program, he is your master."  Richard Stallman


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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 19:49     ` Goffredo Baroncelli
  2014-02-13 20:22       ` Duncan
@ 2014-02-13 21:00       ` Roman Mamedov
  2014-02-14 17:57         ` Goffredo Baroncelli
  1 sibling, 1 reply; 34+ messages in thread
From: Roman Mamedov @ 2014-02-13 21:00 UTC (permalink / raw)
  To: kreijack; +Cc: kreijack, linux-btrfs

[-- Attachment #1: Type: text/plain, Size: 511 bytes --]

On Thu, 13 Feb 2014 20:49:08 +0100
Goffredo Baroncelli <kreijack@libero.it> wrote:

> Thanks for the comments, however I don't like du not usage; but you are right 
> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?

Personally I don't see the point of being super-pedantic here, i.e. "look this
is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
of having a matching "dev usage" and "fi usage" would have been nicer.

-- 
With respect,
Roman

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-13 21:00       ` Roman Mamedov
@ 2014-02-14 17:57         ` Goffredo Baroncelli
  2014-02-14 18:11           ` Roman Mamedov
  0 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-14 17:57 UTC (permalink / raw)
  To: Roman Mamedov, kreijack; +Cc: linux-btrfs

On 02/13/2014 10:00 PM, Roman Mamedov wrote:
> On Thu, 13 Feb 2014 20:49:08 +0100
> Goffredo Baroncelli <kreijack@libero.it> wrote:
> 
>> Thanks for the comments, however I don't like du not usage; but you are right 
>> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
> 
> Personally I don't see the point of being super-pedantic here, i.e. "look this
> is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
> of having a matching "dev usage" and "fi usage" would have been nicer.


What about "btrfs filesystem chunk-usage" ? 

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-14 17:57         ` Goffredo Baroncelli
@ 2014-02-14 18:11           ` Roman Mamedov
  2014-02-14 18:27             ` Goffredo Baroncelli
  0 siblings, 1 reply; 34+ messages in thread
From: Roman Mamedov @ 2014-02-14 18:11 UTC (permalink / raw)
  To: kreijack; +Cc: kreijack, linux-btrfs

[-- Attachment #1: Type: text/plain, Size: 1095 bytes --]

On Fri, 14 Feb 2014 18:57:03 +0100
Goffredo Baroncelli <kreijack@libero.it> wrote:

> On 02/13/2014 10:00 PM, Roman Mamedov wrote:
> > On Thu, 13 Feb 2014 20:49:08 +0100
> > Goffredo Baroncelli <kreijack@libero.it> wrote:
> > 
> >> Thanks for the comments, however I don't like du not usage; but you are right 
> >> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
> > 
> > Personally I don't see the point of being super-pedantic here, i.e. "look this
> > is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
> > of having a matching "dev usage" and "fi usage" would have been nicer.
> 
> 
> What about "btrfs filesystem chunk-usage" ? 

Uhm? Had to reread this several times, but it looks like you're repeating
exactly the same question that I was already answering in the quoted part.

To clarify even more, personally I'd like if there would have been "btrfs dev
usage" and "btrfs fi usage". Do not see the need to specifically make the 2nd
one "chunk-usage" instead of simply "usage".

-- 
With respect,
Roman

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-14 18:11           ` Roman Mamedov
@ 2014-02-14 18:27             ` Goffredo Baroncelli
  2014-02-14 18:34               ` Hugo Mills
  0 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-14 18:27 UTC (permalink / raw)
  To: Roman Mamedov; +Cc: linux-btrfs

On 02/14/2014 07:11 PM, Roman Mamedov wrote:
> On Fri, 14 Feb 2014 18:57:03 +0100
> Goffredo Baroncelli <kreijack@libero.it> wrote:
> 
>> On 02/13/2014 10:00 PM, Roman Mamedov wrote:
>>> On Thu, 13 Feb 2014 20:49:08 +0100
>>> Goffredo Baroncelli <kreijack@libero.it> wrote:
>>>
>>>> Thanks for the comments, however I don't like du not usage; but you are right 
>>>> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
>>>
>>> Personally I don't see the point of being super-pedantic here, i.e. "look this
>>> is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
>>> of having a matching "dev usage" and "fi usage" would have been nicer.
>>
>>
>> What about "btrfs filesystem chunk-usage" ? 
> 
> Uhm? Had to reread this several times, but it looks like you're repeating
> exactly the same question that I was already answering in the quoted part.
> 
> To clarify even more, personally I'd like if there would have been "btrfs dev
> usage" and "btrfs fi usage". Do not see the need to specifically make the 2nd
> one "chunk-usage" instead of simply "usage".

I don't like "usage" because it to me seems to be too much generic.
Because both "btrfs filesystem disk-usage" and "btrfs device disk-usage"
report about chunk (and/or block group) infos, I am investigating 
about 
- btrfs filesystem chunk-usage
- btrfs device chunk-usage

Regards
GB


-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-14 18:27             ` Goffredo Baroncelli
@ 2014-02-14 18:34               ` Hugo Mills
  2014-02-15 22:23                 ` Chris Murphy
  0 siblings, 1 reply; 34+ messages in thread
From: Hugo Mills @ 2014-02-14 18:34 UTC (permalink / raw)
  To: kreijack; +Cc: Roman Mamedov, linux-btrfs

[-- Attachment #1: Type: text/plain, Size: 1878 bytes --]

On Fri, Feb 14, 2014 at 07:27:57PM +0100, Goffredo Baroncelli wrote:
> On 02/14/2014 07:11 PM, Roman Mamedov wrote:
> > On Fri, 14 Feb 2014 18:57:03 +0100
> > Goffredo Baroncelli <kreijack@libero.it> wrote:
> > 
> >> On 02/13/2014 10:00 PM, Roman Mamedov wrote:
> >>> On Thu, 13 Feb 2014 20:49:08 +0100
> >>> Goffredo Baroncelli <kreijack@libero.it> wrote:
> >>>
> >>>> Thanks for the comments, however I don't like du not usage; but you are right 
> >>>> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
> >>>
> >>> Personally I don't see the point of being super-pedantic here, i.e. "look this
> >>> is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
> >>> of having a matching "dev usage" and "fi usage" would have been nicer.
> >>
> >>
> >> What about "btrfs filesystem chunk-usage" ? 
> > 
> > Uhm? Had to reread this several times, but it looks like you're repeating
> > exactly the same question that I was already answering in the quoted part.
> > 
> > To clarify even more, personally I'd like if there would have been "btrfs dev
> > usage" and "btrfs fi usage". Do not see the need to specifically make the 2nd
> > one "chunk-usage" instead of simply "usage".
> 
> I don't like "usage" because it to me seems to be too much generic.
> Because both "btrfs filesystem disk-usage" and "btrfs device disk-usage"
> report about chunk (and/or block group) infos, I am investigating 
> about 
> - btrfs filesystem chunk-usage
> - btrfs device chunk-usage

   Most people aren't going to know (or care) what a chunk is. I'm
much happier with Roman's suggestion of btrfs {fi,dev} usage.

   Hugo.

-- 
=== Hugo Mills: hugo@... carfax.org.uk | darksatanic.net | lug.org.uk ===
  PGP key: 65E74AC0 from wwwkeys.eu.pgp.net or http://www.carfax.org.uk
               --- Nostalgia isn't what it used to be. ---               

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 811 bytes --]

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-14 18:34               ` Hugo Mills
@ 2014-02-15 22:23                 ` Chris Murphy
  2014-02-17 18:09                   ` Goffredo Baroncelli
  0 siblings, 1 reply; 34+ messages in thread
From: Chris Murphy @ 2014-02-15 22:23 UTC (permalink / raw)
  To: Hugo Mills; +Cc: kreijack, Roman Mamedov, linux-btrfs


On Feb 14, 2014, at 11:34 AM, Hugo Mills <hugo@carfax.org.uk> wrote:

> On Fri, Feb 14, 2014 at 07:27:57PM +0100, Goffredo Baroncelli wrote:
>> On 02/14/2014 07:11 PM, Roman Mamedov wrote:
>>> On Fri, 14 Feb 2014 18:57:03 +0100
>>> Goffredo Baroncelli <kreijack@libero.it> wrote:
>>> 
>>>> On 02/13/2014 10:00 PM, Roman Mamedov wrote:
>>>>> On Thu, 13 Feb 2014 20:49:08 +0100
>>>>> Goffredo Baroncelli <kreijack@libero.it> wrote:
>>>>> 
>>>>>> Thanks for the comments, however I don't like du not usage; but you are right 
>>>>>> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
>>>>> 
>>>>> Personally I don't see the point of being super-pedantic here, i.e. "look this
>>>>> is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
>>>>> of having a matching "dev usage" and "fi usage" would have been nicer.
>>>> 
>>>> 
>>>> What about "btrfs filesystem chunk-usage" ? 
>>> 
>>> Uhm? Had to reread this several times, but it looks like you're repeating
>>> exactly the same question that I was already answering in the quoted part.
>>> 
>>> To clarify even more, personally I'd like if there would have been "btrfs dev
>>> usage" and "btrfs fi usage". Do not see the need to specifically make the 2nd
>>> one "chunk-usage" instead of simply "usage".
>> 
>> I don't like "usage" because it to me seems to be too much generic.
>> Because both "btrfs filesystem disk-usage" and "btrfs device disk-usage"
>> report about chunk (and/or block group) infos, I am investigating 
>> about 
>> - btrfs filesystem chunk-usage
>> - btrfs device chunk-usage
> 
>   Most people aren't going to know (or care) what a chunk is. I'm
> much happier with Roman's suggestion of btrfs {fi,dev} usage.

Or btrfs filesystem examine, or btrfs filesystem detail, which are semi-consistent with mdadm for obtaining similar data.


Chris Murphy

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-15 22:23                 ` Chris Murphy
@ 2014-02-17 18:09                   ` Goffredo Baroncelli
  2014-02-20 17:31                     ` David Sterba
  0 siblings, 1 reply; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-17 18:09 UTC (permalink / raw)
  To: Chris Murphy, Hugo Mills; +Cc: Roman Mamedov, linux-btrfs

On 02/15/2014 11:23 PM, Chris Murphy wrote:
> 
> On Feb 14, 2014, at 11:34 AM, Hugo Mills <hugo@carfax.org.uk> wrote:
> 
>> On Fri, Feb 14, 2014 at 07:27:57PM +0100, Goffredo Baroncelli wrote:
>>> On 02/14/2014 07:11 PM, Roman Mamedov wrote:
>>>> On Fri, 14 Feb 2014 18:57:03 +0100
>>>> Goffredo Baroncelli <kreijack@libero.it> wrote:
>>>>
>>>>> On 02/13/2014 10:00 PM, Roman Mamedov wrote:
>>>>>> On Thu, 13 Feb 2014 20:49:08 +0100
>>>>>> Goffredo Baroncelli <kreijack@libero.it> wrote:
>>>>>>
>>>>>>> Thanks for the comments, however I don't like du not usage; but you are right 
>>>>>>> when you don't like "disk-usage". What about "btrfs filesystem chunk-usage" ?
>>>>>>
>>>>>> Personally I don't see the point of being super-pedantic here, i.e. "look this
>>>>>> is not just filesystem usage, this is filesystem CHUNK usage"... Consistency
>>>>>> of having a matching "dev usage" and "fi usage" would have been nicer.
>>>>>
>>>>>
>>>>> What about "btrfs filesystem chunk-usage" ? 
>>>>
>>>> Uhm? Had to reread this several times, but it looks like you're repeating
>>>> exactly the same question that I was already answering in the quoted part.
>>>>
>>>> To clarify even more, personally I'd like if there would have been "btrfs dev
>>>> usage" and "btrfs fi usage". Do not see the need to specifically make the 2nd
>>>> one "chunk-usage" instead of simply "usage".
>>>
>>> I don't like "usage" because it to me seems to be too much generic.
>>> Because both "btrfs filesystem disk-usage" and "btrfs device disk-usage"
>>> report about chunk (and/or block group) infos, I am investigating 
>>> about 
>>> - btrfs filesystem chunk-usage
>>> - btrfs device chunk-usage
>>
>>   Most people aren't going to know (or care) what a chunk is. I'm
>> much happier with Roman's suggestion of btrfs {fi,dev} usage.
> 
> Or btrfs filesystem examine, or btrfs filesystem detail, which are
> semi-consistent with mdadm for obtaining similar data.
> 

I have to agree with Chris: looking at the output of "btrfs fi disk-usage"

$ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/
         Data   Data    Metadata Metadata System System             
         Single RAID6   Single   RAID5    Single RAID5   Unallocated
                                                                    
/dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB     97.98GB
/dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
/dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
/dev/vde      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
         ====== ======= ======== ======== ====== ======= ===========
Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB 12.00MB    391.97GB
Used       0.00 11.25MB     0.00  36.00KB   0.00  4.00KB   

it is hard to tell that this can be named "filesystem usage". I think that 
"details" or "examine" is a better name.

Regarding "btrfs device usage", it seems to me more coherent. But as 
reported before consistency also matters, so now I am inclined to use
"detail" (or examine) also for "btrfs device"

> 
> Chris Murphy
> 
Regards
Goffredo

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (7 preceding siblings ...)
  2014-02-13 19:20 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
@ 2014-02-17 18:41 ` David Sterba
  2014-02-17 20:49   ` Goffredo Baroncelli
  2014-02-20 18:08 ` David Sterba
  9 siblings, 1 reply; 34+ messages in thread
From: David Sterba @ 2014-02-17 18:41 UTC (permalink / raw)
  To: kreijack; +Cc: linux-btrfs, Josef Bacik, Hugo Mills, Kostia Khlebopros

On Thu, Feb 13, 2014 at 08:18:10PM +0100, Goffredo Baroncelli wrote:
> This is the 4th attempt of my patches related to show how the data
> are stored in a btrfs filesystem. I rebased all the patches on the v3.13
> btrfs-progs. 

FYI, I've added this series as-is into the -next part of the integration
branch so we have something to test, let the review and comments phase
continue.

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-17 18:41 ` [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df David Sterba
@ 2014-02-17 20:49   ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-17 20:49 UTC (permalink / raw)
  To: dsterba, linux-btrfs, Josef Bacik, Hugo Mills, Kostia Khlebopros

On 02/17/2014 07:41 PM, David Sterba wrote:
> series as-is into the -next part of the integration
> branch so we have something to test, let the review and comments phase
> continue.
Hi David,

many thanks

BR
G.Baroncelli

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
  2014-02-17 18:09                   ` Goffredo Baroncelli
@ 2014-02-20 17:31                     ` David Sterba
  0 siblings, 0 replies; 34+ messages in thread
From: David Sterba @ 2014-02-20 17:31 UTC (permalink / raw)
  To: Goffredo Baroncelli; +Cc: Chris Murphy, Hugo Mills, Roman Mamedov, linux-btrfs

On Mon, Feb 17, 2014 at 07:09:55PM +0100, Goffredo Baroncelli wrote:
> I have to agree with Chris: looking at the output of "btrfs fi disk-usage"
> 
> $ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/
>          Data   Data    Metadata Metadata System System             
>          Single RAID6   Single   RAID5    Single RAID5   Unallocated
>                                                                     
> /dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB     97.98GB
> /dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
> /dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
> /dev/vde      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
>          ====== ======= ======== ======== ====== ======= ===========
> Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB 12.00MB    391.97GB
> Used       0.00 11.25MB     0.00  36.00KB   0.00  4.00KB   
> 
> it is hard to tell that this can be named "filesystem usage". I think that 
> "details" or "examine" is a better name.
> 
> Regarding "btrfs device usage", it seems to me more coherent. But as 
> reported before consistency also matters, so now I am inclined to use
> "detail" (or examine) also for "btrfs device"

I'm for 'btrfs filesystem usage' and 'btrfs device usage', IMHO
intuitive, easy to type and remember.

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
                   ` (8 preceding siblings ...)
  2014-02-17 18:41 ` [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df David Sterba
@ 2014-02-20 18:08 ` David Sterba
  2014-02-20 18:32   ` Josef Bacik
  2014-02-20 19:18   ` Goffredo Baroncelli
  9 siblings, 2 replies; 34+ messages in thread
From: David Sterba @ 2014-02-20 18:08 UTC (permalink / raw)
  To: kreijack; +Cc: linux-btrfs, Josef Bacik, Hugo Mills, Kostia Khlebopros

On Thu, Feb 13, 2014 at 08:18:10PM +0100, Goffredo Baroncelli wrote:
> space (if the next chunk are allocated as SINGLE) or the minimum one (
> if the next chunks are allocated as DUP/RAID1/RAID10).
> 
> The other two commands show the chunks in the disks.
> 
> $ sudo btrfs filesystem disk-usage /mnt/btrfs1/
> Data,Single: Size:8.00MB, Used:0.00
>    /dev/vdb	    8.00MB

The information about per-device usage can be enhanced and there's
enough space to print that:

* allocated in chunks (the number above)
* actually used (simiar to what 'btrfs fi show' prints as 'used')

I don't see a reason why it would not fit here, nor any other place
where this can be obtained.

There is the cumulative number of 'Used' for all devices, but I'd like
to see it per-device as well.

> or in tabular format
> 
> $ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/
>          Data   Data    Metadata Metadata System System             
>          Single RAID6   Single   RAID5    Single RAID5   Unallocated
>                                                                     
> /dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB     97.98GB
> /dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
> /dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
> /dev/vde      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
>          ====== ======= ======== ======== ====== ======= ===========
> Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB 12.00MB    391.97GB
> Used       0.00 11.25MB     0.00  36.00KB   0.00  4.00KB            
> 
> These are the most complete output, where it is possible to know which
> disk a chunk uses and the usage of every chunk.

Though not per-device, similar to the above, but the tabular output is
limited compared to the sequential output. Not sure what to do here.

> Finally the last command shows which chunks a disk hosts:
> 
> $ sudo ./btrfs device disk-usage /mnt/btrfs1/
> /dev/vdb	  100.00GB
>    Data,Single:              8.00MB
>    Data,RAID6:               1.00GB
>    Metadata,Single:          8.00MB
>    Metadata,RAID5:           1.00GB
>    System,Single:            4.00MB
>    System,RAID5:             4.00MB
>    Unallocated:             97.98GB
> 
> /dev/vdc	  100.00GB
>    Data,RAID6:               1.00GB
>    Metadata,RAID5:           1.00GB
>    System,RAID5:             4.00MB
>    Unallocated:             98.00GB
> 
> /dev/vdd	  100.00GB
>    Data,RAID6:               1.00GB
>    Metadata,RAID5:           1.00GB
>    System,RAID5:             4.00MB
>    Unallocated:             98.00GB
> 
> /dev/vde	  100.00GB
>    Data,RAID6:               1.00GB
>    Metadata,RAID5:           1.00GB
>    System,RAID5:             4.00MB
>    Unallocated:             98.00GB

> More or less are the same information above, only grouped by disk.

Ie. it's only a variant of the 'filesystem usage' where it is grouped by
blockgroup type.

Why doesn't 'btrfs device usage' take a device instead of the whole
filesystem? This seems counterintuitive. It should be possible to
ask for a device by it or path.

Also, I'd like to see all useful information about the device:

* id, path, uuid, ... whatever
* physical device size
* size visible by the filesystem
* space allocated in chunks
* space actually used

> Unfortunately I don't have any information about the chunk usage per disk basis.

And I'm missing it. Is it a fundamental problem or just not addressed in
this patchset?

> Finally I have to point out that the command btrfs fi df previous didn't require 
> the root capability, now with my patches it is required, because I need 
> to know some info about the chunks so I need to use the 
> "BTRFS_IOC_TREE_SEARCH".
> 
> I think that there are the following possibilities:
> 1) accept this regresssion
> 2) remove the command "btrfs fi df" and leave only "btrfs fi disk-usage" and
>    "btrfs dev disk-usage"
> 3) adding a new ioctl which could be used without root capability. Of course
>    this ioctl would return only a subset of the BTRFS_IOC_TREE_SEARCH info
> 
> I think that the 3) would be the "long term" solution. I am not happy about
> the 1), so as "short term solution" I think that we should go with the 2).
> What do you think ?

No sorry, 1) is not acceptable. We can live with this limitation only
during development so we're not blocked by some new ioctl development.

No for 2), 'fi df' is useful as and widely used in existing scripts.

Yes for 3), we may also export the information through the existing
ioctls if possible (eg. IOC_FS_INFO).

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

* Re: [PATCH 4/8] Allow use of get_device_info()
  2014-02-13 19:19 ` [PATCH 4/8] Allow use of get_device_info() Goffredo Baroncelli
@ 2014-02-20 18:13   ` David Sterba
  0 siblings, 0 replies; 34+ messages in thread
From: David Sterba @ 2014-02-20 18:13 UTC (permalink / raw)
  To: kreijack; +Cc: linux-btrfs

On Thu, Feb 13, 2014 at 08:19:44PM +0100, Goffredo Baroncelli wrote:
> 
> Allow the use of get_device_info()  for different units.

FYI, I'll move this patch to integration base, it's a simple and
isolated change.

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-20 18:08 ` David Sterba
@ 2014-02-20 18:32   ` Josef Bacik
  2014-02-20 19:20     ` Goffredo Baroncelli
  2014-02-22  0:03     ` David Sterba
  2014-02-20 19:18   ` Goffredo Baroncelli
  1 sibling, 2 replies; 34+ messages in thread
From: Josef Bacik @ 2014-02-20 18:32 UTC (permalink / raw)
  To: dsterba, kreijack, linux-btrfs, Hugo Mills, Kostia Khlebopros

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/20/2014 01:08 PM, David Sterba wrote:
> On Thu, Feb 13, 2014 at 08:18:10PM +0100, Goffredo Baroncelli
> wrote:
>> space (if the next chunk are allocated as SINGLE) or the minimum
>> one ( if the next chunks are allocated as DUP/RAID1/RAID10).
>> 
>> The other two commands show the chunks in the disks.
>> 
>> $ sudo btrfs filesystem disk-usage /mnt/btrfs1/ Data,Single:
>> Size:8.00MB, Used:0.00 /dev/vdb	    8.00MB
> 
> The information about per-device usage can be enhanced and there's 
> enough space to print that:
> 
> * allocated in chunks (the number above) * actually used (simiar to
> what 'btrfs fi show' prints as 'used')
> 
> I don't see a reason why it would not fit here, nor any other
> place where this can be obtained.
> 
> There is the cumulative number of 'Used' for all devices, but I'd
> like to see it per-device as well.
> 
>> or in tabular format
>> 
>> $ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/ Data   Data
>> Metadata Metadata System System Single RAID6   Single   RAID5
>> Single RAID5   Unallocated
>> 
>> /dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB
>> 97.98GB /dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB
>> 98.00GB /dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB
>> 98.00GB /dev/vde      -  1.00GB        -   1.00GB      -  4.00MB
>> 98.00GB ====== ======= ======== ======== ====== =======
>> =========== Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB
>> 12.00MB    391.97GB Used       0.00 11.25MB     0.00  36.00KB
>> 0.00  4.00KB
>> 
>> These are the most complete output, where it is possible to know
>> which disk a chunk uses and the usage of every chunk.
> 
> Though not per-device, similar to the above, but the tabular output
> is limited compared to the sequential output. Not sure what to do
> here.
> 
>> Finally the last command shows which chunks a disk hosts:
>> 
>> $ sudo ./btrfs device disk-usage /mnt/btrfs1/ /dev/vdb
>> 100.00GB Data,Single:              8.00MB Data,RAID6:
>> 1.00GB Metadata,Single:          8.00MB Metadata,RAID5:
>> 1.00GB System,Single:            4.00MB System,RAID5:
>> 4.00MB Unallocated:             97.98GB
>> 
>> /dev/vdc	  100.00GB Data,RAID6:               1.00GB 
>> Metadata,RAID5:           1.00GB System,RAID5:
>> 4.00MB Unallocated:             98.00GB
>> 
>> /dev/vdd	  100.00GB Data,RAID6:               1.00GB 
>> Metadata,RAID5:           1.00GB System,RAID5:
>> 4.00MB Unallocated:             98.00GB
>> 
>> /dev/vde	  100.00GB Data,RAID6:               1.00GB 
>> Metadata,RAID5:           1.00GB System,RAID5:
>> 4.00MB Unallocated:             98.00GB
> 
>> More or less are the same information above, only grouped by
>> disk.
> 
> Ie. it's only a variant of the 'filesystem usage' where it is
> grouped by blockgroup type.
> 
> Why doesn't 'btrfs device usage' take a device instead of the
> whole filesystem? This seems counterintuitive. It should be
> possible to ask for a device by it or path.
> 
> Also, I'd like to see all useful information about the device:
> 
> * id, path, uuid, ... whatever * physical device size * size
> visible by the filesystem * space allocated in chunks * space
> actually used
> 
>> Unfortunately I don't have any information about the chunk usage
>> per disk basis.
> 
> And I'm missing it. Is it a fundamental problem or just not
> addressed in this patchset?
> 
>> Finally I have to point out that the command btrfs fi df previous
>> didn't require the root capability, now with my patches it is
>> required, because I need to know some info about the chunks so I
>> need to use the "BTRFS_IOC_TREE_SEARCH".
>> 
>> I think that there are the following possibilities: 1) accept
>> this regresssion 2) remove the command "btrfs fi df" and leave
>> only "btrfs fi disk-usage" and "btrfs dev disk-usage" 3) adding a
>> new ioctl which could be used without root capability. Of course 
>> this ioctl would return only a subset of the
>> BTRFS_IOC_TREE_SEARCH info
>> 
>> I think that the 3) would be the "long term" solution. I am not
>> happy about the 1), so as "short term solution" I think that we
>> should go with the 2). What do you think ?
> 
> No sorry, 1) is not acceptable. We can live with this limitation
> only during development so we're not blocked by some new ioctl
> development.
> 
> No for 2), 'fi df' is useful as and widely used in existing
> scripts.
> 
> Yes for 3), we may also export the information through the
> existing ioctls if possible (eg. IOC_FS_INFO).
> 

For _right now_ I'd say just not do the raid56 stuff if we don't
notice any raid56 chunks from the normal load_space_info, and then if
there are raid56 we try and run the tree search ioctl and notice if we
get back EPERM or whatever you get when you don't have permissions.
Then just spit out as much information that you can about the fs with
a little note at the bottom that available calculation isn't 100% and
you need to run as root if you want that info.

Then what we could do is add another flag type for the existing
SPACE_INFO ioctl to spit out the information you need about the
raid5/6 chunks and then just test for those flags and make the
adjustment necessary.  This way we avoid adding yet another ioctl and
stuff will still work nicely for old kernels that don't have the
updated ioctl.  Thanks,

Josef
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJTBko8AAoJEANb+wAKly3B8bgP+wU2yWBhtUWE9gFycBeW0gk7
gKexgV/8OV93FQbhQcPburhkzGixS1XMLbVYnJsYfwfRLKZl4l+M2mOJHyDu93M3
HGfSSuKoTJ8cQ8Fa2qdFIbZNFWSBeHpkOSmOl0NxyFLq/uXLaDP+ANRSE94K54d2
jdT9ncKdQcgiqRRaEIwgUkOUKdqRdRytm3BDr2otuvatWeKRtSVsSE7hG9uyxCBP
CxwE8SM7I4OByEqfrm7MJ2beQiOJoYIAKfVRjC1h+rUMd6IhjkfQGL1CBBrkB732
JWsOupRPPZkGQLMpD1Cbxy7BebzagKwC7oTubaWr8NnTFTbRX1+URJJFkPSEKmNy
9iYK4P17/w30GIfHJ5G4oEr2dl+41iCCaOJM0G57/yTMn0ostfRtdv3gSXHDHGYr
o39sDymTIX+H8w5Jd+ItTFKiP2B8NE9o6k9ZvLCF5gS38SdisyOiMwUu85jiAjHA
7YcGP2+Z2s1OlYJLpNrASt/JoXMtzGnXr7IinuLxjyA9RbnQk6K0Vzoen8eF+mtU
Ge/2D5zDdILrdlPwf/gaffNglstH2MgkiY9uTeAxlN90i9zW2BylJW+WR3o3aDq+
ajZfIoerQkk16EUvXxOap+vbkBpOfaEkzfWOOj7JU8CdkMF4L2g0FUUSan9vDc5v
meYQ/s2qy0eKDeRTcj3m
=tF0W
-----END PGP SIGNATURE-----

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-20 18:08 ` David Sterba
  2014-02-20 18:32   ` Josef Bacik
@ 2014-02-20 19:18   ` Goffredo Baroncelli
  1 sibling, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-20 19:18 UTC (permalink / raw)
  To: dsterba, linux-btrfs, Josef Bacik, Hugo Mills, Kostia Khlebopros

Hi David,

below my comments

On 02/20/2014 07:08 PM, David Sterba wrote:
> On Thu, Feb 13, 2014 at 08:18:10PM +0100, Goffredo Baroncelli wrote:
>> space (if the next chunk are allocated as SINGLE) or the minimum one (
>> if the next chunks are allocated as DUP/RAID1/RAID10).
>>
>> The other two commands show the chunks in the disks.
>>
>> $ sudo btrfs filesystem disk-usage /mnt/btrfs1/
>> Data,Single: Size:8.00MB, Used:0.00
>>    /dev/vdb	    8.00MB
> 
> The information about per-device usage can be enhanced and there's
> enough space to print that:
> 
> * allocated in chunks (the number above)
This is the value already written.


> * actually used (simiar to what 'btrfs fi show' prints as 'used')

The "used" is a value returned by the ioctl BTRFS_IOC_SPACE_INFO,
which returns this value per group-block basis. See below.


> 
> I don't see a reason why it would not fit here, nor any other place
> where this can be obtained.
> 
> There is the cumulative number of 'Used' for all devices, but I'd like
> to see it per-device as well.
> 
>> or in tabular format
>>
>> $ sudo ./btrfs filesystem disk-usage -t /mnt/btrfs1/
>>          Data   Data    Metadata Metadata System System             
>>          Single RAID6   Single   RAID5    Single RAID5   Unallocated
>>                                                                     
>> /dev/vdb 8.00MB  1.00GB   8.00MB   1.00GB 4.00MB  4.00MB     97.98GB
>> /dev/vdc      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
>> /dev/vdd      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
>> /dev/vde      -  1.00GB        -   1.00GB      -  4.00MB     98.00GB
>>          ====== ======= ======== ======== ====== ======= ===========
>> Total    8.00MB  2.00GB   8.00MB   3.00GB 4.00MB 12.00MB    391.97GB
>> Used       0.00 11.25MB     0.00  36.00KB   0.00  4.00KB            
>>
>> These are the most complete output, where it is possible to know which
>> disk a chunk uses and the usage of every chunk.
> 
> Though not per-device, similar to the above, but the tabular output is
> limited compared to the sequential output. Not sure what to do here.

The tabular is to have a "friendly" summary of how the filesystem is span 
on the different disks. I suggest to not add more info in the tabular

> 
>> Finally the last command shows which chunks a disk hosts:
>>
>> $ sudo ./btrfs device disk-usage /mnt/btrfs1/
>> /dev/vdb	  100.00GB
>>    Data,Single:              8.00MB
>>    Data,RAID6:               1.00GB
>>    Metadata,Single:          8.00MB
>>    Metadata,RAID5:           1.00GB
>>    System,Single:            4.00MB
>>    System,RAID5:             4.00MB
>>    Unallocated:             97.98GB
>>
>> /dev/vdc	  100.00GB
>>    Data,RAID6:               1.00GB
>>    Metadata,RAID5:           1.00GB
>>    System,RAID5:             4.00MB
>>    Unallocated:             98.00GB
>>
>> /dev/vdd	  100.00GB
>>    Data,RAID6:               1.00GB
>>    Metadata,RAID5:           1.00GB
>>    System,RAID5:             4.00MB
>>    Unallocated:             98.00GB
>>
>> /dev/vde	  100.00GB
>>    Data,RAID6:               1.00GB
>>    Metadata,RAID5:           1.00GB
>>    System,RAID5:             4.00MB
>>    Unallocated:             98.00GB
> 
>> More or less are the same information above, only grouped by disk.
> 
> Ie. it's only a variant of the 'filesystem usage' where it is grouped by
> blockgroup type.
> 
> Why doesn't 'btrfs device usage' take a device instead of the whole
> filesystem? This seems counterintuitive. It should be possible to
> ask for a device by it or path.

If a device is passed, what you would expect as output: the list of all the devices involved,or only the one(s) passed ? In other terms, the device passed has to act 
also as filter, or it is only a different way to indicate the path ?

> 
> Also, I'd like to see all useful information about the device:
> 
> * id, path, uuid, ... whatever
ok, we can add a "-v" switch to add these further information

> * physical device size
ok, it is already written

> * size visible by the filesystem
Could you be more explicit ? a) For each chunk (in each disk) or b) for each disk ? And how
this information per disk basis would be useful ?

Example (supposing 4 disks)
a)
/dev/vde	  100.00GB
    Data,RAID6:               Disk size:  1.00GB, FS size: 512.00MB
    Metadata,RAID5:           Disk size:  1.00GB, FS size: 750.00MB
    System,RAID5:             Disk size:  4.00MB, FS size;   3.00MB
    Unallocated:              Disk size: 98.00GB

b)
/dev/vde	  Disk size: 100.00GB, FS size: 1.28GB
    Data,RAID6:               1.00GB
    Metadata,RAID5:           1.00GB
    System,RAID5:             4.00MB
    Unallocated:             98.00GB



> * space allocated in chunks
ok, it is already written

> * space actually used
See my other comments


I am not against to add further information to btrfs dev [disk-]usage, but I liked 
the idea to add the minimum information to avoid ambiguities:
- the number on the left of the device is the device size 
- the number on the left of the block group is the space allocated on the disk
All the number are in terms of disk space.

> 
>> Unfortunately I don't have any information about the chunk usage per disk basis.
> 
> And I'm missing it. Is it a fundamental problem or just not addressed in
> this patchset?

As above, the "used" is a value returned by the ioctl BTRFS_IOC_SPACE_INFO,
which returns this value per group-block basis. I don't know how
calculates this values per device basis. If you give me some hints on 
how we can get these information, I can improve
the output.


> 
>> Finally I have to point out that the command btrfs fi df previous didn't require 
>> the root capability, now with my patches it is required, because I need 
>> to know some info about the chunks so I need to use the 
>> "BTRFS_IOC_TREE_SEARCH".
>>
>> I think that there are the following possibilities:
>> 1) accept this regresssion
>> 2) remove the command "btrfs fi df" and leave only "btrfs fi disk-usage" and
>>    "btrfs dev disk-usage"
>> 3) adding a new ioctl which could be used without root capability. Of course
>>    this ioctl would return only a subset of the BTRFS_IOC_TREE_SEARCH info
>>
>> I think that the 3) would be the "long term" solution. I am not happy about
>> the 1), so as "short term solution" I think that we should go with the 2).
>> What do you think ?
> 
> No sorry, 1) is not acceptable. We can live with this limitation only
> during development so we're not blocked by some new ioctl development.
> 
> No for 2), 'fi df' is useful as and widely used in existing scripts.

Of course I meant "from my patchset". I would leave the actual "fi df" implementation.
Anyway if you are talking about "existing scripts", this means that we cannot
touch the actual btrfs fi df at all, but we have to add a another 
command (btrfs fi free ?)

> 
> Yes for 3), we may also export the information through the existing
> ioctls if possible (eg. IOC_FS_INFO).

Of course this would be the best. But what if we do "btrfs fi df" in 
an old kernel ? It is acceptable to fall-back to the old output ?



> 


-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-20 18:32   ` Josef Bacik
@ 2014-02-20 19:20     ` Goffredo Baroncelli
  2014-02-22  0:03     ` David Sterba
  1 sibling, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2014-02-20 19:20 UTC (permalink / raw)
  To: Josef Bacik, dsterba, linux-btrfs, Hugo Mills, Kostia Khlebopros

Hi Josef,

On 02/20/2014 07:32 PM, Josef Bacik wrote:
>> > Yes for 3), we may also export the information through the
>> > existing ioctls if possible (eg. IOC_FS_INFO).
>> > 
> For _right now_ I'd say just not do the raid56 stuff if we don't
> notice any raid56 chunks from the normal load_space_info, and then if
> there are raid56 we try and run the tree search ioctl and notice if we
> get back EPERM or whatever you get when you don't have permissions.
> Then just spit out as much information that you can about the fs with
> a little note at the bottom that available calculation isn't 100% and
> you need to run as root if you want that info.
> 
> Then what we could do is add another flag type for the existing
> SPACE_INFO ioctl to spit out the information you need about the
> raid5/6 chunks and then just test for those flags and make the
> adjustment necessary.  This way we avoid adding yet another ioctl and
> stuff will still work nicely for old kernels that don't have the
> updated ioctl.  Thanks,
> 
> Josef

Good suggestion ! I will take it

-- 
gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

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

* Re: [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df
  2014-02-20 18:32   ` Josef Bacik
  2014-02-20 19:20     ` Goffredo Baroncelli
@ 2014-02-22  0:03     ` David Sterba
  1 sibling, 0 replies; 34+ messages in thread
From: David Sterba @ 2014-02-22  0:03 UTC (permalink / raw)
  To: Josef Bacik; +Cc: kreijack, linux-btrfs, Hugo Mills, Kostia Khlebopros

On Thu, Feb 20, 2014 at 01:32:34PM -0500, Josef Bacik wrote:
> > Yes for 3), we may also export the information through the
> > existing ioctls if possible (eg. IOC_FS_INFO).
> > 
> 
> For _right now_ I'd say just not do the raid56 stuff if we don't
> notice any raid56 chunks from the normal load_space_info, and then if
> there are raid56 we try and run the tree search ioctl and notice if we
> get back EPERM or whatever you get when you don't have permissions.
> Then just spit out as much information that you can about the fs with
> a little note at the bottom that available calculation isn't 100% and
> you need to run as root if you want that info.

Works for me.

> Then what we could do is add another flag type for the existing
> SPACE_INFO ioctl to spit out the information you need about the
> raid5/6 chunks and then just test for those flags and make the
> adjustment necessary.  This way we avoid adding yet another ioctl and
> stuff will still work nicely for old kernels that don't have the
> updated ioctl.  Thanks,

Agreed. Extending SPACE_INFO looks suitable for this.

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

* [PATCH 5/8] Add command btrfs filesystem disk-usage
  2013-03-10 12:17 [PATCH V3][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
@ 2013-03-10 12:17 ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2013-03-10 12:17 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Hugo Mills, Michael Kjörling, Martin Steigerwald, cwillu,
	Chris Murphy, David Sterba, Zach Brown, Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-fi-disk_usage.c |  432 ++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |    3 +
 cmds-filesystem.c    |    2 +
 utils.c              |   58 +++++++
 utils.h              |    3 +
 5 files changed, 498 insertions(+)

diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 50b2fae..cb680e6 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -20,11 +20,13 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include "utils.h"
 #include "kerncompat.h"
 #include "ctree.h"
 #include "string_list.h"
+#include "string_table.h"
 
 #include "commands.h"
 
@@ -45,6 +47,13 @@ struct chunk_info {
 	u64	num_stripes;
 };
 
+/* to store information about the disks */
+struct disk_info {
+	u64	devid;
+	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
+	u64	size;
+};
+
 /*
  * Pretty print the size
  */
@@ -528,3 +537,426 @@ int cmd_filesystem_df(int argc, char **argv)
 	return 0;
 }
 
+/*
+ *  Helper to sort the disk_info structure
+ */
+static int cmp_disk_info(const void *a, const void *b)
+{
+	return strcmp(((struct disk_info *)a)->path,
+			((struct disk_info *)b)->path);
+}
+
+/*
+ *  This function load the disk_info structure and put them in an array
+ */
+static int load_disks_info(int fd,
+			   struct disk_info **disks_info_ptr,
+			   int *disks_info_count)
+{
+
+	int ret, i, ndevs;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+	struct disk_info *info;
+
+	*disks_info_count = 0;
+	*disks_info_ptr = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		fprintf(stderr, "ERROR: cannot get filesystem info\n");
+		return -1;
+	}
+
+	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
+	if (!info) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return -1;
+	}
+
+	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
+
+		BUG_ON(ndevs >= fi_args.num_devices);
+		ret = get_device_info(fd, i, &dev_info);
+
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			fprintf(stderr,
+			    "ERROR: cannot get info about device devid=%d\n",
+			    i);
+			free(info);
+			return -1;
+		}
+
+		info[ndevs].devid = dev_info.devid;
+		strcpy(info[ndevs].path, (char *)dev_info.path);
+		info[ndevs].size = get_partition_size((char *)dev_info.path);
+		++ndevs;
+	}
+
+	BUG_ON(ndevs != fi_args.num_devices);
+	qsort(info, fi_args.num_devices,
+		sizeof(struct disk_info), cmp_disk_info);
+
+	*disks_info_count = fi_args.num_devices;
+	*disks_info_ptr = info;
+
+	return 0;
+
+}
+
+/*
+ *  This function computes the size of a chunk in a disk
+ */ 
+static u64 calc_chunk_size(struct chunk_info *ci)
+{
+	if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
+		return ci->size / ci->num_stripes;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
+		return ci->size / (ci->num_stripes -1);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
+		return ci->size / (ci->num_stripes -2);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
+		return ci->size / ci->num_stripes;
+	return ci->size;
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in tabular format
+ */
+static void _cmd_filesystem_disk_usage_tabular(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *chunks_info_ptr,
+					int chunks_info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+	u64 total_unused = 0;
+	struct string_table *matrix = 0;
+	int  ncols, nrows;
+	
+
+	ncols = sargs->total_spaces + 2;
+	nrows = 2 + 1 + disks_info_count + 1 + 2;
+
+	matrix = table_create(ncols, nrows);
+	if (!matrix) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return;
+	}
+
+	/* header */
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+
+		u64 flags = sargs->spaces[i].flags;
+		description = btrfs_flags2description(flags);
+
+		table_printf(matrix, 1+i, 0, "<%s", description);
+	}
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		r_mode = btrfs_flags2profile(flags);
+
+		table_printf(matrix, 1+i, 1, "<%s", r_mode);
+	}
+
+	table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
+
+	/* body */
+	for (i = 0 ; i < disks_info_count ; i++) {
+		int k, col;
+		char *p;
+
+		u64  total_allocated = 0, unused;
+
+		p = strrchr(disks_info_ptr[i].path, '/');
+		if (!p)
+			p = disks_info_ptr[i].path;
+		else
+			p++;
+
+		table_printf(matrix, 0, i+3, "<%s",
+				disks_info_ptr[i].path);
+
+		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
+			u64	flags = sargs->spaces[k].flags;
+			int	j;
+
+			for (j = 0 ; j < chunks_info_count ; j++) {
+				u64 size = calc_chunk_size(chunks_info_ptr+j);
+
+				if (chunks_info_ptr[j].type != flags ||
+				    chunks_info_ptr[j].devid !=
+					disks_info_ptr[i].devid)
+						continue;
+
+				table_printf(matrix, col, i+3,
+					">%s", sla_pretty_sizes(size, mode));
+				total_allocated += size;
+				col++;
+				break;
+
+			}
+			if (j == chunks_info_count) {
+				table_printf(matrix, col, i+3, ">-");
+				col++;
+			}
+		}
+
+		unused = get_partition_size(disks_info_ptr[i].path) -
+				total_allocated;
+
+		table_printf(matrix, sargs->total_spaces + 1, i + 3,
+			       ">%s", sla_pretty_sizes(unused, mode));
+		total_unused += unused;
+
+	}
+
+	for (i = 0; i <= sargs->total_spaces; i++)
+		table_printf(matrix, i + 1, disks_info_count + 3, "=");
+
+
+	/* footer */
+	table_printf(matrix, 0, disks_info_count + 4, "<Total");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1 + i, disks_info_count + 4,
+			">%s",
+			sla_pretty_sizes(sargs->spaces[i].total_bytes, mode));
+
+	table_printf(matrix, sargs->total_spaces+1, disks_info_count+4,
+		">%s", sla_pretty_sizes(total_unused, mode));
+
+	table_printf(matrix, 0, disks_info_count+5, "<Used");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1+i, disks_info_count+5, ">%s",
+			sla_pretty_sizes(sargs->spaces[i].used_bytes, mode));
+
+
+	table_dump(matrix);
+	table_free(matrix);
+
+}
+
+/*
+ *  This function prints the unused space per every disk
+ */
+static void print_unused(struct chunk_info *info_ptr,
+			  int info_count,
+			  struct disk_info *disks_info_ptr,
+			  int disks_info_count,
+			  int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < info_count ; j++)
+			if (info_ptr[j].devid == disks_info_ptr[i].devid)
+				total += calc_chunk_size(info_ptr+j);
+
+		s = sla_pretty_sizes(disks_info_ptr[i].size - total, mode);
+		printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+
+	}
+
+}
+
+/*
+ *  This function prints the allocated chunk per every disk
+ */
+static void print_chunk_disks(u64 chunk_type,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				struct disk_info *disks_info_ptr,
+				int disks_info_count,
+				int mode)
+{
+	int i;
+
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < chunks_info_count ; j++) {
+
+			if (chunks_info_ptr[j].type != chunk_type)
+				continue;
+			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
+				continue;
+
+			total += calc_chunk_size(&(chunks_info_ptr[j]));
+			//total += chunks_info_ptr[j].size;
+		}
+
+		if (total > 0) {
+			s = sla_pretty_sizes(total, mode);
+			printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+		}
+	}
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in linear format
+ */
+static void _cmd_filesystem_disk_usage_linear(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *info_ptr,
+					int info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		description= btrfs_flags2description(flags);
+		r_mode = btrfs_flags2profile(flags);
+
+		printf("%s,%s: Size:%s, Used:%s\n",
+			description,
+			r_mode,
+			sla_pretty_sizes(sargs->spaces[i].total_bytes ,
+			    mode),
+			sla_pretty_sizes(sargs->spaces[i].used_bytes,
+					mode));
+
+		print_chunk_disks(flags, info_ptr, info_count,
+				disks_info_ptr, disks_info_count,
+				mode);
+		printf("\n");
+
+	}
+
+	printf("Unallocated:\n");
+	print_unused(info_ptr, info_count,
+			disks_info_ptr, disks_info_count,
+			mode);
+
+
+
+}
+
+static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+	int ret = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (tabular)
+		_cmd_filesystem_disk_usage_tabular(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+	else
+		_cmd_filesystem_disk_usage_linear(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+
+exit:
+
+	string_list_free();
+	if (sargs)
+		free(sargs);
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_disk_usage_usage[] = {
+	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
+	"Show in which disk the chunks are allocated.",
+	"",
+	"-b\tSet byte as unit",
+	"-t\tShow data in tabular format",
+	NULL
+};
+
+int cmd_filesystem_disk_usage(int argc, char **argv)
+{
+
+	int	flags =	DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+	int	tabular = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "bt");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		case 't':
+			tabular = 1;
+			break;
+		default:
+			usage(cmd_filesystem_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i]);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
+		close(fd);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
+
+
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index 9f68bb3..c7459b1 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -22,4 +22,7 @@
 extern const char * const cmd_filesystem_df_usage[];
 int cmd_filesystem_df(int argc, char **argv);
 
+extern const char * const cmd_filesystem_disk_usage_usage[];
+int cmd_filesystem_disk_usage(int argc, char **argv);
+
 #endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 5301dc3..e9eb0c4 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -403,6 +403,8 @@ const struct cmd_group filesystem_cmd_group = {
 		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
 		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
 		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
+		{ "disk-usage", cmd_filesystem_disk_usage,
+			cmd_filesystem_disk_usage_usage, NULL, 0 },
 		{ 0, 0, 0, 0, 0 },
 	}
 };
diff --git a/utils.c b/utils.c
index 029729c..60f05e4 100644
--- a/utils.c
+++ b/utils.c
@@ -1400,3 +1400,61 @@ u64 disk_size(char *path)
 
 }
 
+u64 get_partition_size(char *dev)
+{
+	u64 result;
+	int fd = open(dev, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
+		close(fd);
+		return 0;
+	}
+	close(fd);
+
+	return result;
+}
+
+/*
+ *  Convert a chunk type to a chunk description
+ */
+const char * btrfs_flags2description(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_DATA) {
+		if (flags & BTRFS_BLOCK_GROUP_METADATA)
+			return "Data+Metadata";
+		else
+			return "Data";
+	} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
+		return "System";
+	} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
+		return "Metadata";
+	} else {
+		return "Unknown";
+	}
+}
+
+/*
+ *  Convert a chunk type to a chunk profile description
+ */
+const char * btrfs_flags2profile(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_RAID0) {
+		return "RAID0";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
+		return "RAID1";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID5) {
+		return "RAID5";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID6) {
+		return "RAID6";
+	} else if (flags & BTRFS_BLOCK_GROUP_DUP) {
+		return "DUP";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
+		return "RAID10";
+	} else {
+		return "Single";
+	}
+}
+
+
diff --git a/utils.h b/utils.h
index 7974d00..84fdd0e 100644
--- a/utils.h
+++ b/utils.h
@@ -60,4 +60,7 @@ char *__strncpy__null(char *dest, const char *src, size_t n);
 #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest))
 
 u64 disk_size(char *path);
+u64 get_partition_size(char *dev);
+const char * btrfs_flags2profile(u64 flags);
+const char * btrfs_flags2description(u64 flags);
 #endif
-- 
1.7.10.4


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

* [PATCH 5/8] Add command btrfs filesystem disk-usage
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2013-02-23 13:46 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Hugo Mills, Michael Kjörling, Martin Steigerwald, cwillu,
	Chris Murphy, David Sterba, Zach Brown, Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-fi-disk_usage.c |  434 +++++++++++++++++++++++++++++++++++++++++++++++++-
 cmds-fi-disk_usage.h |    2 +
 cmds-filesystem.c    |    2 +
 utils.c              |   58 +++++++
 utils.h              |    3 +
 5 files changed, 498 insertions(+), 1 deletion(-)

diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 1e3589f..eea4168 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -20,11 +20,13 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include "utils.h"
 #include "kerncompat.h"
 #include "ctree.h"
 #include "string_list.h"
+#include "string_table.h"
 
 #include "commands.h"
 
@@ -42,7 +44,14 @@ struct chunk_info {
 	u64	type;
 	u64	size;
 	u64	devid;
-	int	num_stripes;
+	u64	num_stripes;
+};
+
+/* to store information about the disks */
+struct disk_info {
+	u64	devid;
+	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
+	u64	size;
 };
 
 /*
@@ -518,3 +527,426 @@ int cmd_filesystem_df(int argc, char **argv)
 	return 0;
 }
 
+/*
+ *  Helper to sort the disk_info structure
+ */
+static int cmp_disk_info(const void *a, const void *b)
+{
+	return strcmp(((struct disk_info *)a)->path,
+			((struct disk_info *)b)->path);
+}
+
+/*
+ *  This function load the disk_info structure and put them in an array
+ */
+static int load_disks_info(int fd,
+			   struct disk_info **disks_info_ptr,
+			   int *disks_info_count)
+{
+
+	int ret, i, ndevs;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+	struct disk_info *info;
+
+	*disks_info_count = 0;
+	*disks_info_ptr = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		fprintf(stderr, "ERROR: cannot get filesystem info\n");
+		return -1;
+	}
+
+	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
+	if (!info) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return -1;
+	}
+
+	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
+
+		BUG_ON(ndevs >= fi_args.num_devices);
+		ret = get_device_info(fd, i, &dev_info);
+
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			fprintf(stderr,
+			    "ERROR: cannot get info about device devid=%d\n",
+			    i);
+			free(info);
+			return -1;
+		}
+
+		info[ndevs].devid = dev_info.devid;
+		strcpy(info[ndevs].path, (char *)dev_info.path);
+		info[ndevs].size = get_partition_size((char *)dev_info.path);
+		++ndevs;
+	}
+
+	BUG_ON(ndevs != fi_args.num_devices);
+	qsort(info, fi_args.num_devices,
+		sizeof(struct disk_info), cmp_disk_info);
+
+	*disks_info_count = fi_args.num_devices;
+	*disks_info_ptr = info;
+
+	return 0;
+
+}
+
+/*
+ *  This function computes the size of a chunk in a disk
+ */ 
+static u64 calc_chunk_size(struct chunk_info *ci)
+{
+	if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
+		return ci->size / ci->num_stripes;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
+		return ci->size / (ci->num_stripes -1);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
+		return ci->size / (ci->num_stripes -2);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
+		return ci->size / ci->num_stripes;
+	return ci->size;
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in tabular format
+ */
+static void _cmd_filesystem_disk_usage_tabular(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *chunks_info_ptr,
+					int chunks_info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+	u64 total_unused = 0;
+	struct string_table *matrix = 0;
+	int  ncols, nrows;
+	
+
+	ncols = sargs->total_spaces + 2;
+	nrows = 2 + 1 + disks_info_count + 1 + 2;
+
+	matrix = table_create(ncols, nrows);
+	if (!matrix) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return;
+	}
+
+	/* header */
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+
+		u64 flags = sargs->spaces[i].flags;
+		description = btrfs_flags2description(flags);
+
+		table_printf(matrix, 1+i, 0, "<%s", description);
+	}
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		r_mode = btrfs_flags2profile(flags);
+
+		table_printf(matrix, 1+i, 1, "<%s", r_mode);
+	}
+
+	table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
+
+	/* body */
+	for (i = 0 ; i < disks_info_count ; i++) {
+		int k, col;
+		char *p;
+
+		u64  total_allocated = 0, unused;
+
+		p = strrchr(disks_info_ptr[i].path, '/');
+		if (!p)
+			p = disks_info_ptr[i].path;
+		else
+			p++;
+
+		table_printf(matrix, 0, i+3, "<%s",
+				disks_info_ptr[i].path);
+
+		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
+			u64	flags = sargs->spaces[k].flags;
+			int	j;
+
+			for (j = 0 ; j < chunks_info_count ; j++) {
+				u64 size = calc_chunk_size(chunks_info_ptr+j);
+
+				if (chunks_info_ptr[j].type != flags ||
+				    chunks_info_ptr[j].devid !=
+					disks_info_ptr[i].devid)
+						continue;
+
+				table_printf(matrix, col, i+3,
+					">%s", df_pretty_sizes(size, mode));
+				total_allocated += size;
+				col++;
+				break;
+
+			}
+			if (j == chunks_info_count) {
+				table_printf(matrix, col, i+3, ">-");
+				col++;
+			}
+		}
+
+		unused = get_partition_size(disks_info_ptr[i].path) -
+				total_allocated;
+
+		table_printf(matrix, sargs->total_spaces + 1, i + 3,
+			       ">%s", df_pretty_sizes(unused, mode));
+		total_unused += unused;
+
+	}
+
+	for (i = 0; i <= sargs->total_spaces; i++)
+		table_printf(matrix, i + 1, disks_info_count + 3, "=");
+
+
+	/* footer */
+	table_printf(matrix, 0, disks_info_count + 4, "<Total");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1 + i, disks_info_count + 4,
+			">%s",
+			df_pretty_sizes(sargs->spaces[i].total_bytes, mode));
+
+	table_printf(matrix, sargs->total_spaces+1, disks_info_count+4,
+		">%s", df_pretty_sizes(total_unused, mode));
+
+	table_printf(matrix, 0, disks_info_count+5, "<Used");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1+i, disks_info_count+5, ">%s",
+			df_pretty_sizes(sargs->spaces[i].used_bytes, mode));
+
+
+	table_dump(matrix);
+	table_free(matrix);
+
+}
+
+/*
+ *  This function prints the unused space per every disk
+ */
+static void print_unused(struct chunk_info *info_ptr,
+			  int info_count,
+			  struct disk_info *disks_info_ptr,
+			  int disks_info_count,
+			  int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < info_count ; j++)
+			if (info_ptr[j].devid == disks_info_ptr[i].devid)
+				total += calc_chunk_size(info_ptr+j);
+
+		s = df_pretty_sizes(disks_info_ptr[i].size - total, mode);
+		printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+
+	}
+
+}
+
+/*
+ *  This function prints the allocated chunk per every disk
+ */
+static void print_chunk_disks(u64 chunk_type,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				struct disk_info *disks_info_ptr,
+				int disks_info_count,
+				int mode)
+{
+	int i;
+
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < chunks_info_count ; j++) {
+
+			if (chunks_info_ptr[j].type != chunk_type)
+				continue;
+			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
+				continue;
+
+			total += calc_chunk_size(&(chunks_info_ptr[j]));
+			//total += chunks_info_ptr[j].size;
+		}
+
+		if (total > 0) {
+			s = df_pretty_sizes(total, mode);
+			printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+		}
+	}
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in linear format
+ */
+static void _cmd_filesystem_disk_usage_linear(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *info_ptr,
+					int info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		description= btrfs_flags2description(flags);
+		r_mode = btrfs_flags2profile(flags);
+
+		printf("%s,%s: Size:%s, Used:%s\n",
+			description,
+			r_mode,
+			df_pretty_sizes(sargs->spaces[i].total_bytes ,
+			    mode),
+			df_pretty_sizes(sargs->spaces[i].used_bytes,
+					mode));
+
+		print_chunk_disks(flags, info_ptr, info_count,
+				disks_info_ptr, disks_info_count,
+				mode);
+		printf("\n");
+
+	}
+
+	printf("Unallocated:\n");
+	print_unused(info_ptr, info_count,
+			disks_info_ptr, disks_info_count,
+			mode);
+
+
+
+}
+
+static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+	int ret = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (tabular)
+		_cmd_filesystem_disk_usage_tabular(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+	else
+		_cmd_filesystem_disk_usage_linear(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+
+exit:
+
+	string_list_free();
+	if (sargs)
+		free(sargs);
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_disk_usage_usage[] = {
+	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
+	"Show in which disk the chunks are allocated.",
+	"",
+	"-b\tSet byte as unit",
+	"-t\tShow data in tabular format",
+	NULL
+};
+
+int cmd_filesystem_disk_usage(int argc, char **argv)
+{
+
+	int	flags =	DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+	int	tabular = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "bt");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		case 't':
+			tabular = 1;
+			break;
+		default:
+			usage(cmd_filesystem_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i]);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
+		close(fd);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
+
+
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index 9f68bb3..ae11570 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -21,5 +21,7 @@
 
 extern const char * const cmd_filesystem_df_usage[];
 int cmd_filesystem_df(int argc, char **argv);
+extern const char * const cmd_filesystem_disk_usage_usage[];
+int cmd_filesystem_disk_usage(int argc, char **argv);
 
 #endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 5301dc3..e9eb0c4 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -403,6 +403,8 @@ const struct cmd_group filesystem_cmd_group = {
 		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
 		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
 		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
+		{ "disk-usage", cmd_filesystem_disk_usage,
+			cmd_filesystem_disk_usage_usage, NULL, 0 },
 		{ 0, 0, 0, 0, 0 },
 	}
 };
diff --git a/utils.c b/utils.c
index 029729c..60f05e4 100644
--- a/utils.c
+++ b/utils.c
@@ -1400,3 +1400,61 @@ u64 disk_size(char *path)
 
 }
 
+u64 get_partition_size(char *dev)
+{
+	u64 result;
+	int fd = open(dev, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
+		close(fd);
+		return 0;
+	}
+	close(fd);
+
+	return result;
+}
+
+/*
+ *  Convert a chunk type to a chunk description
+ */
+const char * btrfs_flags2description(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_DATA) {
+		if (flags & BTRFS_BLOCK_GROUP_METADATA)
+			return "Data+Metadata";
+		else
+			return "Data";
+	} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
+		return "System";
+	} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
+		return "Metadata";
+	} else {
+		return "Unknown";
+	}
+}
+
+/*
+ *  Convert a chunk type to a chunk profile description
+ */
+const char * btrfs_flags2profile(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_RAID0) {
+		return "RAID0";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
+		return "RAID1";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID5) {
+		return "RAID5";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID6) {
+		return "RAID6";
+	} else if (flags & BTRFS_BLOCK_GROUP_DUP) {
+		return "DUP";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
+		return "RAID10";
+	} else {
+		return "Single";
+	}
+}
+
+
diff --git a/utils.h b/utils.h
index 7974d00..84fdd0e 100644
--- a/utils.h
+++ b/utils.h
@@ -60,4 +60,7 @@ char *__strncpy__null(char *dest, const char *src, size_t n);
 #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest))
 
 u64 disk_size(char *path);
+u64 get_partition_size(char *dev);
+const char * btrfs_flags2profile(u64 flags);
+const char * btrfs_flags2description(u64 flags);
 #endif
-- 
1.7.10.4


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

* [PATCH 5/8] Add command btrfs filesystem disk-usage
  2013-02-18 21:04 [PATCH][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
@ 2013-02-18 21:04 ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2013-02-18 21:04 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Hugo Mills, Michael Kjörling, Martin Steigerwald, cwillu,
	Chris Murphy, David Sterba

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-fi-disk_usage.c |  434 +++++++++++++++++++++++++++++++++++++++++++++++++-
 cmds-fi-disk_usage.h |    2 +
 cmds-filesystem.c    |    2 +
 utils.c              |   58 +++++++
 utils.h              |    3 +
 5 files changed, 498 insertions(+), 1 deletion(-)

diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 1e3589f..eea4168 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -20,11 +20,13 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include "utils.h"
 #include "kerncompat.h"
 #include "ctree.h"
 #include "string_list.h"
+#include "string_table.h"
 
 #include "commands.h"
 
@@ -42,7 +44,14 @@ struct chunk_info {
 	u64	type;
 	u64	size;
 	u64	devid;
-	int	num_stripes;
+	u64	num_stripes;
+};
+
+/* to store information about the disks */
+struct disk_info {
+	u64	devid;
+	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
+	u64	size;
 };
 
 /*
@@ -518,3 +527,426 @@ int cmd_filesystem_df(int argc, char **argv)
 	return 0;
 }
 
+/*
+ *  Helper to sort the disk_info structure
+ */
+static int cmp_disk_info(const void *a, const void *b)
+{
+	return strcmp(((struct disk_info *)a)->path,
+			((struct disk_info *)b)->path);
+}
+
+/*
+ *  This function load the disk_info structure and put them in an array
+ */
+static int load_disks_info(int fd,
+			   struct disk_info **disks_info_ptr,
+			   int *disks_info_count)
+{
+
+	int ret, i, ndevs;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+	struct disk_info *info;
+
+	*disks_info_count = 0;
+	*disks_info_ptr = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		fprintf(stderr, "ERROR: cannot get filesystem info\n");
+		return -1;
+	}
+
+	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
+	if (!info) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return -1;
+	}
+
+	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
+
+		BUG_ON(ndevs >= fi_args.num_devices);
+		ret = get_device_info(fd, i, &dev_info);
+
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			fprintf(stderr,
+			    "ERROR: cannot get info about device devid=%d\n",
+			    i);
+			free(info);
+			return -1;
+		}
+
+		info[ndevs].devid = dev_info.devid;
+		strcpy(info[ndevs].path, (char *)dev_info.path);
+		info[ndevs].size = get_partition_size((char *)dev_info.path);
+		++ndevs;
+	}
+
+	BUG_ON(ndevs != fi_args.num_devices);
+	qsort(info, fi_args.num_devices,
+		sizeof(struct disk_info), cmp_disk_info);
+
+	*disks_info_count = fi_args.num_devices;
+	*disks_info_ptr = info;
+
+	return 0;
+
+}
+
+/*
+ *  This function computes the size of a chunk in a disk
+ */ 
+static u64 calc_chunk_size(struct chunk_info *ci)
+{
+	if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
+		return ci->size / ci->num_stripes;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
+		return ci->size ;
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
+		return ci->size / (ci->num_stripes -1);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
+		return ci->size / (ci->num_stripes -2);
+	else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
+		return ci->size / ci->num_stripes;
+	return ci->size;
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in tabular format
+ */
+static void _cmd_filesystem_disk_usage_tabular(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *chunks_info_ptr,
+					int chunks_info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+	u64 total_unused = 0;
+	struct string_table *matrix = 0;
+	int  ncols, nrows;
+	
+
+	ncols = sargs->total_spaces + 2;
+	nrows = 2 + 1 + disks_info_count + 1 + 2;
+
+	matrix = table_create(ncols, nrows);
+	if (!matrix) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return;
+	}
+
+	/* header */
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+
+		u64 flags = sargs->spaces[i].flags;
+		description = btrfs_flags2description(flags);
+
+		table_printf(matrix, 1+i, 0, "<%s", description);
+	}
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		r_mode = btrfs_flags2profile(flags);
+
+		table_printf(matrix, 1+i, 1, "<%s", r_mode);
+	}
+
+	table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
+
+	/* body */
+	for (i = 0 ; i < disks_info_count ; i++) {
+		int k, col;
+		char *p;
+
+		u64  total_allocated = 0, unused;
+
+		p = strrchr(disks_info_ptr[i].path, '/');
+		if (!p)
+			p = disks_info_ptr[i].path;
+		else
+			p++;
+
+		table_printf(matrix, 0, i+3, "<%s",
+				disks_info_ptr[i].path);
+
+		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
+			u64	flags = sargs->spaces[k].flags;
+			int	j;
+
+			for (j = 0 ; j < chunks_info_count ; j++) {
+				u64 size = calc_chunk_size(chunks_info_ptr+j);
+
+				if (chunks_info_ptr[j].type != flags ||
+				    chunks_info_ptr[j].devid !=
+					disks_info_ptr[i].devid)
+						continue;
+
+				table_printf(matrix, col, i+3,
+					">%s", df_pretty_sizes(size, mode));
+				total_allocated += size;
+				col++;
+				break;
+
+			}
+			if (j == chunks_info_count) {
+				table_printf(matrix, col, i+3, ">-");
+				col++;
+			}
+		}
+
+		unused = get_partition_size(disks_info_ptr[i].path) -
+				total_allocated;
+
+		table_printf(matrix, sargs->total_spaces + 1, i + 3,
+			       ">%s", df_pretty_sizes(unused, mode));
+		total_unused += unused;
+
+	}
+
+	for (i = 0; i <= sargs->total_spaces; i++)
+		table_printf(matrix, i + 1, disks_info_count + 3, "=");
+
+
+	/* footer */
+	table_printf(matrix, 0, disks_info_count + 4, "<Total");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1 + i, disks_info_count + 4,
+			">%s",
+			df_pretty_sizes(sargs->spaces[i].total_bytes, mode));
+
+	table_printf(matrix, sargs->total_spaces+1, disks_info_count+4,
+		">%s", df_pretty_sizes(total_unused, mode));
+
+	table_printf(matrix, 0, disks_info_count+5, "<Used");
+	for (i = 0; i < sargs->total_spaces; i++)
+		table_printf(matrix, 1+i, disks_info_count+5, ">%s",
+			df_pretty_sizes(sargs->spaces[i].used_bytes, mode));
+
+
+	table_dump(matrix);
+	table_free(matrix);
+
+}
+
+/*
+ *  This function prints the unused space per every disk
+ */
+static void print_unused(struct chunk_info *info_ptr,
+			  int info_count,
+			  struct disk_info *disks_info_ptr,
+			  int disks_info_count,
+			  int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < info_count ; j++)
+			if (info_ptr[j].devid == disks_info_ptr[i].devid)
+				total += calc_chunk_size(info_ptr+j);
+
+		s = df_pretty_sizes(disks_info_ptr[i].size - total, mode);
+		printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+
+	}
+
+}
+
+/*
+ *  This function prints the allocated chunk per every disk
+ */
+static void print_chunk_disks(u64 chunk_type,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				struct disk_info *disks_info_ptr,
+				int disks_info_count,
+				int mode)
+{
+	int i;
+
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < chunks_info_count ; j++) {
+
+			if (chunks_info_ptr[j].type != chunk_type)
+				continue;
+			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
+				continue;
+
+			total += calc_chunk_size(&(chunks_info_ptr[j]));
+			//total += chunks_info_ptr[j].size;
+		}
+
+		if (total > 0) {
+			s = df_pretty_sizes(total, mode);
+			printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+		}
+	}
+}
+
+/*
+ *  This function print the results of the command btrfs fi disk-usage
+ *  in linear format
+ */
+static void _cmd_filesystem_disk_usage_linear(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *info_ptr,
+					int info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		const char *description;
+		const char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		description= btrfs_flags2description(flags);
+		r_mode = btrfs_flags2profile(flags);
+
+		printf("%s,%s: Size:%s, Used:%s\n",
+			description,
+			r_mode,
+			df_pretty_sizes(sargs->spaces[i].total_bytes ,
+			    mode),
+			df_pretty_sizes(sargs->spaces[i].used_bytes,
+					mode));
+
+		print_chunk_disks(flags, info_ptr, info_count,
+				disks_info_ptr, disks_info_count,
+				mode);
+		printf("\n");
+
+	}
+
+	printf("Unallocated:\n");
+	print_unused(info_ptr, info_count,
+			disks_info_ptr, disks_info_count,
+			mode);
+
+
+
+}
+
+static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+	int ret = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (tabular)
+		_cmd_filesystem_disk_usage_tabular(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+	else
+		_cmd_filesystem_disk_usage_linear(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+
+exit:
+
+	string_list_free();
+	if (sargs)
+		free(sargs);
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_disk_usage_usage[] = {
+	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
+	"Show in which disk the chunks are allocated.",
+	"",
+	"-b\tSet byte as unit",
+	"-t\tShow data in tabular format",
+	NULL
+};
+
+int cmd_filesystem_disk_usage(int argc, char **argv)
+{
+
+	int	flags =	DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+	int	tabular = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "bt");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		case 't':
+			tabular = 1;
+			break;
+		default:
+			usage(cmd_filesystem_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i]);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
+		close(fd);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
+
+
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index 9f68bb3..ae11570 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -21,5 +21,7 @@
 
 extern const char * const cmd_filesystem_df_usage[];
 int cmd_filesystem_df(int argc, char **argv);
+extern const char * const cmd_filesystem_disk_usage_usage[];
+int cmd_filesystem_disk_usage(int argc, char **argv);
 
 #endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 5301dc3..e9eb0c4 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -403,6 +403,8 @@ const struct cmd_group filesystem_cmd_group = {
 		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
 		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
 		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
+		{ "disk-usage", cmd_filesystem_disk_usage,
+			cmd_filesystem_disk_usage_usage, NULL, 0 },
 		{ 0, 0, 0, 0, 0 },
 	}
 };
diff --git a/utils.c b/utils.c
index 029729c..60f05e4 100644
--- a/utils.c
+++ b/utils.c
@@ -1400,3 +1400,61 @@ u64 disk_size(char *path)
 
 }
 
+u64 get_partition_size(char *dev)
+{
+	u64 result;
+	int fd = open(dev, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
+		close(fd);
+		return 0;
+	}
+	close(fd);
+
+	return result;
+}
+
+/*
+ *  Convert a chunk type to a chunk description
+ */
+const char * btrfs_flags2description(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_DATA) {
+		if (flags & BTRFS_BLOCK_GROUP_METADATA)
+			return "Data+Metadata";
+		else
+			return "Data";
+	} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
+		return "System";
+	} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
+		return "Metadata";
+	} else {
+		return "Unknown";
+	}
+}
+
+/*
+ *  Convert a chunk type to a chunk profile description
+ */
+const char * btrfs_flags2profile(u64 flags)
+{
+	if (flags & BTRFS_BLOCK_GROUP_RAID0) {
+		return "RAID0";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
+		return "RAID1";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID5) {
+		return "RAID5";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID6) {
+		return "RAID6";
+	} else if (flags & BTRFS_BLOCK_GROUP_DUP) {
+		return "DUP";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
+		return "RAID10";
+	} else {
+		return "Single";
+	}
+}
+
+
diff --git a/utils.h b/utils.h
index 7974d00..84fdd0e 100644
--- a/utils.h
+++ b/utils.h
@@ -60,4 +60,7 @@ char *__strncpy__null(char *dest, const char *src, size_t n);
 #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest))
 
 u64 disk_size(char *path);
+u64 get_partition_size(char *dev);
+const char * btrfs_flags2profile(u64 flags);
+const char * btrfs_flags2description(u64 flags);
 #endif
-- 
1.7.10.4


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

* [PATCH 5/8] Add command btrfs filesystem disk-usage
  2012-11-02 10:15 [PATCH][BTRFS-PROGS] Enhance btrfs fi df Goffredo Baroncelli
@ 2012-11-02 10:15 ` Goffredo Baroncelli
  0 siblings, 0 replies; 34+ messages in thread
From: Goffredo Baroncelli @ 2012-11-02 10:15 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Hugo Mills, Michael Kjörling, Martin Steigerwald, cwillu,
	Chris Murphy, Goffredo Baroncelli

From: Goffredo Baroncelli <kreijack@inwind.it>

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds-fi-disk_usage.c |  662 +++++++++++++++++++++++++++++++++++++++++++++++++-
 cmds-fi-disk_usage.h |    2 +
 cmds-filesystem.c    |    2 +
 utils.c              |   15 ++
 utils.h              |    1 +
 5 files changed, 680 insertions(+), 2 deletions(-)

diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index 9131c47..4bec167 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -20,6 +20,7 @@
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <stdarg.h>
 
 #include "utils.h"
 #include "kerncompat.h"
@@ -31,14 +32,14 @@
 
 #define DF_HUMAN_UNIT		(1<<0)
 
-/* to store the information about the chunk */
+/* to store the information about the chunks */
 struct chunk_info {
 	u64	type;
 	u64	size;
 	u64	devid;
-	int	processed:1;
 };
 
+/* to store information about the disks */
 struct disk_info {
 	u64	devid;
 	char	path[BTRFS_DEVICE_PATH_NAME_MAX];
@@ -79,6 +80,95 @@ static void free_strings_to_free()
 	count_string_to_free = 0;
 }
 
+static int cmd_info_add_info(struct chunk_info **info_ptr,
+			int *info_count,
+			struct btrfs_chunk *chunk)
+{
+
+	u64	type = btrfs_stack_chunk_type(chunk);
+	u64	size = btrfs_stack_chunk_length(chunk);
+	int	num_stripes = btrfs_stack_chunk_num_stripes(chunk);
+	int	sub_stripes = btrfs_stack_chunk_sub_stripes(chunk);
+	int	j;
+
+	for (j = 0 ; j < num_stripes ; j++) {
+		int i;
+		struct chunk_info *p = 0;
+		struct btrfs_stripe *stripe;
+		u64    devid;
+
+		stripe = btrfs_stripe_nr(chunk, j);
+		devid = btrfs_stack_stripe_devid(stripe);
+
+		for (i = 0 ; i < *info_count ; i++)
+			if ((*info_ptr)[i].type == type &&
+			    (*info_ptr)[i].devid == devid) {
+				p = (*info_ptr) + i;
+				break;
+			}
+
+		if (!p) {
+			int size = sizeof(struct btrfs_chunk) * (*info_count+1);
+			struct chunk_info *res = realloc(*info_ptr, size);
+
+			if (!res) {
+				fprintf(stderr, "ERROR: not enough memory\n");
+				return -1;
+			}
+
+			*info_ptr = res;
+			p = res + *info_count;
+			(*info_count)++;
+
+			p->devid = devid;
+			p->type = type;
+			p->size = 0;
+		}
+
+		if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
+			p->size += size;
+		else if (type & BTRFS_BLOCK_GROUP_RAID10)
+			p->size += size / (num_stripes / sub_stripes);
+		else
+			p->size += size / num_stripes;
+
+	}
+
+	return 0;
+
+}
+
+static void btrfs_flags2description(u64 flags, char **description)
+{
+	if (flags & BTRFS_BLOCK_GROUP_DATA) {
+		if (flags & BTRFS_BLOCK_GROUP_METADATA)
+			*description = "Data+Metadata";
+		else
+			*description = "Data";
+	} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
+		*description = "System";
+	} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
+		*description = "Metadata";
+	} else {
+		*description = "Unknown";
+	}
+}
+
+static void btrfs_flags2profile(u64 flags, char **profile)
+{
+	if (flags & BTRFS_BLOCK_GROUP_RAID0) {
+		*profile = "RAID0";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
+		*profile = "RAID1";
+	} else if (flags & BTRFS_BLOCK_GROUP_DUP) {
+		*profile = "DUP";
+	} else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
+		*profile = "RAID10";
+	} else {
+		*profile = "Single";
+	}
+}
+
 static char *df_pretty_sizes(u64 size, int mode)
 {
 	char *s;
@@ -332,3 +422,571 @@ int cmd_filesystem_df(int argc, char **argv)
 	return 0;
 }
 
+static int cmp_chunk_info(const void *a, const void *b)
+{
+	return cmp_chunk_block_group(
+		((struct chunk_info *)a)->type,
+		((struct chunk_info *)b)->type);
+}
+
+static int load_chunk_info(int fd,
+			  struct chunk_info **info_ptr,
+			  int *info_count)
+{
+
+	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;
+	int i, e;
+
+
+	memset(&args, 0, sizeof(args));
+
+	/*
+	 * there may be more than one ROOT_ITEM key if there are
+	 * snapshots pending deletion, we have to loop through
+	 * them.
+	 */
+
+
+	sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID;
+
+	sk->min_objectid = 0;
+	sk->max_objectid = (u64)-1;
+	sk->max_type = 0;
+	sk->min_type = (u8)-1;
+	sk->min_offset = 0;
+	sk->max_offset = (u64)-1;
+	sk->min_transid = 0;
+	sk->max_transid = (u64)-1;
+	sk->nr_items = 4096;
+
+	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 0;
+		}
+		/* the ioctl returns the number of item it found in nr_items */
+
+		if (sk->nr_items == 0)
+			break;
+
+		off = 0;
+		for (i = 0; i < sk->nr_items; i++) {
+			struct btrfs_chunk *item;
+			sh = (struct btrfs_ioctl_search_header *)(args.buf +
+								  off);
+
+			off += sizeof(*sh);
+			item = (struct btrfs_chunk *)(args.buf + off);
+
+			if (cmd_info_add_info(info_ptr, info_count, item)) {
+				*info_ptr = 0;
+				free(*info_ptr);
+				return 100;
+			}
+
+			off += sh->len;
+
+			sk->min_objectid = sh->objectid;
+			sk->min_type = sh->type;
+			sk->min_offset = sh->offset+1;
+
+		}
+		if (!sk->min_offset)	/* overflow */
+			sk->min_type++;
+		else
+			continue;
+
+		if (!sk->min_type)
+			sk->min_objectid++;
+		 else
+			continue;
+
+		if (!sk->min_objectid)
+			break;
+	}
+
+	qsort(*info_ptr, *info_count, sizeof(struct chunk_info),
+		cmp_chunk_info);
+
+	return 0;
+
+}
+
+static int cmp_disk_info(const void *a, const void *b)
+{
+	return strcmp(((struct disk_info *)a)->path,
+			((struct disk_info *)b)->path);
+}
+
+static int load_disks_info(int fd,
+			   struct disk_info **disks_info_ptr,
+			   int *disks_info_count)
+{
+
+	int ret, i, ndevs;
+	struct btrfs_ioctl_fs_info_args fi_args;
+	struct btrfs_ioctl_dev_info_args dev_info;
+	struct disk_info *info;
+
+	*disks_info_count = 0;
+	*disks_info_ptr = 0;
+
+	ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
+	if (ret < 0) {
+		fprintf(stderr, "ERROR: cannot get filesystem info\n");
+		return -1;
+	}
+
+	info = malloc(sizeof(struct disk_info) * fi_args.num_devices);
+	if (!info) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return -1;
+	}
+
+	for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
+
+		BUG_ON(ndevs >= fi_args.num_devices);
+		ret = get_device_info(fd, i, &dev_info);
+
+		if (ret == -ENODEV)
+			continue;
+		if (ret) {
+			fprintf(stderr,
+			    "ERROR: cannot get info about device devid=%d\n",
+			    i);
+			free(info);
+			return -1;
+		}
+
+		info[ndevs].devid = dev_info.devid;
+		strcpy(info[ndevs].path, (char *)dev_info.path);
+		info[ndevs].size = get_partition_size((char *)dev_info.path);
+		++ndevs;
+	}
+
+	BUG_ON(ndevs != fi_args.num_devices);
+	qsort(info, fi_args.num_devices,
+		sizeof(struct disk_info), cmp_disk_info);
+
+	*disks_info_count = fi_args.num_devices;
+	*disks_info_ptr = info;
+
+	return 0;
+
+}
+
+static void print_unused(struct chunk_info *info_ptr,
+			  int info_count,
+			  struct disk_info *disks_info_ptr,
+			  int disks_info_count,
+			  int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < info_count ; j++)
+			if (info_ptr[j].devid == disks_info_ptr[i].devid)
+				total += info_ptr[j].size;
+
+		s = df_pretty_sizes(disks_info_ptr[i].size - total, mode);
+		printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+
+	}
+
+}
+
+static void print_chunk_disks(u64 chunk_type,
+				struct chunk_info *chunks_info_ptr,
+				int chunks_info_count,
+				struct disk_info *disks_info_ptr,
+				int disks_info_count,
+				int mode)
+{
+	int i;
+	for (i = 0 ; i < disks_info_count ; i++) {
+
+		int	j;
+		u64	total = 0;
+		char	*s;
+
+		for (j = 0 ; j < chunks_info_count ; j++) {
+			if (chunks_info_ptr[j].type != chunk_type)
+				continue;
+			if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid)
+				continue;
+
+			total += chunks_info_ptr[j].size;
+		}
+
+		if (total > 0) {
+			s = df_pretty_sizes(total, mode);
+			printf("   %s\t%10s\n", disks_info_ptr[i].path, s);
+		}
+	}
+}
+
+static char **create_table(int columns, int rows)
+{
+	char **p = calloc(rows * columns, sizeof(char *));
+	if (p)
+		add_strings_to_free((char *)p);
+	return p;
+}
+
+/*
+ * If fmt  starts with '<', the text is left aligned; if fmt starts with
+ * '>' the text is right aligned. If fmt is equal to '=' the text will
+ * be replaced by a '=====' dimensioned in the basis of the column width
+ */
+static char *vprintf_table(char **p, int num_cols, int column, int row,
+			  char *fmt, va_list ap)
+{
+	int idx =  num_cols*row+column;
+	char *msg = calloc(100, sizeof(char));
+
+	if (!msg)
+		return NULL;
+
+	add_strings_to_free(msg);
+	p[idx] = msg;
+	vsnprintf(msg, 99, fmt, ap);
+
+	return msg;
+}
+
+static char *printf_table(char **p, int num_cols, int column, int row,
+			  char *fmt, ...)
+{
+	va_list ap;
+	char *ret;
+
+	va_start(ap, fmt);
+	ret = vprintf_table(p, num_cols, column, row, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+static void dump_table(char **p, int ncols, int nrows)
+{
+	int	sizes[ncols];
+	int	i, j;
+
+	for (i = 0 ; i < ncols ; i++) {
+		sizes[i] = 0;
+		for (j = 0 ; j < nrows ; j++) {
+			int idx = i + j*ncols;
+			int s;
+
+			if (!p[idx])
+				continue;
+
+			s = strlen(p[idx]) - 1;
+			if (s < 1 || p[idx][0] == '=')
+				continue;
+
+			if (s > sizes[i])
+				sizes[i] = s;
+		}
+	}
+
+
+	for (j = 0 ; j < nrows ; j++) {
+		for (i = 0 ; i < ncols ; i++) {
+
+			int idx = i + j*ncols;
+
+			if (!p[idx] || !strlen(p[idx])) {
+				printf("%*s", sizes[i], "");
+			} else if (p[idx][0] == '=') {
+				int k;
+				for (k = 0 ; k < sizes[i] ; k++)
+					putchar('=');
+			} else {
+				printf("%*s",
+					p[idx][0] == '<' ? -sizes[i] : sizes[i],
+					p[idx]+1);
+			}
+			if (i != (ncols - 1))
+				putchar(' ');
+		}
+		putchar('\n');
+	}
+
+}
+
+
+static void _cmd_filesystem_disk_usage_tabular(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *chunks_info_ptr,
+					int chunks_info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+	u64 total_unused = 0;
+	char **matrix = 0;
+	int  ncols, nrows;
+
+	ncols = sargs->total_spaces + 2;
+	nrows = 2 + 1 + disks_info_count + 1 + 2;
+
+	matrix = create_table(ncols, nrows);
+	if (!matrix) {
+		fprintf(stderr, "ERROR: not enough memory\n");
+		return;
+	}
+
+	/* header */
+	for (i = 0; i < sargs->total_spaces; i++) {
+		char *description;
+
+		u64 flags = sargs->spaces[i].flags;
+		btrfs_flags2description(flags, &description);
+
+		printf_table(matrix, ncols, 1+i, 0, "<%s", description);
+	}
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		btrfs_flags2profile(flags, &r_mode);
+
+		printf_table(matrix, ncols, 1+i, 1, "<%s", r_mode);
+	}
+
+	printf_table(matrix, ncols, 1+sargs->total_spaces, 1, "<Unallocated");
+
+	/* body */
+	for (i = 0 ; i < disks_info_count ; i++) {
+		int k, col;
+		char *p;
+
+		u64  total_allocated = 0, unused;
+
+		p = strrchr(disks_info_ptr[i].path, '/');
+		if (!p)
+			p = disks_info_ptr[i].path;
+		else
+			p++;
+
+		printf_table(matrix, ncols, 0, i+3, "<%s",
+				disks_info_ptr[i].path);
+
+		for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
+			u64	flags = sargs->spaces[k].flags;
+			int	j;
+
+			for (j = 0 ; j < chunks_info_count ; j++) {
+				u64 size = chunks_info_ptr[j].size;
+
+				if (chunks_info_ptr[j].type != flags ||
+				    chunks_info_ptr[j].devid !=
+					disks_info_ptr[i].devid)
+						continue;
+
+				printf_table(matrix, ncols, col, i+3,
+					">%s", df_pretty_sizes(size, mode));
+				total_allocated += size;
+				col++;
+				break;
+
+			}
+			if (j == chunks_info_count) {
+				printf_table(matrix, ncols, col, i+3, ">-");
+				col++;
+			}
+		}
+
+		unused = get_partition_size(disks_info_ptr[i].path) -
+				total_allocated;
+
+		printf_table(matrix, ncols, sargs->total_spaces + 1, i + 3,
+			       ">%s", df_pretty_sizes(unused, mode));
+		total_unused += unused;
+
+	}
+
+	for (i = 0; i <= sargs->total_spaces; i++)
+		printf_table(matrix, ncols, i + 1, disks_info_count + 3, "=");
+
+
+	/* footer */
+	printf_table(matrix, ncols, 0, disks_info_count + 4, "<Total");
+	for (i = 0; i < sargs->total_spaces; i++)
+		printf_table(matrix, ncols, 1 + i, disks_info_count + 4,
+			">%s",
+			df_pretty_sizes(sargs->spaces[i].total_bytes, mode));
+
+	printf_table(matrix, ncols, sargs->total_spaces+1, disks_info_count+4,
+		">%s", df_pretty_sizes(total_unused, mode));
+
+	printf_table(matrix, ncols, 0, disks_info_count+5, "<Used");
+	for (i = 0; i < sargs->total_spaces; i++)
+		printf_table(matrix, ncols, 1+i, disks_info_count+5,
+			">%s",
+			df_pretty_sizes(sargs->spaces[i].used_bytes, mode));
+
+
+	dump_table(matrix, ncols, nrows);
+
+}
+
+static void _cmd_filesystem_disk_usage_linear(int mode,
+					struct btrfs_ioctl_space_args *sargs,
+					struct chunk_info *info_ptr,
+					int info_count,
+					struct disk_info *disks_info_ptr,
+					int disks_info_count)
+{
+	int i;
+
+	for (i = 0; i < sargs->total_spaces; i++) {
+		char *description;
+		char *r_mode;
+
+		u64 flags = sargs->spaces[i].flags;
+		btrfs_flags2description(flags, &description);
+		btrfs_flags2profile(flags, &r_mode);
+
+		printf("%s,%s: Size:%s, Used:%s\n",
+			description,
+			r_mode,
+			df_pretty_sizes(sargs->spaces[i].total_bytes ,
+			    mode),
+			df_pretty_sizes(sargs->spaces[i].used_bytes,
+					mode));
+
+		print_chunk_disks(flags, info_ptr, info_count,
+				disks_info_ptr, disks_info_count,
+				mode);
+		printf("\n");
+
+	}
+
+	printf("Unallocated:\n");
+	print_unused(info_ptr, info_count,
+			disks_info_ptr, disks_info_count,
+			mode);
+
+
+
+}
+
+static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular)
+{
+	struct btrfs_ioctl_space_args *sargs = 0;
+	int info_count = 0;
+	struct chunk_info *info_ptr = 0;
+	struct disk_info *disks_info_ptr = 0;
+	int disks_info_count = 0;
+	int ret = 0;
+
+	if (load_chunk_info(fd, &info_ptr, &info_count) ||
+	    load_disks_info(fd, &disks_info_ptr, &disks_info_count)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if ((sargs = load_space_info(fd, path)) == NULL) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (tabular)
+		_cmd_filesystem_disk_usage_tabular(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+	else
+		_cmd_filesystem_disk_usage_linear(mode, sargs,
+					info_ptr, info_count,
+					disks_info_ptr, disks_info_count);
+
+exit:
+
+	free_strings_to_free();
+	if (sargs)
+		free(sargs);
+	if (disks_info_ptr)
+		free(disks_info_ptr);
+	if (info_ptr)
+		free(info_ptr);
+
+	return ret;
+}
+
+const char * const cmd_filesystem_disk_usage_usage[] = {
+	"btrfs filesystem disk-usage [-b][-t] <path> [<path>..]",
+	"Show in which disk the chunks are allocated.",
+	"",
+	"-b\tSet byte as unit",
+	"-t\tShow data in tabular format",
+	NULL
+};
+
+int cmd_filesystem_disk_usage(int argc, char **argv)
+{
+
+	int	flags =	DF_HUMAN_UNIT;
+	int	i, more_than_one = 0;
+	int	tabular = 0;
+
+	optind = 1;
+	while (1) {
+		char	c = getopt(argc, argv, "bt");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			flags &= ~DF_HUMAN_UNIT;
+			break;
+		case 't':
+			tabular = 1;
+			break;
+		default:
+			usage(cmd_filesystem_disk_usage_usage);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		usage(cmd_filesystem_disk_usage_usage);
+		return 21;
+	}
+
+	for (i = optind; i < argc ; i++) {
+		int r, fd;
+		if (more_than_one)
+			printf("\n");
+
+		fd = open_file_or_dir(argv[i]);
+		if (fd < 0) {
+			fprintf(stderr, "ERROR: can't access to '%s'\n",
+				argv[1]);
+			return 12;
+		}
+		r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular);
+		close(fd);
+
+		if (r)
+			return r;
+		more_than_one = 1;
+
+	}
+
+	return 0;
+}
+
+
diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h
index 9f68bb3..ae11570 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -21,5 +21,7 @@
 
 extern const char * const cmd_filesystem_df_usage[];
 int cmd_filesystem_df(int argc, char **argv);
+extern const char * const cmd_filesystem_disk_usage_usage[];
+int cmd_filesystem_disk_usage(int argc, char **argv);
 
 #endif
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 1b915e4..7a833b4 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -423,6 +423,8 @@ const struct cmd_group filesystem_cmd_group = {
 		{ "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
 		{ "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
 		{ "label", cmd_label, cmd_label_usage, NULL, 0 },
+		{ "disk-usage", cmd_filesystem_disk_usage,
+			cmd_filesystem_disk_usage_usage, NULL, 0 },
 		{ 0, 0, 0, 0, 0 },
 	}
 };
diff --git a/utils.c b/utils.c
index 023fbca..2b12890 100644
--- a/utils.c
+++ b/utils.c
@@ -1341,3 +1341,18 @@ u64 disk_size(char *path)
 
 }
 
+u64 get_partition_size(char *dev)
+{
+	u64 result;
+	int fd = open(dev, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
+		close(fd);
+		return 0;
+	}
+	close(fd);
+
+	return result;
+}
diff --git a/utils.h b/utils.h
index 34a814d..e1caaae 100644
--- a/utils.h
+++ b/utils.h
@@ -56,4 +56,5 @@ int get_mountpt(char *dev, char *mntpt, size_t size);
 
 int btrfs_scan_block_devices(int run_ioctl);
 u64 disk_size(char *path);
+u64 get_partition_size(char *dev);
 #endif
-- 
1.7.10.4


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

end of thread, other threads:[~2014-02-22  0:03 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-13 19:18 [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df Goffredo Baroncelli
2014-02-13 19:19 ` [PATCH 1/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
2014-02-13 19:19 ` [PATCH 2/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
2014-02-13 19:19 ` [PATCH 3/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
2014-02-13 19:19 ` [PATCH 4/8] Allow use of get_device_info() Goffredo Baroncelli
2014-02-20 18:13   ` David Sterba
2014-02-13 19:19 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
2014-02-13 19:28   ` Roman Mamedov
2014-02-13 19:49     ` Goffredo Baroncelli
2014-02-13 20:22       ` Duncan
2014-02-13 21:00       ` Roman Mamedov
2014-02-14 17:57         ` Goffredo Baroncelli
2014-02-14 18:11           ` Roman Mamedov
2014-02-14 18:27             ` Goffredo Baroncelli
2014-02-14 18:34               ` Hugo Mills
2014-02-15 22:23                 ` Chris Murphy
2014-02-17 18:09                   ` Goffredo Baroncelli
2014-02-20 17:31                     ` David Sterba
2014-02-13 19:20 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
2014-02-13 19:20 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
2014-02-13 19:23   ` Roman Mamedov
2014-02-13 19:44     ` Goffredo Baroncelli
2014-02-13 19:20 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
2014-02-17 18:41 ` [PATCH][BTRFS-PROGS][v4] Enhance btrfs fi df David Sterba
2014-02-17 20:49   ` Goffredo Baroncelli
2014-02-20 18:08 ` David Sterba
2014-02-20 18:32   ` Josef Bacik
2014-02-20 19:20     ` Goffredo Baroncelli
2014-02-22  0:03     ` David Sterba
2014-02-20 19:18   ` Goffredo Baroncelli
  -- strict thread matches above, loose matches on Subject: below --
2013-03-10 12:17 [PATCH V3][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
2013-03-10 12:17 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
2013-02-18 21:04 [PATCH][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
2013-02-18 21:04 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
2012-11-02 10:15 [PATCH][BTRFS-PROGS] Enhance btrfs fi df Goffredo Baroncelli
2012-11-02 10:15 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli

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