linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] improved filefrag output
@ 2010-02-18 13:07 Andreas Dilger
  2010-02-23 22:53 ` [PATCH] improved filefrag output v2 Andreas Dilger
  0 siblings, 1 reply; 3+ messages in thread
From: Andreas Dilger @ 2010-02-18 13:07 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: ext4 development

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

Attached is a patch to improve the filefrag output.  The most  
important part of the change is that it allows the "extent format"  
output to be used even if the filesystem does not support FIEMAP.   
This is useful for older kernels (i.e. most vendor kernels), or in  
case FIEMAP hasn't been wired into a filesystem yet.

The extent format output is improved to be more similar to that of  
xfs_bmap, so it prints out a range of logical and physical block  
numbers, in addition to the extent length, so that it is easier to see  
where the discontinuities are.  There is also an option to print out  
the extents/lengths in hex, and using a different blocksize (e.g. "- 
b1M" to print in units of 1MB):

$ filefrag -e -b1M "Indiana Jones And The Temple Of Doom.avi"
  ext:     device_logical:        physical_offset: length: flags:
    0:        0..       1:     320566..    320567:      1:
    1:        1..       3:     320866..    320868:      2:
    2:        3..       3:     320768..    320768:      0:
    3:        4..      29:     320870..    320895:     26:
    4:       30..     155:     320898..    321023:    126:
    5:      156..     281:     321026..    321151:    126:
    6:      282..     407:     321154..    321279:    126:
    7:      408..     533:     321282..    321407:    126:
    8:      534..     659:     321410..    321535:    126:

Also included is support for FIEMAP extensions to support multi-device  
filesystems (e.g. Lustre, ZFS, maybe btrfs in the future).

Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.

[-- Attachment #2: e2fsprogs-fiemap-lustre.patch --]
[-- Type: application/octet-stream, Size: 20492 bytes --]

Improve the filefrag output in a number of ways:
* properly handle the -b option to print blocksizes other than disk blocksize
* allow -b to take an argument to specify the blocksize (with compatibility)
* add -k option as shorthand for "1024-byte blocks" (like "df -k")
* re-enable the -x option to print extent-format output, even with FIBMAP
* improve extent-format to print extent ranges, more like xfs_bmap
* add -X option to print extent-format output in hexadecimal
* print one error with filename when FIBMAP fails, continue on to next file
* add support for FIEMAP extensions for network and multi-device filesystems
* add auto-detection of Lustre filesystems to select correct options

Signed-off-by: Andreas Dilger <adilger@sun.com>

Index: e2fsprogs-1.41.10/lib/ext2fs/fiemap.h
===================================================================
--- e2fsprogs-1.41.10.orig/lib/ext2fs/fiemap.h
+++ e2fsprogs-1.41.10/lib/ext2fs/fiemap.h
@@ -21,7 +21,8 @@ struct fiemap_extent {
 	__u64 fe_length;   /* length in bytes for this extent */
 	__u64 fe_reserved64[2];
 	__u32 fe_flags;    /* FIEMAP_EXTENT_* flags for this extent */
-	__u32 fe_reserved[3];
+	__u32 fe_device;   /* device number (fs-specific if FIEMAP_EXTENT_NET)*/
+	__u32 fe_reserved[2];
 };
 
 struct fiemap {
@@ -40,6 +41,7 @@ struct fiemap {
 
 #define FIEMAP_FLAG_SYNC	0x00000001 /* sync file data before map */
 #define FIEMAP_FLAG_XATTR	0x00000002 /* map extended attribute tree */
+#define FIEMAP_FLAG_DEVICE_ORDER 0x40000000 /* return device ordered mapping */
 
 #define FIEMAP_FLAGS_COMPAT	(FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
 
@@ -63,4 +65,9 @@ struct fiemap {
 						    * support extents. Result
 						    * merged for efficiency. */
 
+/* Network filesystem flags - use a high bit, don't conflict with upstream */
+#define FIEMAP_EXTENT_NO_DIRECT		0x40000000 /* Data mapping undefined */
+#define FIEMAP_EXTENT_NET		0x80000000 /* Data stored remotely.
+						    * Sets NO_DIRECT flag */
+
 #endif /* _LINUX_FIEMAP_H */
Index: e2fsprogs-1.41.10/misc/filefrag.8.in
===================================================================
--- e2fsprogs-1.41.10.orig/misc/filefrag.8.in
+++ e2fsprogs-1.41.10/misc/filefrag.8.in
@@ -5,7 +5,10 @@ filefrag \- report on file fragmentation
 .SH SYNOPSIS
 .B filefrag
 [
-.B \-Bbsvx
+.BI \-b blocksize
+]
+[
+.B \-BeklsvxX
 ]
 [
 .I files...
@@ -27,8 +30,15 @@ If FIEMAP is not supported then filefrag
 Force the use of the older FIBMAP ioctl instead of the FIEMAP ioctl for
 testing purposes.
 .TP
-.B \-b
-Use 1024 byte blocksize for the output.
+.BI \-b blocksize
+Use specified blocksize in bytes for the output instead of the filesystem
+.TP
+.B \-e
+Print output in extent format, even for non-extent files.
+.BI \-k
+Use 1024-byte blocksize for output.
+.B \-l
+Extents are displayed in device-logical offset order.
 .TP
 .B \-s
 Sync the file before requesting the mapping.
@@ -38,6 +48,9 @@ Be verbose when checking for file fragme
 .TP
 .B \-x
 Display mapping of extended attributes.
+.TP
+.B \-X
+Display extent block numbers in hexadecimal format.
 .SH AUTHOR
 .B filefrag
 was written by Theodore Ts'o <tytso@mit.edu>.
Index: e2fsprogs-1.41.10/misc/filefrag.c
===================================================================
--- e2fsprogs-1.41.10.orig/misc/filefrag.c
+++ e2fsprogs-1.41.10/misc/filefrag.c
@@ -15,8 +15,8 @@
 #include <unistd.h>
 
 int main(void) {
-    fputs("This program is only supported on Linux!\n", stderr);
-    exit(EXIT_FAILURE);
+	fputs("This program is only supported on Linux!\n", stderr);
+	exit(EXIT_FAILURE);
 }
 #else
 #define _LARGEFILE64_SOURCE
@@ -43,23 +43,35 @@ extern int optind;
 #include <ext2fs/fiemap.h>
 
 int verbose = 0;
-int no_bs = 0;		/* Don't use the files blocksize, use 1K blocksize */
+int blocksize = 0;	/* Use specified blocksize (default 1kB) */
 int sync_file = 0;	/* fsync file before getting the mapping */
 int xattr_map = 0;	/* get xattr mapping */
-int force_bmap = 0;
-int logical_width = 12;
-int physical_width = 14;
-unsigned long long filesize;
+int force_bmap = 0;	/* force use of FIBMAP instead of FIEMAP */
+int force_extent = 0;	/* print output in extent format always */
+int device_offset = 0;	/* extents report device-relative offsets */
+int logical_width = 8;
+int physical_width = 10;
+char *ext_fmt = "%4d: %*llu..%*llu: %*llu..%*llu: %6llu: %s\n";
+char *hex_fmt = "%4d: %*llx..%*llx: %*llx..%*llx: %6llx: %s\n";
 
-#define FILEFRAG_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
+#define FILEFRAG_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR |\
+				      FIEMAP_FLAG_DEVICE_ORDER)
 
 #define FIBMAP		_IO(0x00, 1)	/* bmap access */
 #define FIGETBSZ	_IO(0x00, 2)	/* get the block size used for bmap */
 #define FS_IOC_FIEMAP	_IOWR('f', 11, struct fiemap)
 
+#define LUSTRE_SUPER_MAGIC 0x0BD00BD0
+
 #define	EXT4_EXTENTS_FL			0x00080000 /* Inode uses extents */
 #define	EXT3_IOC_GETFLAGS		_IOR('f', 1, long)
 
+#ifdef HAVE_FSTAT64
+#define mystat stat64
+#else
+#define mystat stat
+#endif
+
 static int int_log2(int arg)
 {
 	int     l = 0;
@@ -102,30 +114,41 @@ static int get_bmap(int fd, unsigned lon
 		if (errno == EPERM) {
 			fprintf(stderr, "No permission to use FIBMAP ioctl; "
 				"must have root privileges\n");
-			exit(1);
 		}
-		perror("FIBMAP");
 	}
 	*phy_blk = b;
 
 	return ret;
 }
 
+static void print_extent_header(void)
+{
+	printf(" ext: %*s %*s length: %sflags:\n",
+	       logical_width * 2 + 3,
+	       device_offset ? "device_logical:" : "logical_offset:",
+	       physical_width * 2 + 3, "physical_offset:",
+	       device_offset ? " dev: " : "");
+}
+
 static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex,
-			      unsigned long long expected, int blk_shift)
+			      int blk_shift, struct mystat *fileinfo)
 {
-	__u64 phy_blk;
+	unsigned long long physical_blk;
 	unsigned long long logical_blk;
-	unsigned long ext_len;
+	unsigned long long ext_blks, ext_len;
 	char flags[256] = "";
 
-	/* For inline data all offsets should be in terms of bytes, not blocks */
+	/* For inline data all offsets should be in bytes, not blocks */
 	if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_INLINE)
 		blk_shift = 0;
 
 	ext_len = fm_extent->fe_length >> blk_shift;
+	ext_blks = (fm_extent->fe_length - 1) >> blk_shift;
 	logical_blk = fm_extent->fe_logical >> blk_shift;
-	phy_blk = fm_extent->fe_physical >> blk_shift;
+	physical_blk = fm_extent->fe_physical >> blk_shift;
+
+	if (device_offset)
+		sprintf(flags, "%04x: ", fm_extent->fe_device);
 
 	if (fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN)
 		strcat(flags, "unknown,");
@@ -143,47 +166,50 @@ static void print_extent_info(struct fie
 		strcat(flags, "unwritten,");
 	if (fm_extent->fe_flags & FIEMAP_EXTENT_MERGED)
 		strcat(flags, "merged,");
+	if (fm_extent->fe_flags & FIEMAP_EXTENT_NET)
+		strcat(flags, "network,");
+	if (fm_extent->fe_flags & FIEMAP_EXTENT_NO_DIRECT)
+		strcat(flags, "no_direct,");
 
-	if (fm_extent->fe_logical + fm_extent->fe_length >= filesize)
+	if (fm_extent->fe_logical + fm_extent->fe_length >= fileinfo->st_size)
 		strcat(flags, "eof,");
 
 	/* Remove trailing comma, if any */
 	if (flags[0])
 		flags[strlen(flags) - 1] = '\0';
 
-	if (expected)
-		printf("%4d %*llu %*llu %*llu %6lu %s\n",
-		       cur_ex, logical_width, logical_blk,
-		       physical_width, phy_blk, physical_width, expected,
-		       ext_len, flags);
-	else
-		printf("%4d %*llu %*llu %*s %6lu %s\n",
-		       cur_ex, logical_width, logical_blk,
-		       physical_width, phy_blk, physical_width, "",
-		       ext_len, flags);
+	printf(ext_fmt, cur_ex, logical_width, logical_blk,
+	       logical_width, logical_blk + ext_blks,
+	       physical_width, physical_blk,
+	       physical_width, physical_blk + ext_blks,
+	       ext_len, flags);
 }
 
-static int filefrag_fiemap(int fd, int blk_shift, int *num_extents)
+static int filefrag_fiemap(int fd, int blk_shift, int *num_extents,
+			   struct mystat *fileinfo)
 {
 	char buf[4096] = "";
 	struct fiemap *fiemap = (struct fiemap *)buf;
 	struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
 	int count = (sizeof(buf) - sizeof(*fiemap)) /
 			sizeof(struct fiemap_extent);
-	unsigned long long last_blk = 0;
+	unsigned long long next_physical = 0;
 	unsigned long flags = 0;
 	unsigned int i;
 	static int fiemap_incompat_printed;
 	int fiemap_header_printed = 0;
 	int tot_extents = 1, n = 0;
+	int previous_device = 0;
 	int last = 0;
 	int rc;
 
 	fiemap->fm_length = ~0ULL;
 
-	memset(fiemap, 0, sizeof(struct fiemap));
+	/* If extents are going to be device ordered, then we may need to use
+	 * the first extent to pass the next starting offset and the device. */
+	memset(fiemap, 0, sizeof(struct fiemap) + sizeof(struct fiemap_extent));
 
-	if (!verbose)
+	if (!verbose && !force_extent)
 		count = 0;
 
 	if (sync_file)
@@ -192,6 +218,10 @@ static int filefrag_fiemap(int fd, int b
 	if (xattr_map)
 		flags |= FIEMAP_FLAG_XATTR;
 
+	if (device_offset)
+		flags |= FIEMAP_FLAG_DEVICE_ORDER;
+
+retry_wo_device_offset:
 	do {
 		fiemap->fm_length = ~0ULL;
 		fiemap->fm_flags = flags;
@@ -202,18 +232,20 @@ static int filefrag_fiemap(int fd, int b
 				printf("FIEMAP failed with unsupported "
 				       "flags %x\n", fiemap->fm_flags);
 				fiemap_incompat_printed = 1;
+			} else if (rc == EBADR && (fiemap->fm_flags &
+						   FIEMAP_FLAG_DEVICE_ORDER)) {
+				flags &= ~FIEMAP_FLAG_DEVICE_ORDER;
+				goto retry_wo_device_offset;
 			}
 			return rc;
 		}
 
-		if (verbose && !fiemap_header_printed) {
-			printf(" ext %*s %*s %*s length flags\n", logical_width,
-			       "logical", physical_width, "physical",
-			       physical_width, "expected");
+		if ((verbose || force_extent) && !fiemap_header_printed) {
+			print_extent_header();
 			fiemap_header_printed = 1;
 		}
 
-		if (!verbose) {
+		if (!verbose && !force_extent) {
 			*num_extents = fiemap->fm_mapped_extents;
 			goto out;
 		}
@@ -223,27 +255,40 @@ static int filefrag_fiemap(int fd, int b
 			break;
 
 		for (i = 0; i < fiemap->fm_mapped_extents; i++) {
-			__u64 phy_blk, logical_blk;
-			unsigned long ext_len;
+			unsigned long long physical, logical;
+
+			physical = fm_ext[i].fe_physical;
+			logical  = fm_ext[i].fe_logical;
 
-			phy_blk = fm_ext[i].fe_physical >> blk_shift;
-			ext_len = fm_ext[i].fe_length >> blk_shift;
-			logical_blk = fm_ext[i].fe_logical >> blk_shift;
+			if (previous_device != fm_ext[i].fe_device)
+				previous_device = fm_ext[i].fe_device;
 
-			if (logical_blk && phy_blk != last_blk + 1)
+			if (logical && physical != next_physical)
 				tot_extents++;
 			else
-				last_blk = 0;
-			print_extent_info(&fm_ext[i], n, last_blk, blk_shift);
+				last = 0;
+			print_extent_info(&fm_ext[i], n, blk_shift, fileinfo);
 
-			last_blk = phy_blk + ext_len - 1;
+			next_physical = physical + fm_ext[i].fe_length;
 			if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
 				last = 1;
 			n++;
 		}
 
-		fiemap->fm_start = (fm_ext[i-1].fe_logical +
-				    fm_ext[i-1].fe_length);
+		/* For DEVICE_ORDER mappings, if EXTENT_LAST not yet found then
+		 * fm_start needs to be the same as it was for earlier ioctl.
+		 * The first extent is used to pass the end offset and device
+		 * of the last FIEMAP call.  Otherwise, we ask for extents
+		 * starting from where the last mapping ended. */
+		if (flags & FIEMAP_FLAG_DEVICE_ORDER) {
+			fm_ext[0].fe_logical = fm_ext[i - 1].fe_logical +
+						      fm_ext[i - 1].fe_length;
+			fm_ext[0].fe_device = fm_ext[i - 1].fe_device;
+			fiemap->fm_start = 0;
+		} else {
+			fiemap->fm_start = fm_ext[i - 1].fe_logical +
+				    fm_ext[i - 1].fe_length;
+		}
 	} while (last == 0);
 
 	*num_extents = tot_extents;
@@ -253,24 +298,85 @@ out:
 
 #define EXT2_DIRECT	12
 
+static int filefrag_fibmap(int fd, int blk_shift, int *num_extents,
+			   struct mystat *fileinfo,
+			   unsigned long numblocks, int is_ext2)
+{
+	struct fiemap_extent	fm_ext;
+	unsigned long		i, last_block;
+				/* Blocks per indirect block */
+	const long		bpib = fileinfo->st_blksize / 4;
+	int			count;
+
+	if (force_extent) {
+		memset(&fm_ext, 0, sizeof(fm_ext));
+		fm_ext.fe_device = fileinfo->st_dev;
+	}
+
+	*num_extents = 0;
+	for (i = 0, count = last_block = 0; i < numblocks; i++) {
+		unsigned long block = 0;
+		int rc;
+
+		if (is_ext2 && last_block) {
+			if (((i - EXT2_DIRECT) % bpib) == 0)
+				last_block++;
+			if (((i - EXT2_DIRECT - bpib) % (bpib * bpib)) == 0)
+				last_block++;
+			if (((i - EXT2_DIRECT - bpib - bpib * bpib) %
+			     (((unsigned long long)bpib )* bpib * bpib)) == 0)
+				last_block++;
+		}
+		rc = get_bmap(fd, i, &block);
+		if (rc < 0)
+			return rc;
+		if (block == 0)
+			continue;
+		if (!*num_extents) {
+			(*num_extents)++;
+			if (force_extent) {
+				print_extent_header();
+				fm_ext.fe_physical = block*fileinfo->st_blksize;
+			}
+		}
+		count++;
+		if (last_block && (block != last_block + 1)) {
+			if (force_extent) {
+				print_extent_info(&fm_ext, *num_extents - 1,
+						  blk_shift, fileinfo);
+				fm_ext.fe_logical = i * fileinfo->st_blksize;
+				fm_ext.fe_physical = block*fileinfo->st_blksize;
+				fm_ext.fe_length = 0;
+			} else if (verbose) {
+				printf("Discontinuity: Block %ld is at %lu "
+				       "(was %lu)\n", i, block, last_block + 1);
+			}
+			(*num_extents)++;
+		}
+		fm_ext.fe_length += fileinfo->st_blksize;
+		last_block = block;
+	}
+
+	if (force_extent)
+		print_extent_info(&fm_ext, *num_extents - 1,
+				  blk_shift, fileinfo);
+
+	return count;
+}
+
 static void frag_report(const char *filename)
 {
 	struct statfs	fsinfo;
-#ifdef HAVE_FSTAT64
-	struct stat64	fileinfo;
-#else
-	struct stat	fileinfo;
-#endif
-	int		bs;
+	struct mystat	fileinfo;
+	int		blk_shift;
 	long		fd;
-	unsigned long	block, last_block = 0, numblocks, i, count;
-	long		bpib;	/* Blocks per indirect block */
-	long		cylgroups;
-	int		num_extents = 0, expected;
+	unsigned long	numblocks;
+	int		data_blocks_per_cyl = 1;
+	int		num_extents = 1, expected;
 	int		is_ext2 = 0;
-	static int	once = 1;
+	static int	last_device;
 	unsigned int	flags;
-	int rc;
+	int		width;
 
 #ifdef HAVE_OPEN64
 	fd = open64(filename, O_RDONLY);
@@ -294,89 +400,91 @@ static void frag_report(const char *file
 		perror("stat");
 		return;
 	}
+	fileinfo.st_blksize = fsinfo.f_bsize;
 	if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0)
 		flags = 0;
 	if (!(flags & EXT4_EXTENTS_FL) &&
 	    ((fsinfo.f_type == 0xef51) || (fsinfo.f_type == 0xef52) ||
 	     (fsinfo.f_type == 0xef53)))
 		is_ext2++;
-	if (verbose && once)
+	if (verbose && last_device != fileinfo.st_dev)
 		printf("Filesystem type is: %lx\n",
 		       (unsigned long) fsinfo.f_type);
 
-	cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize*8);
-	if (verbose && is_ext2 && once)
-		printf("Filesystem cylinder groups is approximately %ld\n",
-		       cylgroups);
-
-	physical_width = int_log10(fsinfo.f_blocks);
-	if (physical_width < 8)
-		physical_width = 8;
-
-	if (ioctl(fd, FIGETBSZ, &bs) < 0) { /* FIGETBSZ takes an int */
-		perror("FIGETBSZ");
-		close(fd);
-		return;
+	/* Check if filesystem is Lustre.  Always print in extent format
+	 * with 1kB blocks, using the device-relative logical offsets. */
+	if (fsinfo.f_type == LUSTRE_SUPER_MAGIC) {
+		is_ext2 = 0;
+		force_extent = 1;
+		device_offset = 1;
+		blocksize = blocksize ?: 1024;
+	}
+
+	if (is_ext2) {
+		long cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize * 8);
+
+		if (verbose && last_device != fileinfo.st_dev)
+		     printf("Filesystem cylinder groups is approximately %ld\n",
+			    cylgroups);
+
+		data_blocks_per_cyl = fsinfo.f_bsize * 8 -
+					(fsinfo.f_files / 8 / cylgroups) - 3;
 	}
+	last_device = fileinfo.st_dev;
 
-	if (no_bs)
-		bs = 1024;
+	width = int_log10(fsinfo.f_blocks);
+	if (width > physical_width)
+		physical_width = width;
+
+	numblocks = div_ceil(fileinfo.st_size, fsinfo.f_bsize);
+	if (blocksize != 0)
+		blk_shift = int_log2(blocksize);
+	else
+		blk_shift = int_log2(fsinfo.f_bsize);
 
-	bpib = bs / 4;
-	numblocks = (fileinfo.st_size + (bs-1)) / bs;
-	logical_width = int_log10(numblocks);
-	if (logical_width < 7)
-		logical_width = 7;
-	filesize = (long long)fileinfo.st_size;
+	width = int_log10(numblocks);
+	if (width > logical_width)
+		logical_width = width;
 	if (verbose)
-		printf("File size of %s is %lld (%ld block%s, blocksize %d)\n",
-		       filename, (long long) fileinfo.st_size, numblocks,
-		       numblocks == 1 ? "" : "s", bs);
+		printf("File size of %s is %lld (%ld block%s of %d bytes)\n",
+		       filename, (long long)fileinfo.st_size,
+		       numblocks * fsinfo.f_bsize >> blk_shift,
+		       numblocks == 1 ? "" : "s", 1 << blk_shift);
+
 	if (force_bmap ||
-	    filefrag_fiemap(fd, int_log2(bs), &num_extents) != 0) {
-		for (i = 0, count = 0; i < numblocks; i++) {
-			if (is_ext2 && last_block) {
-				if (((i-EXT2_DIRECT) % bpib) == 0)
-					last_block++;
-				if (((i-EXT2_DIRECT-bpib) % (bpib*bpib)) == 0)
-					last_block++;
-				if (((i-EXT2_DIRECT-bpib-bpib*bpib) %
-				     (((__u64) bpib)*bpib*bpib)) == 0)
-					last_block++;
-			}
-			rc = get_bmap(fd, i, &block);
-			if (block == 0)
-				continue;
-			if (!num_extents)
-				num_extents++;
-			count++;
-			if (last_block && (block != last_block+1) ) {
-				if (verbose)
-					printf("Discontinuity: Block %ld is at "
-					       "%lu (was %lu)\n",
-					       i, block, last_block+1);
-				num_extents++;
+	    filefrag_fiemap(fd, blk_shift, &num_extents, &fileinfo) != 0) {
+		expected = filefrag_fibmap(fd, blk_shift, &num_extents,
+					   &fileinfo, numblocks, is_ext2);
+		if (expected < 0) {
+			if (errno == EINVAL || errno == ENOTTY) {
+				fprintf(stderr, "%s: FIBMAP unsupported\n",
+					filename);
+			} else if (errno != EPERM) {
+				fprintf(stderr, "%s: FIBMAP error: %s",
+					filename, strerror(errno));
 			}
-			last_block = block;
+			goto out_close;
 		}
+		expected = expected / data_blocks_per_cyl + 1;
 	}
+
 	if (num_extents == 1)
 		printf("%s: 1 extent found", filename);
 	else
 		printf("%s: %d extents found", filename, num_extents);
-	expected = (count/((bs*8)-(fsinfo.f_files/8/cylgroups)-3))+1;
 	if (is_ext2 && expected < num_extents)
 		printf(", perfection would be %d extent%s\n", expected,
-			(expected>1) ? "s" : "");
+			(expected > 1) ? "s" : "");
 	else
 		fputc('\n', stdout);
+out_close:
 	close(fd);
-	once = 0;
 }
 
 static void usage(const char *progname)
 {
-	fprintf(stderr, "Usage: %s [-Bbvsx] file ...\n", progname);
+	fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeklsvxX] file ...\n",
+		progname);
 	exit(1);
 }
 
@@ -385,23 +493,59 @@ int main(int argc, char**argv)
 	char **cpp;
 	int c;
 
-	while ((c = getopt(argc, argv, "Bbsvx")) != EOF)
+	while ((c = getopt(argc, argv, "Bb::eklsvxX")) != EOF)
 		switch (c) {
 		case 'B':
 			force_bmap++;
+			force_extent = 0;
 			break;
 		case 'b':
-			no_bs++;
+			if (optarg) {
+				char *end;
+				blocksize = strtoul(optarg, &end, 0);
+				if (end) {
+					switch (end[0]) {
+					case 'g':
+					case 'G': blocksize *= 1024;
+						/* no break */
+					case 'm':
+					case 'M': blocksize *= 1024;
+						/* no break */
+					case 'k':
+					case 'K': blocksize *= 1024;
+						break;
+					default: break;
+					}
+				}
+			} else { /* allow -b without argument, for compat */
+				fprintf(stderr, "%s: -b needs a blocksize "
+					"option, assuming 1024-byte blocks.\n",
+					argv[0]);
+				blocksize = 1024;
+			}
 			break;
-		case 'v':
-			verbose++;
+		case 'e':
+			force_extent++;
+			force_bmap = 0;
+			break;
+		case 'k':
+			blocksize = 1024;
+			break;
+		case 'l':
+			device_offset++;
 			break;
 		case 's':
 			sync_file++;
 			break;
+		case 'v':
+			verbose++;
+			break;
 		case 'x':
 			xattr_map++;
 			break;
+		case 'X':
+			ext_fmt = hex_fmt;
+			break;
 		default:
 			usage(argv[0]);
 			break;

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

end of thread, other threads:[~2010-05-13 21:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-18 13:07 [PATCH] improved filefrag output Andreas Dilger
2010-02-23 22:53 ` [PATCH] improved filefrag output v2 Andreas Dilger
2010-05-13 21:56   ` tytso

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).