lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4EC57A6A.80306@redhat.com>
Date:	Thu, 17 Nov 2011 15:19:38 -0600
From:	Eric Sandeen <sandeen@...hat.com>
To:	"Theodore Ts'o" <tytso@....edu>
CC:	Ext4 Developers List <linux-ext4@...r.kernel.org>
Subject: Re: [PATCH 1/2] debugfs: add filefrag command

On 11/17/11 3:12 PM, Theodore Ts'o wrote:
> Add the ability to report on the fragmentation of a file on a file
> system opened using debugfs.
> 
> Signed-off-by: "Theodore Ts'o" <tytso@....edu>
> ---
>  debugfs/Makefile.in      |    8 +-
>  debugfs/debug_cmds.ct    |    3 +
>  debugfs/debugfs.8.in     |   21 +++
>  debugfs/debugfs.h        |    1 +
>  debugfs/filefrag.c       |  324 ++++++++++++++++++++++++++++++++++++++++++++++

Is it possible to share any of ^^^ that code ^^^ with misc/filefrag.c somehow?

-Eric

>  debugfs/ro_debug_cmds.ct |    3 +
>  6 files changed, 357 insertions(+), 3 deletions(-)
>  create mode 100644 debugfs/filefrag.c
> 
> diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
> index e03a3c6..c6aaa3a 100644
> --- a/debugfs/Makefile.in
> +++ b/debugfs/Makefile.in
> @@ -17,15 +17,17 @@ MANPAGES=	debugfs.8
>  MK_CMDS=	_SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
>  
>  DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
> -	lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o
> +	lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
> +	filefrag.o
>  
>  RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
> -	lsdel.o logdump.o htree.o e2freefrag.o
> +	lsdel.o logdump.o htree.o e2freefrag.o filefrag.o
>  
>  SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
>  	$(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
>  	$(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
> -	$(srcdir)/htree.c $(srcdir)/unused.c
> +	$(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
> +	$(srcdir)/filefrag.c
>  
>  LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
>  	$(LIBUUID)
> diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
> index 47de672..af969b1 100644
> --- a/debugfs/debug_cmds.ct
> +++ b/debugfs/debug_cmds.ct
> @@ -52,6 +52,9 @@ request do_dump_extents, "Dump extents information ",
>  request do_blocks, "Dump blocks used by an inode ",
>  	blocks;
>  
> +request do_filefrag, "Report fragmentation information for an inode",
> +	filefrag;
> +
>  request do_link, "Create directory link",
>  	link, ln;
>  
> diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
> index 69490ff..70c8326 100644
> --- a/debugfs/debugfs.8.in
> +++ b/debugfs/debugfs.8.in
> @@ -251,6 +251,27 @@ Set or clear various filesystem features in the superblock.  After setting
>  or clearing any filesystem features that were requested, print the current
>  state of the filesystem feature set.
>  .TP
> +.I filefrag [-dvr] filespec
> +Print the number of contiguous extents in
> +.IR filespec .
> +If
> +.I filespec
> +is a directory and the
> +.I -d
> +option is not specified,
> +.I filefrag
> +will print the number of contiguous extents for each file in
> +the directory.  The
> +.I -v
> +option will cause
> +.I filefrag
> +print a tabular listing of the contiguous extents in the
> +file.  The
> +.I -r
> +option will cause
> +.I filefrag
> +to do a recursive listing of the directory.
> +.TP
>  .I find_free_block [count [goal]]
>  Find the first 
>  .I count
> diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
> index 6d7dfcd..0afa1df 100644
> --- a/debugfs/debugfs.h
> +++ b/debugfs/debugfs.h
> @@ -134,3 +134,4 @@ extern void do_supported_features(int argc, char **argv);
>  extern void do_punch(int argc, char **argv);
>  
>  extern void do_freefrag(int argc, char **argv);
> +extern void do_filefrag(int argc, char *argv[]);
> diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
> new file mode 100644
> index 0000000..30933b6
> --- /dev/null
> +++ b/debugfs/filefrag.c
> @@ -0,0 +1,324 @@
> +/*
> + * filefrag.c --- display the fragmentation information for a file
> + *
> + * Copyright (C) 2011 Theodore Ts'o.  This file may be redistributed
> + * under the terms of the GNU Public License.
> + */
> +
> +#include "config.h"
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <ctype.h>
> +#include <string.h>
> +#include <time.h>
> +#ifdef HAVE_ERRNO_H
> +#include <errno.h>
> +#endif
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <utime.h>
> +#ifdef HAVE_GETOPT_H
> +#include <getopt.h>
> +#else
> +extern int optind;
> +extern char *optarg;
> +#endif
> +
> +#include "debugfs.h"
> +
> +#define VERBOSE_OPT	0x0001
> +#define DIR_OPT		0x0002
> +#define RECURSIVE_OPT	0x0004
> +
> +struct dir_list {
> +	char		*name;
> +	ext2_ino_t	ino;
> +	struct dir_list	*next;
> +};
> +
> +struct filefrag_struct {
> +	FILE		*f;
> +	const char	*name;
> +	const char	*dir_name;
> +	int		options;
> +	int		logical_width;
> +	int		physical_width;
> +	int		ext;
> +	int		cont_ext;
> +	e2_blkcnt_t	num;
> +	e2_blkcnt_t	logical_start;
> +	blk64_t		physical_start;
> +	blk64_t		expected;
> +	struct dir_list *dir_list, *dir_last;
> +};
> +
> +static int int_log10(unsigned long long arg)
> +{
> +	int     l = 0;
> +
> +	arg = arg / 10;
> +	while (arg) {
> +		l++;
> +		arg = arg / 10;
> +	}
> +	return l;
> +}
> +
> +static void print_header(struct filefrag_struct *fs)
> +{
> +	if (fs->options & VERBOSE_OPT) {
> +		fprintf(fs->f, "%4s %*s %*s %*s %*s\n", "ext",
> +			fs->logical_width, "logical", fs->physical_width,
> +			"physical", fs->physical_width, "expected",
> +			fs->logical_width, "length");
> +	}
> +}
> +
> +static void report_filefrag(struct filefrag_struct *fs)
> +{
> +	if (fs->num == 0)
> +		return;
> +	if (fs->options & VERBOSE_OPT) {
> +		if (fs->expected)
> +			fprintf(fs->f, "%4d %*lu %*llu %*llu %*lu\n", fs->ext,
> +				fs->logical_width,
> +				(unsigned long) fs->logical_start,
> +				fs->physical_width, fs->physical_start,
> +				fs->physical_width, fs->expected,
> +				fs->logical_width, (unsigned long) fs->num);
> +		else
> +			fprintf(fs->f, "%4d %*lu %*llu %*s %*lu\n", fs->ext,
> +				fs->logical_width,
> +				(unsigned long) fs->logical_start,
> +				fs->physical_width, fs->physical_start,
> +				fs->physical_width, "",
> +				fs->logical_width, (unsigned long) fs->num);
> +	}
> +	fs->ext++;
> +}
> +
> +static int filefrag_blocks_proc(ext2_filsys ext4_fs EXT2FS_ATTR((unused)),
> +				blk64_t *blocknr, e2_blkcnt_t blockcnt,
> +				blk64_t ref_block EXT2FS_ATTR((unused)),
> +				int ref_offset EXT2FS_ATTR((unused)),
> +				void *private)
> +{
> +	struct filefrag_struct *fs = private;
> +
> +	if (blockcnt < 0 || *blocknr == 0)
> +		return 0;
> +
> +	if ((fs->num == 0) || (blockcnt != fs->logical_start + fs->num) ||
> +	    (*blocknr != fs->physical_start + fs->num)) {
> +		report_filefrag(fs);
> +		if (blockcnt == fs->logical_start + fs->num)
> +			fs->expected = fs->physical_start + fs->num;
> +		else
> +			fs->expected = 0;
> +		fs->logical_start = blockcnt;
> +		fs->physical_start = *blocknr;
> +		fs->num = 1;
> +		fs->cont_ext++;
> +	} else
> +		fs->num++;
> +	return 0;
> +}
> +
> +static void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
> +		     struct filefrag_struct *fs)
> +{
> +	errcode_t	retval;
> +	int		blocksize = current_fs->blocksize;
> +
> +	fs->logical_width = int_log10((EXT2_I_SIZE(inode) + blocksize - 1) /
> +				      blocksize) + 1;
> +	if (fs->logical_width < 7)
> +		fs->logical_width = 7;
> +	fs->ext = 0;
> +	fs->cont_ext = 0;
> +	fs->logical_start = 0;
> +	fs->physical_start = 0;
> +	fs->num = 0;
> +
> +	if (fs->options & VERBOSE_OPT) {
> +		blk64_t num_blocks = ext2fs_inode_i_blocks(current_fs, inode);
> +
> +		if (!(current_fs->super->s_feature_ro_compat &
> +		     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
> +		    !(inode->i_flags & EXT4_HUGE_FILE_FL))
> +			num_blocks /= current_fs->blocksize / 512;
> +
> +		fprintf(fs->f, "\n%s has %llu block(s), i_size is %llu\n",
> +			fs->name, num_blocks, EXT2_I_SIZE(inode));
> +	}
> +	print_header(fs);
> +	retval = ext2fs_block_iterate3(current_fs, ino,
> +				       BLOCK_FLAG_READ_ONLY, NULL,
> +				       filefrag_blocks_proc, fs);
> +	if (retval)
> +		com_err("ext2fs_block_iterate3", retval, 0);
> +
> +	report_filefrag(fs);
> +	fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
> +		LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
> +}
> +
> +static int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
> +			     int	entry,
> +			     struct ext2_dir_entry *dirent,
> +			     int	offset EXT2FS_ATTR((unused)),
> +			     int	blocksize EXT2FS_ATTR((unused)),
> +			     char	*buf EXT2FS_ATTR((unused)),
> +			     void	*private)
> +{
> +	struct filefrag_struct *fs = private;
> +	struct ext2_inode	inode;
> +	ext2_ino_t		ino;
> +	char			name[EXT2_NAME_LEN + 1];
> +	char			*cp;
> +	int			thislen;
> +
> +	if (entry == DIRENT_DELETED_FILE)
> +		return 0;
> +
> +	thislen = dirent->name_len & 0xFF;
> +	strncpy(name, dirent->name, thislen);
> +	name[thislen] = '\0';
> +	ino = dirent->inode;
> +
> +	if (!strcmp(name, ".") || !strcmp(name, ".."))
> +		return 0;
> +
> +	cp = malloc(strlen(fs->dir_name) + strlen(name) + 2);
> +	if (!cp) {
> +		fprintf(stderr, "Couldn't allocate memory for %s/%s\n",
> +			fs->dir_name, name);
> +		return 0;
> +	}
> +
> +	sprintf(cp, "%s/%s", fs->dir_name, name);
> +	fs->name = cp;
> +
> +	if (debugfs_read_inode(ino, &inode, fs->name))
> +		goto errout;
> +
> +	filefrag(ino, &inode, fs);
> +
> +	if ((fs->options & RECURSIVE_OPT) && LINUX_S_ISDIR(inode.i_mode)) {
> +		struct dir_list *p;
> +
> +		p = malloc(sizeof(struct dir_list));
> +		if (!p) {
> +			fprintf(stderr, "Couldn't allocate dir_list for %s\n",
> +				fs->name);
> +			goto errout;
> +		}
> +		memset(p, 0, sizeof(struct dir_list));
> +		p->name = cp;
> +		p->ino = ino;
> +		if (fs->dir_last)
> +			fs->dir_last->next = p;
> +		else
> +			fs->dir_list = p;
> +		fs->dir_last = p;
> +		return 0;
> +	}
> +errout:
> +	free(cp);
> +	fs->name = 0;
> +	return 0;
> +}
> +
> +
> +static void dir_iterate(ext2_ino_t ino, struct filefrag_struct *fs)
> +{
> +	errcode_t	retval;
> +	struct dir_list	*p = NULL;
> +
> +	fs->dir_name = fs->name;
> +
> +	while (1) {
> +		retval = ext2fs_dir_iterate2(current_fs, ino, 0,
> +					     0, filefrag_dir_proc, fs);
> +		if (retval)
> +			com_err("ext2fs_dir_iterate2", retval, 0);
> +		if (p) {
> +			free(p->name);
> +			fs->dir_list = p->next;
> +			if (!fs->dir_list)
> +				fs->dir_last = 0;
> +			free(p);
> +		}
> +		p = fs->dir_list;
> +		if (!p)
> +			break;
> +		ino = p->ino;
> +		fs->dir_name = p->name;
> +	}
> +}
> +
> +void do_filefrag(int argc, char *argv[])
> +{
> +	struct filefrag_struct fs;
> +	struct ext2_inode inode;
> +	ext2_ino_t	ino;
> +	int		c;
> +
> +	memset(&fs, 0, sizeof(fs));
> +	if (check_fs_open(argv[0]))
> +		return;
> +
> +	reset_getopt();
> +	while ((c = getopt (argc, argv, "dvr")) != EOF) {
> +		switch (c) {
> +		case 'd':
> +			fs.options |= DIR_OPT;
> +			break;
> +		case 'v':
> +			fs.options |= VERBOSE_OPT;
> +			break;
> +		case 'r':
> +			fs.options |= RECURSIVE_OPT;
> +			break;
> +		default:
> +			goto print_usage;
> +		}
> +	}
> +
> +	if (argc > optind+1) {
> +	print_usage:
> +		com_err(0, 0, "Usage: filefrag [-dv] file");
> +		return;
> +	}
> +
> +	if (argc == optind) {
> +		ino = cwd;
> +		fs.name = ".";
> +	} else {
> +		ino = string_to_inode(argv[optind]);
> +		fs.name = argv[optind];
> +	}
> +	if (!ino)
> +		return;
> +
> +	if (debugfs_read_inode(ino, &inode, argv[0]))
> +		return;
> +
> +	fs.f = open_pager();
> +	fs.physical_width = int_log10(ext2fs_blocks_count(current_fs->super));
> +	fs.physical_width++;
> +	if (fs.physical_width < 8)
> +		fs.physical_width = 8;
> +
> +	if (!LINUX_S_ISDIR(inode.i_mode) || (fs.options & DIR_OPT))
> +		filefrag(ino, &inode, &fs);
> +	else
> +		dir_iterate(ino, &fs);
> +
> +	fprintf(fs.f, "\n");
> +	close_pager(fs.f);
> +
> +	return;
> +}
> diff --git a/debugfs/ro_debug_cmds.ct b/debugfs/ro_debug_cmds.ct
> index 7eb552d..4feb621 100644
> --- a/debugfs/ro_debug_cmds.ct
> +++ b/debugfs/ro_debug_cmds.ct
> @@ -45,6 +45,9 @@ request do_dump_extents, "Dump extents information ",
>  request do_blocks, "Dump blocks used by an inode ",
>  	blocks;
>  
> +request do_filefrag, "Report fragmentation information for an inode",
> +	filefrag;
> +
>  request do_testi, "Test an inode's in-use flag",
>  	testi;
>  

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ