All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
@ 2013-02-23 13:46 Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation Goffredo Baroncelli
                   ` (9 more replies)
  0 siblings, 10 replies; 19+ 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

Hi all, 

I updates my previous patches [1] to add support for raid5/6.
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
        http://cassiopea.homelinux.net/git/btrfs-progs-unstable.git
branch
        df-du-raid56

BR
G.Baroncelli

[1] http://permalink.gmane.org/gmane.comp.file-systems.btrfs/21071

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.

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

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

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

* [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation.
  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
  2013-02-25  2:20   ` Eric Sandeen
  2013-02-23 13:46 ` [PATCH 2/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 19+ 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>

This patch adds some helpers to manage the strings allocation and
deallocation.
The function string_list_add(char *) adds the passed string to a list;
the function string_list_free() frees all the strings together.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 Makefile      |    3 ++-
 string_list.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string_list.h |   23 +++++++++++++++++++++
 3 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 string_list.c
 create mode 100644 string_list.h

diff --git a/Makefile b/Makefile
index 596bf93..0d6c43a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,8 @@ 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 crc32c.o rbtree.o extent-cache.o extent_io.o \
 	  volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \
-	  send-stream.o send-utils.o qgroup.o raid6.o
+	  send-stream.o send-utils.o qgroup.o raid6.o \
+	  string_list.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
diff --git a/string_list.c b/string_list.c
new file mode 100644
index 0000000..8d8cc1f
--- /dev/null
+++ b/string_list.c
@@ -0,0 +1,63 @@
+/*
+ * 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>
+
+/* To store the strings */
+static void **strings_to_free;
+static int count_string_to_free;
+
+/* 
+ * Add a string to the dynamic allocated string list
+ */
+char *string_list_add(char *s)
+{
+	int  size;
+
+	size = sizeof(void *) * ++count_string_to_free;
+	strings_to_free = realloc(strings_to_free, size);
+
+	/* if we don't have enough memory, we have more serius
+	   problem than that a wrong handling of not enough memory */
+	if (!strings_to_free) {
+		fprintf(stderr, "add_string_to_free(): Not enough memory\n");
+		count_string_to_free = 0;
+		return NULL;
+	}
+
+	strings_to_free[count_string_to_free-1] = s;
+	return s;
+}
+
+/*
+ * Free the dynamic allocated strings list
+ */
+void string_list_free()
+{
+	int	i;
+	for (i = 0 ; i < count_string_to_free ; i++)
+		free(strings_to_free[i]);
+
+	free(strings_to_free);
+
+	strings_to_free = 0;
+	count_string_to_free = 0;
+}
+
+
diff --git a/string_list.h b/string_list.h
new file mode 100644
index 0000000..f974fbc
--- /dev/null
+++ b/string_list.h
@@ -0,0 +1,23 @@
+/*
+ * 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_LIST_H
+#define STRING_LIST_H
+
+void string_list_add(char *s);
+void string_list_free();
+
+#endif
-- 
1.7.10.4


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

* [PATCH 2/8] Enhance the command btrfs filesystem df.
  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 1/8] Add some helpers to manage the strings allocation/deallocation Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 3/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 19+ 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>

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             |    2 +-
 cmds-fi-disk_usage.c |  520 ++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |   25 +++
 cmds-filesystem.c    |  125 +-----------
 ctree.h              |   17 +-
 utils.c              |   14 ++
 utils.h              |    2 +
 7 files changed, 579 insertions(+), 126 deletions(-)
 create mode 100644 cmds-fi-disk_usage.c
 create mode 100644 cmds-fi-disk_usage.h

diff --git a/Makefile b/Makefile
index 0d6c43a..bd792b6 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
 	  string_list.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-quota.o cmds-qgroup.o cmds-replace.o cmds-fi-disk_usage.o
 
 CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
 	    -Wuninitialized -Wshadow -Wundef
diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
new file mode 100644
index 0000000..1e3589f
--- /dev/null
+++ b/cmds-fi-disk_usage.c
@@ -0,0 +1,520 @@
+/*
+ * 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 "string_list.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;
+	int	num_stripes;
+};
+
+/*
+ * Pretty print the size
+ */
+static char *df_pretty_sizes(u64 size, int mode)
+{
+	char *s;
+
+	if (mode & DF_HUMAN_UNIT) {
+		s = pretty_sizes(size);
+		if (!s)
+			return NULL;
+	} else {
+		s = malloc(20);
+		if (!s)
+			return NULL;
+		sprintf(s, "%llu", size);
+	}
+
+	string_list_add(s);
+	return s;
+}
+
+/*
+ * 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;
+
+		/* TODO: the raid5/raid6 ratio depends by the number
+		   of disk 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 = 9;
+	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(Max: %s, min: %s)\n",
+		width,
+		df_pretty_sizes((u64)(K*total_disk-total_used), mode),
+		df_pretty_sizes(total_disk-total_chunks+total_free, mode),
+		df_pretty_sizes((total_disk-total_chunks)/2+total_free, mode));
+	printf("Data to disk ratio:\t%*.0f %%\n",
+		width-2, K*100);
+
+exit:
+
+	string_list_free();
+	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;
+		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_disk_free(fd, argv[i], flags);
+		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
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 bdbd2ee..5301dc3 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -33,6 +33,7 @@
 
 #include "commands.h"
 #include "btrfslabel.h"
+#include "cmds-fi-disk_usage.h"
 
 static const char * const filesystem_cmd_group_usage[] = {
 	"btrfs filesystem [<group>] <command> [<args>]",
@@ -45,128 +46,6 @@ static const char * const cmd_df_usage[] = {
 	NULL
 };
 
-static int cmd_df(int argc, char **argv)
-{
-	struct btrfs_ioctl_space_args *sargs, *sargs_orig;
-	u64 count = 0, i;
-	int ret;
-	int fd;
-	int e;
-	char *path;
-
-	if (check_argc_exact(argc, 2))
-		usage(cmd_df_usage);
-
-	path = argv[1];
-
-	fd = open_file_or_dir(path);
-	if (fd < 0) {
-		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
-		return 12;
-	}
-
-	sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
-	if (!sargs)
-		return -ENOMEM;
-
-	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));
-		close(fd);
-		free(sargs);
-		return ret;
-	}
-	if (!sargs->total_spaces) {
-		close(fd);
-		free(sargs);
-		return 0;
-	}
-
-	count = sargs->total_spaces;
-
-	sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
-			(count * sizeof(struct btrfs_ioctl_space_info)));
-	if (!sargs) {
-		close(fd);
-		free(sargs_orig);
-		return -ENOMEM;
-	}
-
-	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));
-		close(fd);
-		free(sargs);
-		return ret;
-	}
-
-	for (i = 0; i < sargs->total_spaces; i++) {
-		char description[80];
-		char *total_bytes;
-		char *used_bytes;
-		int written = 0;
-		u64 flags = sargs->spaces[i].flags;
-
-		memset(description, 0, 80);
-
-		if (flags & BTRFS_BLOCK_GROUP_DATA) {
-			if (flags & BTRFS_BLOCK_GROUP_METADATA) {
-				snprintf(description, 14, "%s",
-					 "Data+Metadata");
-				written += 13;
-			} else {
-				snprintf(description, 5, "%s", "Data");
-				written += 4;
-			}
-		} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
-			snprintf(description, 7, "%s", "System");
-			written += 6;
-		} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
-			snprintf(description, 9, "%s", "Metadata");
-			written += 8;
-		}
-
-		if (flags & BTRFS_BLOCK_GROUP_RAID0) {
-			snprintf(description+written, 8, "%s", ", RAID0");
-			written += 7;
-		} else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
-			snprintf(description+written, 8, "%s", ", RAID1");
-			written += 7;
-		} else if (flags & BTRFS_BLOCK_GROUP_DUP) {
-			snprintf(description+written, 6, "%s", ", DUP");
-			written += 5;
-		} else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
-			snprintf(description+written, 9, "%s", ", RAID10");
-			written += 8;
-		} else if (flags & BTRFS_BLOCK_GROUP_RAID5) {
-			snprintf(description+written, 9, "%s", ", RAID5");
-			written += 7;
-		} else if (flags & BTRFS_BLOCK_GROUP_RAID6) {
-			snprintf(description+written, 9, "%s", ", RAID6");
-			written += 7;
-		}
-
-		total_bytes = pretty_sizes(sargs->spaces[i].total_bytes);
-		used_bytes = pretty_sizes(sargs->spaces[i].used_bytes);
-		printf("%s: total=%s, used=%s\n", description, total_bytes,
-		       used_bytes);
-	}
-	close(fd);
-	free(sargs);
-
-	return 0;
-}
-
 static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
 {
 	char uuidbuf[37];
@@ -517,7 +396,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 12f8fe3..a029368 100644
--- a/ctree.h
+++ b/ctree.h
@@ -798,9 +798,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)
+
 
 /* used in struct btrfs_balance_args fields */
 #define BTRFS_AVAIL_ALLOC_BIT_SINGLE	(1ULL << 48)
diff --git a/utils.c b/utils.c
index f9ee812..029729c 100644
--- a/utils.c
+++ b/utils.c
@@ -38,6 +38,8 @@
 #include <linux/major.h>
 #include <linux/kdev_t.h>
 #include <limits.h>
+#include <sys/vfs.h>
+
 #include "kerncompat.h"
 #include "radix-tree.h"
 #include "ctree.h"
@@ -1386,3 +1388,15 @@ int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
 
 	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 bbcaf6a..7974d00 100644
--- a/utils.h
+++ b/utils.h
@@ -19,6 +19,7 @@
 #ifndef __UTILS__
 #define __UTILS__
 
+#include "kerncompat.h"
 #include "ctree.h"
 
 #define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024)
@@ -58,4 +59,5 @@ char *__strncpy__null(char *dest, const char *src, size_t n);
 /* Helper to always get proper size of the destination string */
 #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest))
 
+u64 disk_size(char *path);
 #endif
-- 
1.7.10.4


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

* [PATCH 3/8] Create the man page entry for the command btrfs fi df
  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 1/8] Add some helpers to manage the strings allocation/deallocation Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 2/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 4/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 19+ 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>
---
 man/btrfs.8.in |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 94f4ffe..e2f86ea 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -31,6 +31,8 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [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 \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
@@ -266,6 +268,53 @@ NOTE: Currently there are the following limitations:
 - the filesystem should not have more than one device.
 .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
+
 \fBfilesystem show\fR [--all-devices|<uuid>|<label>]\fR
 Show the btrfs filesystem with some additional info. If no \fIUUID\fP or 
 \fIlabel\fP is passed, \fBbtrfs\fR show info of all the btrfs filesystem.
-- 
1.7.10.4


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

* [PATCH 4/8] Add helpers functions to handle the printing of data in tabular format.
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (2 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 3/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 19+ 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>

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 |  157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string_table.h |   36 +++++++++++++
 3 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 string_table.c
 create mode 100644 string_table.h

diff --git a/Makefile b/Makefile
index bd792b6..fd1b312 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
 	  inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
 	  volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \
 	  send-stream.o send-utils.o qgroup.o raid6.o \
-	  string_list.o
+	  string_list.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-fi-disk_usage.o
diff --git a/string_table.c b/string_table.c
new file mode 100644
index 0000000..9784422
--- /dev/null
+++ b/string_table.c
@@ -0,0 +1,157 @@
+/*
+ * 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 in 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.7.10.4


^ permalink raw reply related	[flat|nested] 19+ 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
                   ` (3 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 4/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 19+ 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] 19+ messages in thread

* [PATCH 6/8] Create entry in man page for btrfs filesystem disk-usage
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (4 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 19+ 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>
---
 man/btrfs.8.in |   13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index e2f86ea..50dc510 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -29,6 +29,9 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem resize\fP\fI [devid:][+/\-]<size>[gkm]|[devid:]max <filesystem>\fP
 .PP
+\fBbtrfs\fP \fBfilesystem filesystem disk-usage [-t][-b]\fP\fI <path> 
+[path..]\fP
+.PP
 \fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
 .PP
 \fBbtrfs\fP \fBfilesystem df\fP\fI [-b] \fIpath [path..]\fR\fP
@@ -251,6 +254,16 @@ it with the new desired size.  When recreating the partition make sure to use
 the same starting disk cylinder as before.
 .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
+
 \fBfilesystem label\fP\fI <dev> [newlabel]\fP
 Show or update the label of a filesystem. \fI<dev>\fR is used to identify the
 filesystem. 
-- 
1.7.10.4


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

* [PATCH 7/8] Add btrfs device disk-usage command
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (5 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-23 13:46 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 19+ 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-device.c        |    3 ++
 cmds-fi-disk_usage.c |  141 ++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-fi-disk_usage.h |    4 ++
 3 files changed, 148 insertions(+)

diff --git a/cmds-device.c b/cmds-device.c
index 198ad68..0dbc02c 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -27,6 +27,7 @@
 #include "ctree.h"
 #include "ioctl.h"
 #include "utils.h"
+#include "cmds-fi-disk_usage.h"
 
 #include "commands.h"
 
@@ -403,6 +404,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 },
 		{ 0, 0, 0, 0, 0 }
 	}
 };
diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c
index eea4168..18350ce 100644
--- a/cmds-fi-disk_usage.c
+++ b/cmds-fi-disk_usage.c
@@ -949,4 +949,145 @@ 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;
+	char *s;
+
+	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 = btrfs_flags2description(flags);
+		r_mode = btrfs_flags2profile(flags);
+		size = calc_chunk_size(chunks_info_ptr+i);
+		s = df_pretty_sizes(size, mode);
+		printf("   %s,%s:%*s%10s\n",
+			description,
+			r_mode,
+			(int)(20 - strlen(description) - strlen(r_mode)), "",
+			s);
+
+		allocated += size;
+
+	}
+	s = df_pretty_sizes(total_size - allocated, mode);
+	printf("   Unallocated: %*s%10s\n",
+		(int)(20 - strlen("Unallocated")), "",
+		s);
+
+}
+
+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++) {
+		char *s;
+
+		s = df_pretty_sizes(disks_info_ptr[i].size, mode);
+		printf("%s\t%10s\n", disks_info_ptr[i].path, s);
+
+		print_disk_chunks(fd, disks_info_ptr[i].devid,
+				disks_info_ptr[i].size,
+				info_ptr, info_count,
+				mode);
+		printf("\n");
+
+	}
+
+
+exit:
+
+	string_list_free();
+	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;
+		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_device_disk_usage(fd, argv[i], flags);
+		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 ae11570..c315004 100644
--- a/cmds-fi-disk_usage.h
+++ b/cmds-fi-disk_usage.h
@@ -21,7 +21,11 @@
 
 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);
 
+extern const char * const cmd_device_disk_usage_usage[];
+int cmd_device_disk_usage(int argc, char **argv);
+
 #endif
-- 
1.7.10.4


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

* [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage.
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (6 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
@ 2013-02-23 13:46 ` Goffredo Baroncelli
  2013-02-25 17:38 ` [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Zach Brown
  2013-02-26 12:55 ` Martin Steigerwald
  9 siblings, 0 replies; 19+ 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>
---
 man/btrfs.8.in |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 50dc510..e60c81f 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -46,6 +46,8 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBdevice delete\fP\fI <device> [<device>...] <path> \fP
 .PP
+\fBbtrfs\fP \fBdevice disk-usage\fP\fI [-b] <path> [<path>...] \fP
+.PP
 \fBbtrfs\fP \fBreplace start\fP \fI[-Bfr] <srcdev>|<devid> <targetdev> <path>\fP
 .PP
 \fBbtrfs\fP \fBreplace status\fP \fI[-1] <path>\fP
@@ -360,6 +362,12 @@ Add device(s) to the filesystem identified by \fI<path>\fR.
 Remove device(s) from a filesystem identified by \fI<path>\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
+
 \fBdevice scan\fR \fI[--all-devices|<device> [<device>...]\fR
 If one or more devices are passed, these are scanned for a btrfs filesystem. 
 If no devices are passed, \fBbtrfs\fR scans all the block devices listed
-- 
1.7.10.4


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

* Re: [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation.
  2013-02-23 13:46 ` [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation Goffredo Baroncelli
@ 2013-02-25  2:20   ` Eric Sandeen
  2013-02-25 19:59     ` Goffredo Baroncelli
  0 siblings, 1 reply; 19+ messages in thread
From: Eric Sandeen @ 2013-02-25  2:20 UTC (permalink / raw)
  To: Goffredo Baroncelli
  Cc: linux-btrfs, Hugo Mills, Michael Kjörling,
	Martin Steigerwald, cwillu, Chris Murphy, David Sterba,
	Zach Brown, Goffredo Baroncelli

On 2/23/13 7:46 AM, Goffredo Baroncelli wrote:
> From: Goffredo Baroncelli <kreijack@inwind.it>
> 
> This patch adds some helpers to manage the strings allocation and
> deallocation.
> The function string_list_add(char *) adds the passed string to a list;
> the function string_list_free() frees all the strings together.

I have to say, I agree with Zach that there are more straightforward
and less error-prone ways to accomplish this same result.

You said:

> your suggestion is not so easy applicable

to Zach's suggestion.  Why do you consider it to be not applicable?
Maybe I am missing some subtlety, but it'd help if you could explain
the problem that you see.

I think that the asymmetry in i.e. _cmd_disk_free where you do:

+	printf("Disk size:\t\t%*s\n", width,
+		df_pretty_sizes(total_disk, mode));
<a few times>
and then:

+	string_list_free();

... because obviously (?)  "df_pretty_sizes" needs this cleanup ...

is unexpected, magic, and error-prone.

-Eric



thanks,
-Eric

> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
> ---
>  Makefile      |    3 ++-
>  string_list.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  string_list.h |   23 +++++++++++++++++++++
>  3 files changed, 88 insertions(+), 1 deletion(-)
>  create mode 100644 string_list.c
>  create mode 100644 string_list.h
> 
> diff --git a/Makefile b/Makefile
> index 596bf93..0d6c43a 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -5,7 +5,8 @@ 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 crc32c.o rbtree.o extent-cache.o extent_io.o \
>  	  volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \
> -	  send-stream.o send-utils.o qgroup.o raid6.o
> +	  send-stream.o send-utils.o qgroup.o raid6.o \
> +	  string_list.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
> diff --git a/string_list.c b/string_list.c
> new file mode 100644
> index 0000000..8d8cc1f
> --- /dev/null
> +++ b/string_list.c
> @@ -0,0 +1,63 @@
> +/*
> + * 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>
> +
> +/* To store the strings */
> +static void **strings_to_free;
> +static int count_string_to_free;
> +
> +/* 
> + * Add a string to the dynamic allocated string list
> + */
> +char *string_list_add(char *s)
> +{
> +	int  size;
> +
> +	size = sizeof(void *) * ++count_string_to_free;
> +	strings_to_free = realloc(strings_to_free, size);
> +
> +	/* if we don't have enough memory, we have more serius
> +	   problem than that a wrong handling of not enough memory */
> +	if (!strings_to_free) {
> +		fprintf(stderr, "add_string_to_free(): Not enough memory\n");
> +		count_string_to_free = 0;
> +		return NULL;
> +	}
> +
> +	strings_to_free[count_string_to_free-1] = s;
> +	return s;
> +}
> +
> +/*
> + * Free the dynamic allocated strings list
> + */
> +void string_list_free()
> +{
> +	int	i;
> +	for (i = 0 ; i < count_string_to_free ; i++)
> +		free(strings_to_free[i]);
> +
> +	free(strings_to_free);
> +
> +	strings_to_free = 0;
> +	count_string_to_free = 0;
> +}
> +
> +
> diff --git a/string_list.h b/string_list.h
> new file mode 100644
> index 0000000..f974fbc
> --- /dev/null
> +++ b/string_list.h
> @@ -0,0 +1,23 @@
> +/*
> + * 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_LIST_H
> +#define STRING_LIST_H
> +
> +void string_list_add(char *s);
> +void string_list_free();
> +
> +#endif
> 


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

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (7 preceding siblings ...)
  2013-02-23 13:46 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
@ 2013-02-25 17:38 ` Zach Brown
  2013-02-26 11:09   ` Martin Steigerwald
  2013-02-26 12:55 ` Martin Steigerwald
  9 siblings, 1 reply; 19+ messages in thread
From: Zach Brown @ 2013-02-25 17:38 UTC (permalink / raw)
  To: Goffredo Baroncelli
  Cc: linux-btrfs, Hugo Mills, Michael Kjörling,
	Martin Steigerwald, cwillu, Chris Murphy, David Sterba

> I updates my previous patches [1] to add support for raid5/6.
> These patches update the btrfs fi df command and add two new commands:
> - btrfs filesystem disk-usage <path>
> - btrfs device disk-usage <path>

This seems like a ton of code.

Here's a thought experiment: What's the smallest possible change that
could communicate the information that people don't have today?

- z

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

* Re: [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation.
  2013-02-25  2:20   ` Eric Sandeen
@ 2013-02-25 19:59     ` Goffredo Baroncelli
  2013-02-25 20:19       ` Zach Brown
  0 siblings, 1 reply; 19+ messages in thread
From: Goffredo Baroncelli @ 2013-02-25 19:59 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-btrfs, Zach Brown

Hi Eric,

On 02/25/2013 03:20 AM, Eric Sandeen wrote:
> On 2/23/13 7:46 AM, Goffredo Baroncelli wrote:
>> From: Goffredo Baroncelli <kreijack@inwind.it>
>>
>> This patch adds some helpers to manage the strings allocation and
>> deallocation.
>> The function string_list_add(char *) adds the passed string to a list;
>> the function string_list_free() frees all the strings together.
> 
> I have to say, I agree with Zach that there are more straightforward
> and less error-prone ways to accomplish this same result.
> 
> You said:
> 
>> your suggestion is not so easy applicable
> 
> to Zach's suggestion.  Why do you consider it to be not applicable?
> Maybe I am missing some subtlety, but it'd help if you could explain
> the problem that you see.

For example try on the following line (is a real example from the
function _cmd_disk_free):

   printf("Disk size:\t\t%*s\n", width,
        df_pretty_sizes(total_disk, mode));

it would be translated (note the '%*s'):

   if (mode == DF_HUMAN_UNIT)
	   printf("Disk size:\t\t%*s%s\n", width-2,
        	df_pretty_sizes_number(total_disk),
		df_pretty_sizes_unit(total_disk));
   else
	   printf("Disk size:\t\t%*lld\n", width, total_disk);


6 lines versus 2: does it make sense ?

> 
> I think that the asymmetry in i.e. _cmd_disk_free where you do:
> 
> +	printf("Disk size:\t\t%*s\n", width,
> +		df_pretty_sizes(total_disk, mode));
> <a few times>
> and then:
> 
> +	string_list_free();
> 
> ... because obviously (?)  "df_pretty_sizes" needs this cleanup ...
> 
> is unexpected, magic, and error-prone.

df_pretty_sizes is not a generic function. There is a reason because it
is _defined_static_. We could improve the function comment (or even
rename the function itself) to point out it better.
It is a facility to avoid to write a lot of equal lines.

However I am open to any suggestion which:
- let the code simple enough
- avoid the duplication of lines.

To avoid all this mess, we should add another conversion specifier with
the function register_printf_function(). Unfortunately I was not able to
find the equivalent one for sprintf().

BR
G.Baroncelli

> 
> -Eric
> 
> 
> 
> thanks,
> -Eric
> 
>> Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
>> ---
>>  Makefile      |    3 ++-
>>  string_list.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  string_list.h |   23 +++++++++++++++++++++
>>  3 files changed, 88 insertions(+), 1 deletion(-)
>>  create mode 100644 string_list.c
>>  create mode 100644 string_list.h
>>
>> diff --git a/Makefile b/Makefile
>> index 596bf93..0d6c43a 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -5,7 +5,8 @@ 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 crc32c.o rbtree.o extent-cache.o extent_io.o \
>>  	  volumes.o utils.o btrfs-list.o btrfslabel.o repair.o \
>> -	  send-stream.o send-utils.o qgroup.o raid6.o
>> +	  send-stream.o send-utils.o qgroup.o raid6.o \
>> +	  string_list.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
>> diff --git a/string_list.c b/string_list.c
>> new file mode 100644
>> index 0000000..8d8cc1f
>> --- /dev/null
>> +++ b/string_list.c
>> @@ -0,0 +1,63 @@
>> +/*
>> + * 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>
>> +
>> +/* To store the strings */
>> +static void **strings_to_free;
>> +static int count_string_to_free;
>> +
>> +/* 
>> + * Add a string to the dynamic allocated string list
>> + */
>> +char *string_list_add(char *s)
>> +{
>> +	int  size;
>> +
>> +	size = sizeof(void *) * ++count_string_to_free;
>> +	strings_to_free = realloc(strings_to_free, size);
>> +
>> +	/* if we don't have enough memory, we have more serius
>> +	   problem than that a wrong handling of not enough memory */
>> +	if (!strings_to_free) {
>> +		fprintf(stderr, "add_string_to_free(): Not enough memory\n");
>> +		count_string_to_free = 0;
>> +		return NULL;
>> +	}
>> +
>> +	strings_to_free[count_string_to_free-1] = s;
>> +	return s;
>> +}
>> +
>> +/*
>> + * Free the dynamic allocated strings list
>> + */
>> +void string_list_free()
>> +{
>> +	int	i;
>> +	for (i = 0 ; i < count_string_to_free ; i++)
>> +		free(strings_to_free[i]);
>> +
>> +	free(strings_to_free);
>> +
>> +	strings_to_free = 0;
>> +	count_string_to_free = 0;
>> +}
>> +
>> +
>> diff --git a/string_list.h b/string_list.h
>> new file mode 100644
>> index 0000000..f974fbc
>> --- /dev/null
>> +++ b/string_list.h
>> @@ -0,0 +1,23 @@
>> +/*
>> + * 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_LIST_H
>> +#define STRING_LIST_H
>> +
>> +void string_list_add(char *s);
>> +void string_list_free();
>> +
>> +#endif
>>
> 
> 


-- 
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] 19+ messages in thread

* Re: [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation.
  2013-02-25 19:59     ` Goffredo Baroncelli
@ 2013-02-25 20:19       ` Zach Brown
  2013-02-25 21:00         ` Goffredo Baroncelli
  0 siblings, 1 reply; 19+ messages in thread
From: Zach Brown @ 2013-02-25 20:19 UTC (permalink / raw)
  To: kreijack; +Cc: Eric Sandeen, linux-btrfs

>    printf("Disk size:\t\t%*s\n", width,
>         df_pretty_sizes(total_disk, mode));
> 
> it would be translated (note the '%*s'):
> 
>    if (mode == DF_HUMAN_UNIT)
> 	   printf("Disk size:\t\t%*s%s\n", width-2,
>         	df_pretty_sizes_number(total_disk),
> 		df_pretty_sizes_unit(total_disk));
>    else
> 	   printf("Disk size:\t\t%*lld\n", width, total_disk);

So use mode as the argument in the second case, just like you did in the
first.

printf("Disk dize:\t\t"sz_fmt"\n", sz_arg(total_disk, mode, width));

#define sz_fmt "%*llu%s"
#define sz_fmt(v,m,w) width(w, m), scaled(v, m), units(v, m)

And again, the reason we jump through these mildly distasteful hoops is
that *it gets rid of allocated strings entirely*.

That bug in df_pretty_sizes() where it allocates a 20 byte buffer to
store a string that can be 21 bytes long with its null?  It'd just
vanish.  Not needed.

The only code that is *sure* to be bug free is the code that doesn't
exist.

> To avoid all this mess, we should add another conversion specifier with
> the function register_printf_function(). Unfortunately I was not able to
> find the equivalent one for sprintf().

Doesn't that prevent compile-time verification that the types of the
format specifiers match the arguments?

- z

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

* Re: [PATCH 1/8] Add some helpers to manage the strings allocation/deallocation.
  2013-02-25 20:19       ` Zach Brown
@ 2013-02-25 21:00         ` Goffredo Baroncelli
  0 siblings, 0 replies; 19+ messages in thread
From: Goffredo Baroncelli @ 2013-02-25 21:00 UTC (permalink / raw)
  To: Zach Brown; +Cc: kreijack, Eric Sandeen, linux-btrfs

On 02/25/2013 09:19 PM, Zach Brown wrote:
>>    printf("Disk size:\t\t%*s\n", width,
>>         df_pretty_sizes(total_disk, mode));
>>
>> it would be translated (note the '%*s'):
>>
>>    if (mode == DF_HUMAN_UNIT)
>> 	   printf("Disk size:\t\t%*s%s\n", width-2,
>>         	df_pretty_sizes_number(total_disk),
>> 		df_pretty_sizes_unit(total_disk));
>>    else
>> 	   printf("Disk size:\t\t%*lld\n", width, total_disk);
> 
> So use mode as the argument in the second case, just like you did in the
> first.
> 
> printf("Disk dize:\t\t"sz_fmt"\n", sz_arg(total_disk, mode, width));

> 
> #define sz_fmt "%*llu%s"
> #define sz_fmt(v,m,w) width(w, m), scaled(v, m), units(v, m)
I suppose s/sz_fmt/sz_arg/

> And again, the reason we jump through these mildly distasteful hoops is
> that *it gets rid of allocated strings entirely*.
I am not entirely convinced, however if you prepare a patch I will
integrate it quickly

> That bug in df_pretty_sizes() where it allocates a 20 byte buffer to
> store a string that can be 21 bytes long with its null?  It'd just
> vanish.  Not needed.
Good catch

>> To avoid all this mess, we should add another conversion specifier with
>> the function register_printf_function(). Unfortunately I was not able to
>> find the equivalent one for sprintf().
> 
> Doesn't that prevent compile-time verification that the types of the
> format specifiers match the arguments?

Yes this was another cons...

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


-- 
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] 19+ messages in thread

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-25 17:38 ` [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Zach Brown
@ 2013-02-26 11:09   ` Martin Steigerwald
  2013-02-26 11:28     ` Gareth Pye
  0 siblings, 1 reply; 19+ messages in thread
From: Martin Steigerwald @ 2013-02-26 11:09 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Zach Brown, Goffredo Baroncelli, Hugo Mills,
	Michael Kjörling, cwillu, Chris Murphy, David Sterba

Am Montag, 25. Februar 2013 schrieb Zach Brown:
> > I updates my previous patches [1] to add support for raid5/6.
> > These patches update the btrfs fi df command and add two new commands:
> > - btrfs filesystem disk-usage <path>
> > - btrfs device disk-usage <path>
> 
> This seems like a ton of code.
> 
> Here's a thought experiment: What's the smallest possible change that
> could communicate the information that people don't have today?

The kind and amount of information output of these additions have been 
discussed several times before.

I found the output provided quite useful. As others.

Free space seems to be a complex matter in BTRFS and one conclusion was that 
its not easily possible to provide a single number to show how much space is 
free.

I´d still like that for df, whose output is quite bogus in certain BTRFS 
setups at the moment and does not give applications a realistic estimate at 
all. One example is raid 1 with 10 GB each disk. Shows 20 GB free. An 
application which wants to write 15 GB will fail. Which can break installer 
scripts, package management, cache software or anything else which checks 
for free space. Thus I´d like df to default to *minimum* free.

But what is it concretely, what you feel uncomfortable with? The Linux 
kernel is also a ton of code.

I´d really like to see Goffredo improvements go in instead of them being 
discussed endlessly. So I´d like to feedback to be as concrete as possible, 
so Goffredo has a chance to work on it.

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

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

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-26 11:09   ` Martin Steigerwald
@ 2013-02-26 11:28     ` Gareth Pye
  2013-02-26 12:58       ` Martin Steigerwald
  0 siblings, 1 reply; 19+ messages in thread
From: Gareth Pye @ 2013-02-26 11:28 UTC (permalink / raw)
  To: Martin Steigerwald
  Cc: linux-btrfs, Zach Brown, Goffredo Baroncelli, Hugo Mills,
	Michael Kjörling, cwillu, Chris Murphy, David Sterba

On Tue, Feb 26, 2013 at 10:09 PM, Martin Steigerwald
<Martin@lichtvoll.de> wrote:
> I´d still like that for df, whose output is quite bogus in certain BTRFS
> setups at the moment and does not give applications a realistic estimate at
> all. One example is raid 1 with 10 GB each disk. Shows 20 GB free. An
> application which wants to write 15 GB will fail. Which can break installer
> scripts, package management, cache software or anything else which checks
> for free space. Thus I´d like df to default to *minimum* free.

Is that any better than the script failing to attempt to install
because it needs 15G but because some of the storage is used in RAID1
then df shows 10G free but the 15G install would work fine. If you
could force the tool to install where it know it doesn't have
sufficient space?


-- 
Gareth Pye
Level 2 Judge, Melbourne, Australia
Australian MTG Forum: mtgau.com
gareth@cerberos.id.au - www.rockpaperdynamite.wordpress.com
"Dear God, I would like to file a bug report"

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

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-23 13:46 [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Goffredo Baroncelli
                   ` (8 preceding siblings ...)
  2013-02-25 17:38 ` [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Zach Brown
@ 2013-02-26 12:55 ` Martin Steigerwald
  9 siblings, 0 replies; 19+ messages in thread
From: Martin Steigerwald @ 2013-02-26 12:55 UTC (permalink / raw)
  To: linux-btrfs
  Cc: Goffredo Baroncelli, Hugo Mills, Michael Kjörling, cwillu,
	Chris Murphy, David Sterba, Zach Brown

Am Samstag, 23. Februar 2013 schrieb Goffredo Baroncelli:
> Hi all,

Hi Goffredo,
 
> I updates my previous patches [1] to add support for raid5/6.
> These patches update the btrfs fi df command and add two new commands:
> - btrfs filesystem disk-usage <path>
> - btrfs device disk-usage <path>

Tested-By: Martin Steigerwald <martin@lichtvoll.de>


Only for -d single and -m single, I have RAID-1 at workstation at work,
but will take some time till I get to office again.

No RAID-5/6 setup at the moment. So test obviously not complete yet.


merkaba:~> /tmp/btrfs fi sh
failed to read /dev/sr0
Label: 'home'  uuid: […]
        Total devices 1 FS bytes used 196.11GB
        devid    1 size 223.52GB used 204.02GB path /dev/dm-2

Label: 'debian'  uuid: […]
        Total devices 1 FS bytes used 10.69GB
        devid    1 size 18.62GB used 17.02GB path /dev/dm-0

Btrfs v0.19-367-g711b24a




/:

merkaba:~> /tmp/btrfs fi df /
Disk size:                18.62GB
Disk allocated:           17.02GB
Disk unallocated:          1.61GB
Used:                     10.69GB
Free (Estimated):          7.93GB       (Max: 7.93GB, min: 7.13GB)
Data to disk ratio:         100 %

merkaba:~> /tmp/btrfs fi disk-usage /
Data,Single: Size:16.01GB, Used:10.14GB
   /dev/dm-0       16.01GB

Metadata,Single: Size:1.01GB, Used:565.34MB
   /dev/dm-0        1.01GB

System,Single: Size:4.00MB, Used:4.00KB
   /dev/dm-0        4.00MB

Unallocated:
   /dev/dm-0        1.61GB

merkaba:~> /tmp/btrfs fi disk-usage -t /
          Data    Metadata System            
          Single  Single   Single Unallocated
                                             
/dev/dm-0 16.01GB   1.01GB 4.00MB      1.61GB
          ======= ======== ====== ===========
Total     16.01GB   1.01GB 4.00MB      1.61GB
Used      10.14GB 565.34MB 4.00KB            

merkaba:~> /tmp/btrfs dev disk-usage /   
/dev/dm-0          18.62GB
   Data,Single:             16.01GB
   Metadata,Single:          1.01GB
   System,Single:            4.00MB
   Unallocated:              1.61GB




/home (quite fresh fs):

merkaba:~#129> /tmp/btrfs fi df /home       
Disk size:               223.52GB
Disk allocated:          204.02GB
Disk unallocated:         19.50GB
Used:                    196.11GB
Free (Estimated):         27.40GB       (Max: 27.40GB, min: 17.66GB)
Data to disk ratio:         100 %

merkaba:~> /tmp/btrfs fi disk-usage /home
Data,Single: Size:202.01GB, Used:194.67GB
   /dev/dm-2      202.01GB

Metadata,Single: Size:2.01GB, Used:1.44GB
   /dev/dm-2        2.01GB

System,Single: Size:4.00MB, Used:48.00KB
   /dev/dm-2        4.00MB

Unallocated:
   /dev/dm-2       19.50GB

merkaba:~> /tmp/btrfs fi disk-usage -t /home
          Data     Metadata System             
          Single   Single   Single  Unallocated
                                               
/dev/dm-2 202.01GB   2.01GB  4.00MB     19.50GB
          ======== ======== ======= ===========
Total     202.01GB   2.01GB  4.00MB     19.50GB
Used      194.67GB   1.44GB 48.00KB            

merkaba:~> /tmp/btrfs dev disk-usage /home  
/dev/dm-2         223.52GB
   Data,Single:            202.01GB
   Metadata,Single:          2.01GB
   System,Single:            4.00MB
   Unallocated:             19.50GB


Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

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

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-26 11:28     ` Gareth Pye
@ 2013-02-26 12:58       ` Martin Steigerwald
  2013-02-26 13:15         ` Martin Steigerwald
  0 siblings, 1 reply; 19+ messages in thread
From: Martin Steigerwald @ 2013-02-26 12:58 UTC (permalink / raw)
  To: linux-btrfs

Am Dienstag, 26. Februar 2013 schrieb Gareth Pye:
> On Tue, Feb 26, 2013 at 10:09 PM, Martin Steigerwald
> 
> <Martin@lichtvoll.de> wrote:
> > I´d still like that for df, whose output is quite bogus in certain
> > BTRFS setups at the moment and does not give applications a realistic
> > estimate at all. One example is raid 1 with 10 GB each disk. Shows 20
> > GB free. An application which wants to write 15 GB will fail. Which
> > can break installer scripts, package management, cache software or
> > anything else which checks for free space. Thus I´d like df to default
> > to *minimum* free.
> 
> Is that any better than the script failing to attempt to install
> because it needs 15G but because some of the storage is used in RAID1
> then df shows 10G free but the 15G install would work fine. If you
> could force the tool to install where it know it doesn't have
> sufficient space?

I do not quite understand your question. In RAID-1 with 10 GB and two disks, 
df will show 20 GB free. If the script needs 15 GB and checks for it it 
would run, but then fail. I would prefer that the script space check bails 
out in that case it is know that there is not enough space available 
anymore.

So or so one can always argue that current free space is just a snapshot of 
the current moment and there is *never* a guarentee that there is enough 
space, cause another application may write to the filesystem at the same 
time.

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

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

* Re: [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support
  2013-02-26 12:58       ` Martin Steigerwald
@ 2013-02-26 13:15         ` Martin Steigerwald
  0 siblings, 0 replies; 19+ messages in thread
From: Martin Steigerwald @ 2013-02-26 13:15 UTC (permalink / raw)
  To: linux-btrfs

Am Dienstag, 26. Februar 2013 schrieb Martin Steigerwald:
> Am Dienstag, 26. Februar 2013 schrieb Gareth Pye:
> > On Tue, Feb 26, 2013 at 10:09 PM, Martin Steigerwald
> > 
> > <Martin@lichtvoll.de> wrote:
> > > I´d still like that for df, whose output is quite bogus in certain
> > > BTRFS setups at the moment and does not give applications a realistic
> > > estimate at all. One example is raid 1 with 10 GB each disk. Shows 20
> > > GB free. An application which wants to write 15 GB will fail. Which
> > > can break installer scripts, package management, cache software or
> > > anything else which checks for free space. Thus I´d like df to
> > > default to *minimum* free.
> > 
> > Is that any better than the script failing to attempt to install
> > because it needs 15G but because some of the storage is used in RAID1
> > then df shows 10G free but the 15G install would work fine. If you
> > could force the tool to install where it know it doesn't have
> > sufficient space?
> 
> I do not quite understand your question. In RAID-1 with 10 GB and two
> disks, df will show 20 GB free. If the script needs 15 GB and checks for
> it it would run, but then fail. I would prefer that the script space
> check bails out in that case it is know that there is not enough space
> available anymore.

Well, okay, and exactly that is not known, cause if the files the installer 
script are installed are stored a single instead of RAID-1 there would be 
enough space.

Anyway for the additions Goffredo made I strongly suggest reading the old 
discussions before starting to discuss stuff that has already been discussed 
back then.

-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

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

end of thread, other threads:[~2013-02-26 13:15 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 1/8] Add some helpers to manage the strings allocation/deallocation Goffredo Baroncelli
2013-02-25  2:20   ` Eric Sandeen
2013-02-25 19:59     ` Goffredo Baroncelli
2013-02-25 20:19       ` Zach Brown
2013-02-25 21:00         ` Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 2/8] Enhance the command btrfs filesystem df Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 3/8] Create the man page entry for the command btrfs fi df Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 4/8] Add helpers functions to handle the printing of data in tabular format Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 5/8] Add command btrfs filesystem disk-usage Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 6/8] Create entry in man page for " Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 7/8] Add btrfs device disk-usage command Goffredo Baroncelli
2013-02-23 13:46 ` [PATCH 8/8] Create a new entry in btrfs man page for btrfs device disk-usage Goffredo Baroncelli
2013-02-25 17:38 ` [PATCH V2][BTRFS-PROGS] Enhance btrfs fi df with raid5/6 support Zach Brown
2013-02-26 11:09   ` Martin Steigerwald
2013-02-26 11:28     ` Gareth Pye
2013-02-26 12:58       ` Martin Steigerwald
2013-02-26 13:15         ` Martin Steigerwald
2013-02-26 12:55 ` Martin Steigerwald

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.