linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Roman Mamedov <rm@romanrm.net>
To: kreijack@inwind.it
Cc: kreijack@libero.it, linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 5/8] Add command btrfs filesystem disk-usage
Date: Fri, 14 Feb 2014 01:28:10 +0600	[thread overview]
Message-ID: <20140214012810.26297146@natsu> (raw)
In-Reply-To: <52FD1AD6.50500@libero.it>

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

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

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

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

-- 
With respect,
Roman

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

  reply	other threads:[~2014-02-13 19:28 UTC|newest]

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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140214012810.26297146@natsu \
    --to=rm@romanrm.net \
    --cc=kreijack@inwind.it \
    --cc=kreijack@libero.it \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).