A sample tool how to use the new ioctl

2011-12-19 Thread David Sterba
This is a standalone tool I've used to exercise the ioctl, simply pass
the name of a file and see the result. The numbers are a rough
estimate. It also takes the range arguments, but the ratio will be bogus
due to comparison to whole file (st_blocks), an exact extent length
from fiemap/filefrag is be the correct one.


david

/*
 * 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 sys/ioctl.h
#include sys/stat.h
#include fcntl.h
#include dirent.h
#include stdlib.h
#include stdio.h
#include string.h
#include inttypes.h

typedef uint64_t __u64;
typedef uint64_t u64;

#ifndef BTRFS_IOCTL_MAGIC
#define BTRFS_IOCTL_MAGIC 0x94
#endif

#ifndef BTRFS_IOC_COMPR_SIZE
#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
		struct __local__btrfs_ioctl_compr_size_args)
#endif

struct __local__btrfs_ioctl_compr_size_args {
	/* Range start, inclusive */
	__u64   start;  /* in */
	/* Range end, exclusive */
	__u64   end;/* in */
	__u64   size;   /* out */
	__u64   reserved[2];
};

static u64 parse_size(char *s)
{
	int len = strlen(s);
	char c;
	u64 mult = 1;

	if (!isdigit(s[len - 1])) {
		c = tolower(s[len - 1]);
		switch (c) {
			case 'e':
			case 'E':
mult *= 1024;
			case 't':
			case 'T':
mult *= 1024;
			case 'g':
			case 'G':
mult *= 1024;
			case 'm':
			case 'M':
mult *= 1024;
			case 'k':
			case 'K':
mult *= 1024;
			case 'b':
			case 'B':
break;
			default:
fprintf(stderr, Unknown size descriptor %c\n, c);
exit(1);
		}
		s[len - 1] = '\0';
	}
	return atoll(s) * mult;
}

static int open_file_or_dir(const char *fname)
{
	int ret;
	struct stat st;
	DIR *dirstream;
	int fd;

	ret = stat(fname, st);
	if (ret  0) {
		perror(stat);
		exit(1);
	}
	if (S_ISDIR(st.st_mode)) {
		dirstream = opendir(fname);
		if (!dirstream) {
			perror(opendir);
			exit(1);
		}
		fd = dirfd(dirstream);
	} else {
		fd = open(fname, O_RDONLY);
	}
	if (fd  0) {
		perror(open);
		exit(1);
	}
	return fd;
}
static char buf[64];
static const char* end_or_eof(u64 end)
{
	if (end == (u64)-1)
		return EOF;
	snprintf(buf, 64, %llu, (unsigned long long)end);
	return buf;
}

int main(int argc, char **argv)
{
	int fd;
	int ret;
	u64 cblocks;
	unsigned long sblocks;
	struct stat st;
	struct __local__btrfs_ioctl_compr_size_args args;

	if (argc  2) {
		printf(Usage: btrfs-compr-size file [start [end] ]\n);
		exit(1);
	}

	fd = open_file_or_dir(argv[1]);
	if (fd == -1) {
		perror(open);
		exit(1);
	}

	if (argc = 3)
		args.start = parse_size(argv[2]);
	else
		args.start = 0;

	if (argc = 4)
		args.end = parse_size(argv[3]);
	else
		args.end = (u64)-1;

	ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, args);
	if (ret  0) {
		perror(ioctl);
		exit(1);
	}
	fstat(fd, st);
	cblocks=args.size;
	sblocks=st.st_blocks;
	printf(Compressed size of %s [%llu,%s)\n, argv[1],
			(unsigned long long)args.start,
			end_or_eof(args.end));
	printf( compr size/512:  % 11lu\n, cblocks);
	printf( stat blocks/512: % 11lu\n, sblocks);
	if (sblocks)
		printf( compr/stat*100:  % 14.2f%%\n, (((float)cblocks) / sblocks) * 100);
	else
		printf( compr/stat*100:  % 14.2f%%\n, (float)0);
	return 0;
}


Re: A sample tool how to use the new ioctl

2011-12-19 Thread Chris Mason
On Mon, Dec 19, 2011 at 03:25:39PM +0100, David Sterba wrote:
 This is a standalone tool I've used to exercise the ioctl, simply pass
 the name of a file and see the result. The numbers are a rough
 estimate. It also takes the range arguments, but the ratio will be bogus
 due to comparison to whole file (st_blocks), an exact extent length
 from fiemap/filefrag is be the correct one.

Thanks Dave.

Could you please add this to btrfs filesystem stat filename

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


Re: A sample tool how to use the new ioctl

2011-12-19 Thread David Sterba
On Mon, Dec 19, 2011 at 09:47:06AM -0500, Chris Mason wrote:
 On Mon, Dec 19, 2011 at 03:25:39PM +0100, David Sterba wrote:
  This is a standalone tool I've used to exercise the ioctl, simply pass
 Could you please add this to btrfs filesystem stat filename

Here it is, but I haven't really thought about the userspace interface and
calling it 'stat' just for reading compressed size does not seem right (and I
have renamed to 'csize' for now).

I will extend the ioctl to return the uncompressed size as well, it is provided
by the extent anyway. The original implementation returned just one u64 for the
whole file, I did the range-aware version because the lock_extent blocked for a
long time when the file was being modified and it could be avoided. However I
missed the options to utilize the information provided by the extents,
so this is not a final version.

From: David Sterba dste...@suse.cz

Signed-off-by: David Sterba dste...@suse.cz
---
 btrfs.c  |9 -
 btrfs_cmds.c |   53 +
 btrfs_cmds.h |1 +
 ioctl.h  |   11 +++
 4 files changed, 73 insertions(+), 1 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 1def354..5ce207a 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -128,7 +128,14 @@ static struct Command commands[] = {
  filesystem label, device [newlabel]\n
  With one argument, get the label of filesystem on device.\n
  If newlabel is passed, set the filesystem label to newlabel.\n
- The filesystem must be unmounted.\n
+ The filesystem must be unmounted.
+   },
+   { do_compr_size, -1,
+ filesystem csize, [-s start] [-e end] file\n
+ Read compressed size of extents in the range [start,end)\n
+ -s start  range start inclusive\n
+ -e endrange end exclusive\n,
+ NULL
},
{ do_scrub_start, -1,
  scrub start, [-Bdqr] path|device\n
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..4c8bf5c 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1305,3 +1305,56 @@ out:
free(inodes);
return ret;
 }
+
+int do_compr_size(int argc, char **argv)
+{
+   int ret;
+   int fd;
+   struct btrfs_ioctl_compr_size_args args;
+
+   args.start = 0;
+   args.end = (u64)-1;
+   optind = 1;
+   while (1) {
+   int c = getopt(argc, argv, s:e:);
+   if (c  0)
+   break;
+   switch (c) {
+   case 's':
+   args.start = parse_size(optarg);
+   break;
+   case 'e':
+   args.end = parse_size(optarg);
+   break;
+   default:
+   fprintf(stderr, ERROR: Invalid arguments for csize\n);
+   return 1;
+   }
+   }
+
+   if (args.start  args.end) {
+   fprintf(stderr, ERROR: Invalid range for csize\n);
+   return 1;
+   }
+
+   if (argc - optind == 0) {
+   fprintf(stderr, ERROR: Invalid arguments for csize\n);
+   return 1;
+   }
+   argc -= optind;
+
+   fd = open_file_or_dir(argv[optind]);
+   if (fd  0) {
+   fprintf(stderr, ERROR: can't access '%s'\n, argv[optind]);
+   return 1;
+   }
+
+   ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, args);
+   if (ret  0) {
+   fprintf(stderr, ERROR: ioctl returned %d, errno %d %s\n, ret, 
errno, strerror(errno));
+   return errno;
+   }
+
+   printf(Compressed size: %llu\n, args.size  9);
+   return 0;
+}
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 81182b1..d171214 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -42,3 +42,4 @@ int open_file_or_dir(const char *fname);
 int do_ino_to_path(int nargs, char **argv);
 int do_logical_to_ino(int nargs, char **argv);
 char *path_for_root(int fd, u64 root);
+int do_compr_size(int argc, char **argv);
diff --git a/ioctl.h b/ioctl.h
index 1ae7537..792ffc0 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -224,6 +224,15 @@ struct btrfs_ioctl_logical_ino_args {
__u64   inodes;
 };
 
+struct btrfs_ioctl_compr_size_args {
+   /* Range start, inclusive */
+   __u64   start;  /* in */
+   /* Range end, exclusive */
+   __u64   end;/* in */
+   __u64   size;   /* out */
+   __u64   reserved[2];
+};
+
 /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
   struct btrfs_ioctl_vol_args)
@@ -277,5 +286,7 @@ struct btrfs_ioctl_logical_ino_args {
struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \