All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs: add new ioctl to determine size of compressed file
@ 2011-12-19 14:17 David Sterba
  2011-12-19 14:25 ` A sample tool how to use the new ioctl David Sterba
  2011-12-20  1:33 ` [PATCH] btrfs: add new ioctl to determine size of compressed file Liu Bo
  0 siblings, 2 replies; 10+ messages in thread
From: David Sterba @ 2011-12-19 14:17 UTC (permalink / raw)
  To: linux-btrfs; +Cc: chris.mason, David Sterba

Go through all extents of a file in a given [start,end) range and sum
for:
* regular extent: ->block_len, size is already rounded up to blocks
* inline extents: length rounded up to 512

The range is start inclusive / end exclusive. For the whole file pass
0 and (u64)-1.

The resulting value is number of occupied 512B sectors so this can
be easily compared to stat.st_blocks to determine rough compression
ratio of a file.

Based on implementation from Ulrich Hecht,
http://comments.gmane.org/gmane.comp.file-systems.btrfs/6253

Signed-off-by: David Sterba <dsterba@suse.cz>
---
 fs/btrfs/ioctl.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/ioctl.h |   11 +++++++
 2 files changed, 88 insertions(+), 0 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index c04f02c..82c3810 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2972,6 +2972,81 @@ static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
 	return 0;
 }
 
+/*
+ * Returns the compressed size of an inode in 512 byte blocks.
+ * Count the on-disk space used by extents starting in range [start, end),
+ * inline data are rounded up to sector, ie. 512.
+ *
+ * The range is start inclusive and end exclusive so it can be used to
+ * determine compressed size of a given extent by its start and start of the
+ * next extent easily, without counting length.
+ * Whole file is specified as start = 0, end = (u64)-1
+ */
+static long btrfs_ioctl_compr_size(struct file *file, void __user *argp)
+{
+	struct inode *inode = fdentry(file)->d_inode;
+	struct btrfs_ioctl_compr_size_args compr_args;
+	u64 len;
+	u64 compressed_size = 0;
+	u64 offset = 0;
+
+	if (S_ISDIR(inode->i_mode))
+		return -EISDIR;
+
+	if (copy_from_user(&compr_args, argp,
+				sizeof(struct btrfs_ioctl_compr_size_args)))
+		return -EFAULT;
+
+	if (compr_args.start > compr_args.end)
+		return -EINVAL;
+
+	mutex_lock(&inode->i_mutex);
+
+	offset = compr_args.start;
+	if (inode->i_size > compr_args.end)
+		len = compr_args.end;
+	else
+		len = inode->i_size;
+
+	/*
+	 * do any pending delalloc/csum calc on inode, one way or
+	 * another, and lock file content
+	 */
+	btrfs_wait_ordered_range(inode, compr_args.start, len);
+
+	while (offset < len) {
+		struct extent_map *em;
+
+		em = btrfs_get_extent(inode, NULL, 0, offset, 1, 0);
+		if (IS_ERR_OR_NULL(em))
+			goto error;
+		if (em->block_len != (u64)-1)
+			compressed_size += em->block_len;
+		else if (em->block_start == EXTENT_MAP_INLINE) {
+			compressed_size += ALIGN(em->len, 512);
+		}
+		offset += em->len;
+		free_extent_map(em);
+	}
+	mutex_unlock(&inode->i_mutex);
+
+	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
+
+	compr_args.size = compressed_size >> 9;
+
+	if (copy_to_user(argp, &compr_args, sizeof(struct
+					btrfs_ioctl_compr_size_args)))
+		return -EFAULT;
+
+	return 0;
+
+error:
+	mutex_unlock(&inode->i_mutex);
+	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
+
+	return -EIO;
+}
+
 static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
 					void __user *arg)
 {
@@ -3110,6 +3185,8 @@ long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_scrub_cancel(root, argp);
 	case BTRFS_IOC_SCRUB_PROGRESS:
 		return btrfs_ioctl_scrub_progress(root, argp);
+	case BTRFS_IOC_COMPR_SIZE:
+		return btrfs_ioctl_compr_size(file, argp);
 	}
 
 	return -ENOTTY;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 252ae99..bce761c 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -217,6 +217,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];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
 				   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -276,5 +285,7 @@ struct btrfs_ioctl_logical_ino_args {
 					struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
 					struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+				struct btrfs_ioctl_compr_size_args)
 
 #endif
-- 
1.7.7.3


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

* A sample tool how to use the new ioctl
  2011-12-19 14:17 [PATCH] btrfs: add new ioctl to determine size of compressed file David Sterba
@ 2011-12-19 14:25 ` David Sterba
  2011-12-19 14:47   ` Chris Mason
  2011-12-20  1:33 ` [PATCH] btrfs: add new ioctl to determine size of compressed file Liu Bo
  1 sibling, 1 reply; 10+ messages in thread
From: David Sterba @ 2011-12-19 14:25 UTC (permalink / raw)
  To: David Sterba; +Cc: linux-btrfs, chris.mason

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

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


[-- Attachment #2: btrfs-compr-size.c --]
[-- Type: text/x-c++src, Size: 3562 bytes --]

/*
 * 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;
}

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

* Re: A sample tool how to use the new ioctl
  2011-12-19 14:25 ` A sample tool how to use the new ioctl David Sterba
@ 2011-12-19 14:47   ` Chris Mason
  2011-12-19 17:27     ` David Sterba
  2011-12-20 17:49     ` [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file David Sterba
  0 siblings, 2 replies; 10+ messages in thread
From: Chris Mason @ 2011-12-19 14:47 UTC (permalink / raw)
  To: David Sterba; +Cc: linux-btrfs

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

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

* Re: A sample tool how to use the new ioctl
  2011-12-19 14:47   ` Chris Mason
@ 2011-12-19 17:27     ` David Sterba
  2011-12-20 17:49     ` [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file David Sterba
  1 sibling, 0 replies; 10+ messages in thread
From: David Sterba @ 2011-12-19 17:27 UTC (permalink / raw)
  To: Chris Mason, David Sterba, linux-btrfs

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 <dsterba@suse.cz>

Signed-off-by: David Sterba <dsterba@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 end    range 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, \
 					struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+		                struct btrfs_ioctl_compr_size_args)
 
 #endif
-- 
1.7.7.3


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

* Re: [PATCH] btrfs: add new ioctl to determine size of compressed file
  2011-12-19 14:17 [PATCH] btrfs: add new ioctl to determine size of compressed file David Sterba
  2011-12-19 14:25 ` A sample tool how to use the new ioctl David Sterba
@ 2011-12-20  1:33 ` Liu Bo
  2011-12-20 17:26   ` David Sterba
  2011-12-20 17:46   ` [PATCH V2] " David Sterba
  1 sibling, 2 replies; 10+ messages in thread
From: Liu Bo @ 2011-12-20  1:33 UTC (permalink / raw)
  To: David Sterba; +Cc: linux-btrfs, chris.mason

On 12/19/2011 10:17 PM, David Sterba wrote:
> Go through all extents of a file in a given [start,end) range and sum
> for:
> * regular extent: ->block_len, size is already rounded up to blocks
> * inline extents: length rounded up to 512
> 
> The range is start inclusive / end exclusive. For the whole file pass
> 0 and (u64)-1.
> 
> The resulting value is number of occupied 512B sectors so this can
> be easily compared to stat.st_blocks to determine rough compression
> ratio of a file.
> 
> Based on implementation from Ulrich Hecht,
> http://comments.gmane.org/gmane.comp.file-systems.btrfs/6253
> 
> Signed-off-by: David Sterba <dsterba@suse.cz>
> ---
>  fs/btrfs/ioctl.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/btrfs/ioctl.h |   11 +++++++
>  2 files changed, 88 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index c04f02c..82c3810 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -2972,6 +2972,81 @@ static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
>  	return 0;
>  }
>  
> +/*
> + * Returns the compressed size of an inode in 512 byte blocks.
> + * Count the on-disk space used by extents starting in range [start, end),
> + * inline data are rounded up to sector, ie. 512.
> + *
> + * The range is start inclusive and end exclusive so it can be used to
> + * determine compressed size of a given extent by its start and start of the
> + * next extent easily, without counting length.
> + * Whole file is specified as start = 0, end = (u64)-1
> + */
> +static long btrfs_ioctl_compr_size(struct file *file, void __user *argp)
> +{
> +	struct inode *inode = fdentry(file)->d_inode;
> +	struct btrfs_ioctl_compr_size_args compr_args;
> +	u64 len;
> +	u64 compressed_size = 0;
> +	u64 offset = 0;
> +
> +	if (S_ISDIR(inode->i_mode))
> +		return -EISDIR;
> +
> +	if (copy_from_user(&compr_args, argp,
> +				sizeof(struct btrfs_ioctl_compr_size_args)))
> +		return -EFAULT;
> +
> +	if (compr_args.start > compr_args.end)
> +		return -EINVAL;
> +
> +	mutex_lock(&inode->i_mutex);
> +
> +	offset = compr_args.start;
> +	if (inode->i_size > compr_args.end)
> +		len = compr_args.end;
> +	else
> +		len = inode->i_size;
> +
> +	/*
> +	 * do any pending delalloc/csum calc on inode, one way or
> +	 * another, and lock file content
> +	 */
> +	btrfs_wait_ordered_range(inode, compr_args.start, len);
> +


missing a lock_extent() ?
and we may adjust i_mutex and [un]lock_extent.

thanks,
liubo

> +	while (offset < len) {
> +		struct extent_map *em;
> +
> +		em = btrfs_get_extent(inode, NULL, 0, offset, 1, 0);
> +		if (IS_ERR_OR_NULL(em))
> +			goto error;
> +		if (em->block_len != (u64)-1)
> +			compressed_size += em->block_len;
> +		else if (em->block_start == EXTENT_MAP_INLINE) {
> +			compressed_size += ALIGN(em->len, 512);
> +		}
> +		offset += em->len;
> +		free_extent_map(em);
> +	}
> +	mutex_unlock(&inode->i_mutex);
> +
> +	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
> +
> +	compr_args.size = compressed_size >> 9;
> +
> +	if (copy_to_user(argp, &compr_args, sizeof(struct
> +					btrfs_ioctl_compr_size_args)))
> +		return -EFAULT;
> +
> +	return 0;
> +
> +error:
> +	mutex_unlock(&inode->i_mutex);
> +	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
> +
> +	return -EIO;
> +}
> +
>  static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
>  					void __user *arg)
>  {
> @@ -3110,6 +3185,8 @@ long btrfs_ioctl(struct file *file, unsigned int
>  		return btrfs_ioctl_scrub_cancel(root, argp);
>  	case BTRFS_IOC_SCRUB_PROGRESS:
>  		return btrfs_ioctl_scrub_progress(root, argp);
> +	case BTRFS_IOC_COMPR_SIZE:
> +		return btrfs_ioctl_compr_size(file, argp);
>  	}
>  
>  	return -ENOTTY;
> diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
> index 252ae99..bce761c 100644
> --- a/fs/btrfs/ioctl.h
> +++ b/fs/btrfs/ioctl.h
> @@ -217,6 +217,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];
> +};
> +
>  #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
>  				   struct btrfs_ioctl_vol_args)
>  #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
> @@ -276,5 +285,7 @@ struct btrfs_ioctl_logical_ino_args {
>  					struct btrfs_ioctl_ino_path_args)
>  #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
>  					struct btrfs_ioctl_ino_path_args)
> +#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
> +				struct btrfs_ioctl_compr_size_args)
>  
>  #endif


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

* Re: [PATCH] btrfs: add new ioctl to determine size of compressed file
  2011-12-20  1:33 ` [PATCH] btrfs: add new ioctl to determine size of compressed file Liu Bo
@ 2011-12-20 17:26   ` David Sterba
  2011-12-20 17:46   ` [PATCH V2] " David Sterba
  1 sibling, 0 replies; 10+ messages in thread
From: David Sterba @ 2011-12-20 17:26 UTC (permalink / raw)
  To: Liu Bo; +Cc: David Sterba, linux-btrfs, chris.mason

On Tue, Dec 20, 2011 at 09:33:06AM +0800, Liu Bo wrote:
> > +static long btrfs_ioctl_compr_size(struct file *file, void __user *argp)
> > +{
> > +	struct inode *inode = fdentry(file)->d_inode;
> > +	struct btrfs_ioctl_compr_size_args compr_args;
> > +	u64 len;
> > +	u64 compressed_size = 0;
> > +	u64 offset = 0;
> > +
> > +	if (S_ISDIR(inode->i_mode))
> > +		return -EISDIR;
> > +
> > +	if (copy_from_user(&compr_args, argp,
> > +				sizeof(struct btrfs_ioctl_compr_size_args)))
> > +		return -EFAULT;
> > +
> > +	if (compr_args.start > compr_args.end)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&inode->i_mutex);
> > +
> > +	offset = compr_args.start;
> > +	if (inode->i_size > compr_args.end)
> > +		len = compr_args.end;
> > +	else
> > +		len = inode->i_size;
> > +
> > +	/*
> > +	 * do any pending delalloc/csum calc on inode, one way or
> > +	 * another, and lock file content
> > +	 */
> > +	btrfs_wait_ordered_range(inode, compr_args.start, len);
> > +
> 
> missing a lock_extent() ?

yeah right, thanks, it was missing even in the original implementation
and was left unnoticed.

> and we may adjust i_mutex and [un]lock_extent.

adjusted which way? I have swapped order of unlock_extent/mutex_unlock
as it was in the wrong order wrt locking. I'll send V2 in a minute.


thanks,
david

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

* [PATCH V2] btrfs: add new ioctl to determine size of compressed file
  2011-12-20  1:33 ` [PATCH] btrfs: add new ioctl to determine size of compressed file Liu Bo
  2011-12-20 17:26   ` David Sterba
@ 2011-12-20 17:46   ` David Sterba
  1 sibling, 0 replies; 10+ messages in thread
From: David Sterba @ 2011-12-20 17:46 UTC (permalink / raw)
  To: linux-btrfs; +Cc: liubo2009, chris.mason, David Sterba

Go through all extents of a file in a given [start,end) range and sum
for:
* regular extent: ->block_len, size is already rounded up to blocks
* inline extents: length rounded up to 512

The range is start inclusive / end exclusive. For whole a file pass
0 and (u64)-1.

The values returned are number of occupied 512B sectors for uncompressed
and compressed size and  can be easily compared to determine rough
compression ratio of the given file range.

Based on implementation from Ulrich Hecht,
http://comments.gmane.org/gmane.comp.file-systems.btrfs/6253

Signed-off-by: David Sterba <dsterba@suse.cz>
---
V1-V2:
* count uncompressed length as well
* add missed lock_extent
* properly ordered unlocking sequence of mutex and extent

 fs/btrfs/ioctl.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/ioctl.h |   12 ++++++++
 2 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index c04f02c..4e058d7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2972,6 +2972,86 @@ static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx)
 	return 0;
 }
 
+/*
+ * Returns the compressed size of an inode in 512 byte blocks.
+ * Count the on-disk space used by extents starting in range [start, end),
+ * inline data are rounded up to sector, ie. 512.
+ *
+ * The range is start inclusive and end exclusive so it can be used to
+ * determine compressed size of a given extent by its start and start of the
+ * next extent easily, without counting length.
+ * Whole file is specified as start = 0, end = (u64)-1
+ */
+static long btrfs_ioctl_compr_size(struct file *file, void __user *argp)
+{
+	struct inode *inode = fdentry(file)->d_inode;
+	struct btrfs_ioctl_compr_size_args compr_args;
+	u64 len;
+	u64 compressed_size = 0;
+	u64 size = 0;
+	u64 offset = 0;
+
+	if (S_ISDIR(inode->i_mode))
+		return -EISDIR;
+
+	if (copy_from_user(&compr_args, argp,
+				sizeof(struct btrfs_ioctl_compr_size_args)))
+		return -EFAULT;
+
+	if (compr_args.start > compr_args.end)
+		return -EINVAL;
+
+	mutex_lock(&inode->i_mutex);
+
+	offset = compr_args.start;
+	if (inode->i_size > compr_args.end)
+		len = compr_args.end;
+	else
+		len = inode->i_size;
+
+	/*
+	 * do any pending delalloc/csum calc on inode, one way or
+	 * another, and lock file content
+	 */
+	btrfs_wait_ordered_range(inode, compr_args.start, len);
+
+	lock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
+
+	while (offset < len) {
+		struct extent_map *em;
+
+		em = btrfs_get_extent(inode, NULL, 0, offset, 1, 0);
+		if (IS_ERR_OR_NULL(em))
+			goto error;
+		if (em->block_len != (u64)-1) {
+			compressed_size += em->block_len;
+			size += ALIGN(em->len, inode->i_sb->s_blocksize);
+		} else if (em->block_start == EXTENT_MAP_INLINE) {
+			compressed_size += ALIGN(em->len, 512);
+			size += ALIGN(em->len, 512);
+		}
+		offset += em->len;
+		free_extent_map(em);
+	}
+	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
+	mutex_unlock(&inode->i_mutex);
+
+	compr_args.size = size >> 9;
+	compr_args.compressed_size = compressed_size >> 9;
+
+	if (copy_to_user(argp, &compr_args,
+				sizeof(struct btrfs_ioctl_compr_size_args)))
+		return -EFAULT;
+
+	return 0;
+
+error:
+	unlock_extent(&BTRFS_I(inode)->io_tree, compr_args.start, len, GFP_NOFS);
+	mutex_unlock(&inode->i_mutex);
+
+	return -EIO;
+}
+
 static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
 					void __user *arg)
 {
@@ -3110,6 +3190,8 @@ long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_scrub_cancel(root, argp);
 	case BTRFS_IOC_SCRUB_PROGRESS:
 		return btrfs_ioctl_scrub_progress(root, argp);
+	case BTRFS_IOC_COMPR_SIZE:
+		return btrfs_ioctl_compr_size(file, argp);
 	}
 
 	return -ENOTTY;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 252ae99..d7b425a 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -217,6 +217,16 @@ 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	compressed_size;		/* out */
+	__u64	reserved[2];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
 				   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -276,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, \
 					struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+				struct btrfs_ioctl_compr_size_args)
 
 #endif
-- 
1.7.6.233.gd79bc


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

* [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file
  2011-12-19 14:47   ` Chris Mason
  2011-12-19 17:27     ` David Sterba
@ 2011-12-20 17:49     ` David Sterba
  2011-12-20 20:32       ` Goffredo Baroncelli
  1 sibling, 1 reply; 10+ messages in thread
From: David Sterba @ 2011-12-20 17:49 UTC (permalink / raw)
  To: linux-btrfs; +Cc: chris.mason, David Sterba

Signed-off-by: David Sterba <dsterba@suse.cz>
---
V1-V2:
* match current kernel side and print uncompressed length as well
* now it's easy to print the compression ratio for the given range

 btrfs.c      |    9 ++++++-
 btrfs_cmds.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 btrfs_cmds.h |    1 +
 ioctl.h      |   13 +++++++++++
 4 files changed, 90 insertions(+), 1 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 1def354..dbb7224 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 ordinary and compressed size of extents in the range [start,end)\n"
+		  "-s start  range start inclusive, accepts K/M/G modifiers\n"
+		  "-e end    range end exclusive, accepts K/M/G modifiers\n",
+	  NULL
 	},
 	{ do_scrub_start, -1,
 	  "scrub start", "[-Bdqr] <path>|<device>\n"
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..1074ade 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1305,3 +1305,71 @@ 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:r");
+		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("File name: %s\n", argv[optind]);
+	if (args.end == (u64)-1)
+		printf("File range:        %llu-EOF\n",
+				(unsigned long long)args.start);
+	else
+		printf("File range:        %llu-%llu\n",
+				(unsigned long long)args.start,
+				(unsigned long long)args.end);
+
+	printf("Compressed size:   %llu\n",
+			(unsigned long long)(args.compressed_size << 9));
+	printf("Uncompressed size: %llu\n",
+			(unsigned long long)(args.size << 9));
+	printf("Ratio:             %3.2f%%\n",
+			100.0 * args.compressed_size / args.size);
+	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..5b5208a 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -224,6 +224,17 @@ 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   compressed_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 +288,7 @@ struct btrfs_ioctl_logical_ino_args {
 					struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
 					struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+		                struct btrfs_ioctl_compr_size_args)
 
 #endif
-- 
1.7.7.3


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

* Re: [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file
  2011-12-20 17:49     ` [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file David Sterba
@ 2011-12-20 20:32       ` Goffredo Baroncelli
  2012-01-06 18:21         ` [PATCH v3] " David Sterba
  0 siblings, 1 reply; 10+ messages in thread
From: Goffredo Baroncelli @ 2011-12-20 20:32 UTC (permalink / raw)
  To: David Sterba; +Cc: linux-btrfs, chris.mason

Hi David

On Tuesday, 20 December, 2011 18:49:58 David Sterba wrote:
> Signed-off-by: David Sterba <dsterba@suse.cz>
> ---
> V1-V2:
> * match current kernel side and print uncompressed length as well
> * now it's easy to print the compression ratio for the given range
> 
>  btrfs.c      |    9 ++++++-
>  btrfs_cmds.c |   68
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ btrfs_cmds.h |  
>  1 +
>  ioctl.h      |   13 +++++++++++

Please, update the man page too

>  4 files changed, 90 insertions(+), 1 deletions(-)
> 
> diff --git a/btrfs.c b/btrfs.c
> index 1def354..dbb7224 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 ordinary and compressed size of extents in the range
> [start,end)\n" +		  "-s start  range start inclusive, accepts K/M/G
> modifiers\n"
> +		  "-e end    range end exclusive, accepts K/M/G modifiers\n",
> +	  NULL
>  	},
>  	{ do_scrub_start, -1,
>  	  "scrub start", "[-Bdqr] <path>|<device>\n"
> diff --git a/btrfs_cmds.c b/btrfs_cmds.c
> index b59e9cb..1074ade 100644
> --- a/btrfs_cmds.c
> +++ b/btrfs_cmds.c
> @@ -1305,3 +1305,71 @@ 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:r");
> +		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("File name: %s\n", argv[optind]);
> +	if (args.end == (u64)-1)
> +		printf("File range:        %llu-EOF\n",
> +				(unsigned long long)args.start);
> +	else
> +		printf("File range:        %llu-%llu\n",
> +				(unsigned long long)args.start,
> +				(unsigned long long)args.end);
> +
> +	printf("Compressed size:   %llu\n",
> +			(unsigned long long)(args.compressed_size << 9));
> +	printf("Uncompressed size: %llu\n",
> +			(unsigned long long)(args.size << 9));
> +	printf("Ratio:             %3.2f%%\n",
> +			100.0 * args.compressed_size / args.size);
> +	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..5b5208a 100644
> --- a/ioctl.h
> +++ b/ioctl.h
> @@ -224,6 +224,17 @@ 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   compressed_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 +288,7 @@ struct btrfs_ioctl_logical_ino_args {
>  					struct btrfs_ioctl_ino_path_args)
>  #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
>  					struct btrfs_ioctl_ino_path_args)
> +#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
> +		                struct btrfs_ioctl_compr_size_args)
> 
>  #endif
-- 
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack@inwind.it>
Key fingerprint = 4769 7E51 5293 D36C 814E  C054 BF04 F161 3DC5 0512

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

* [PATCH v3] btrfs-progs: Add ioctl to read compressed size of a file
  2011-12-20 20:32       ` Goffredo Baroncelli
@ 2012-01-06 18:21         ` David Sterba
  0 siblings, 0 replies; 10+ messages in thread
From: David Sterba @ 2012-01-06 18:21 UTC (permalink / raw)
  To: linux-btrfs; +Cc: chris.mason, kreijack, David Sterba

Signed-off-by: David Sterba <dsterba@suse.cz>
---
v2->v3: manpage updated, added <...> around file in command description

 btrfs.c        |    9 ++++++-
 btrfs_cmds.c   |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 btrfs_cmds.h   |    1 +
 ioctl.h        |   13 ++++++++++
 man/btrfs.8.in |   10 ++++++++
 5 files changed, 100 insertions(+), 1 deletions(-)

diff --git a/btrfs.c b/btrfs.c
index 1def354..d6a7665 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 ordinary and compressed size of extents in the range [start,end)\n"
+		  "-s start  range start inclusive, accepts K/M/G modifiers\n"
+		  "-e end    range end exclusive, accepts K/M/G modifiers\n",
+	  NULL
 	},
 	{ do_scrub_start, -1,
 	  "scrub start", "[-Bdqr] <path>|<device>\n"
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..1074ade 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -1305,3 +1305,71 @@ 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:r");
+		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("File name: %s\n", argv[optind]);
+	if (args.end == (u64)-1)
+		printf("File range:        %llu-EOF\n",
+				(unsigned long long)args.start);
+	else
+		printf("File range:        %llu-%llu\n",
+				(unsigned long long)args.start,
+				(unsigned long long)args.end);
+
+	printf("Compressed size:   %llu\n",
+			(unsigned long long)(args.compressed_size << 9));
+	printf("Uncompressed size: %llu\n",
+			(unsigned long long)(args.size << 9));
+	printf("Ratio:             %3.2f%%\n",
+			100.0 * args.compressed_size / args.size);
+	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..5b5208a 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -224,6 +224,17 @@ 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   compressed_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 +288,7 @@ struct btrfs_ioctl_logical_ino_args {
 					struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
 					struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \
+		                struct btrfs_ioctl_compr_size_args)
 
 #endif
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index be478e0..b7dacea 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -31,6 +31,8 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
 .PP
+\fBbtrfs\fP \fBfilesystem csize \fP\fI [-s start] [-e end] <file> \fP
+.PP
 \fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
 .PP
 \fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
@@ -209,6 +211,14 @@ If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
 otherwise the devices list is extracted from the /proc/partitions file.
 .TP
 
+\fBfilesystem csize \fR \fI [-s start] [-e end] <file> \fR
+Read ordinary and compressed size of extents in the range [start,end) of \fI<file>\fR
+.IP
+\fB-s start\fP  range start inclusive, accepts K/M/G modifiers
+.IP
+\fB-e end\fP    range end exclusive, accepts K/M/G modifiers
+.TP
+
 \fBdevice balance\fR \fI<path>\fR
 Balance the chunks of the filesystem identified by \fI<path>\fR
 across the devices.
-- 
1.7.6.233.gd79bc


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

end of thread, other threads:[~2012-01-06 18:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-19 14:17 [PATCH] btrfs: add new ioctl to determine size of compressed file David Sterba
2011-12-19 14:25 ` A sample tool how to use the new ioctl David Sterba
2011-12-19 14:47   ` Chris Mason
2011-12-19 17:27     ` David Sterba
2011-12-20 17:49     ` [PATCH V2] btrfs-progs: Add ioctl to read compressed size of a file David Sterba
2011-12-20 20:32       ` Goffredo Baroncelli
2012-01-06 18:21         ` [PATCH v3] " David Sterba
2011-12-20  1:33 ` [PATCH] btrfs: add new ioctl to determine size of compressed file Liu Bo
2011-12-20 17:26   ` David Sterba
2011-12-20 17:46   ` [PATCH V2] " David Sterba

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.