* [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
* Re: [PATCH] improved filefrag output v2
2010-02-18 13:07 [PATCH] improved filefrag output Andreas Dilger
@ 2010-02-23 22:53 ` Andreas Dilger
2010-05-13 21:56 ` tytso
0 siblings, 1 reply; 3+ messages in thread
From: Andreas Dilger @ 2010-02-23 22:53 UTC (permalink / raw)
To: Andreas Dilger; +Cc: Theodore Ts'o, ext4 development
[-- Attachment #1: Type: text/plain, Size: 2044 bytes --]
Attached is a new 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 major change from v1 of the patch is that for FIBMAP files it
considers logical file discontinuity as well as physical
discontinuity. This impacts only sparse files, but provides more
accurate information in "extent" output format. The old filefrag
output has not been changed (for compatibility, if that is a concern),
though it now reports a different number of extents for sparse files.
This could be changed fairly easily.
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: logical_offset: 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: eof
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: 20674 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,88 @@ 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;
+ unsigned long long logical;
+ /* 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;
+ }
+
+ for (i = 0, logical = 0, *num_extents = 0, count = last_block = 0;
+ i < numblocks;
+ i++, logical += fileinfo->st_blksize) {
+ 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 (force_extent &&
+ (last_block && (block != last_block + 1) ||
+ fm_ext.fe_logical + fm_ext.fe_length != logical)) {
+ print_extent_info(&fm_ext, *num_extents - 1,
+ blk_shift, fileinfo);
+ fm_ext.fe_logical = logical;
+ fm_ext.fe_physical = block*fileinfo->st_blksize;
+ fm_ext.fe_length = 0;
+ (*num_extents)++;
+ } else if (verbose && last_block && (block != last_block + 1)) {
+ 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 +403,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 +496,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
* Re: [PATCH] improved filefrag output v2
2010-02-23 22:53 ` [PATCH] improved filefrag output v2 Andreas Dilger
@ 2010-05-13 21:56 ` tytso
0 siblings, 0 replies; 3+ messages in thread
From: tytso @ 2010-05-13 21:56 UTC (permalink / raw)
To: Andreas Dilger; +Cc: ext4 development
Added to the e2fsprogs maint branch, thanks.
- Ted
^ 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).