diff options
author | Theodore Ts'o <tytso@mit.edu> | 2020-01-23 10:46:10 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2020-01-23 10:46:10 -0500 |
commit | a320a1c6a0aa57d91b3471a7a65eef2688960568 (patch) | |
tree | a7c82a7ca63e8c6efff84738f9be4d18eceb7b72 | |
parent | dbc05604d33aece6c4ab55e9f621213243117212 (diff) | |
download | e2fsprogs-a320a1c6a0aa57d91b3471a7a65eef2688960568.tar.gz |
filefrag: add -E option to display the extent status cache
Ext4 has an extent status cache; add the fiemap extensions so we can
query the kernel for the extent status cache information.
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | lib/ext2fs/fiemap.h | 16 | ||||
-rw-r--r-- | misc/filefrag.8.in | 8 | ||||
-rw-r--r-- | misc/filefrag.c | 65 |
3 files changed, 80 insertions, 9 deletions
diff --git a/lib/ext2fs/fiemap.h b/lib/ext2fs/fiemap.h index 0d1072ac6..33ab8fb7e 100644 --- a/lib/ext2fs/fiemap.h +++ b/lib/ext2fs/fiemap.h @@ -45,10 +45,23 @@ struct fiemap { #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) #endif +#if defined(__linux__) && !defined(FS_IOC_GETSTATE) +#define EXT4_IOC_GETSTATE _IOW('f', 41, __u32) +#endif + +#if defined(__linux__) && !defined(EXT4_IOC_GET_ES_CACHE) +#define EXT4_IOC_GET_ES_CACHE _IOWR('f', 42, struct fiemap) +#endif + +#if defined(__linux__) && !defined(EXT4_STATE_FLAG_EXT_PRECACHED) +#define EXT4_STATE_FLAG_EXT_PRECACHED 0x00000001 +#endif + #define FIEMAP_MAX_OFFSET (~0ULL) #define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */ #define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */ +#define FIEMAP_FLAG_CACHE 0x00000004 /* request caching of the extents */ #define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) @@ -74,4 +87,7 @@ struct fiemap { #define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other * files. */ +#define EXT4_FIEMAP_EXTENT_HOLE 0x08000000 /* Entry in extent status + cache for a hole*/ + #endif /* _LINUX_FIEMAP_H */ diff --git a/misc/filefrag.8.in b/misc/filefrag.8.in index 5292672f8..302d85697 100644 --- a/misc/filefrag.8.in +++ b/misc/filefrag.8.in @@ -43,6 +43,14 @@ is unspecified it defaults to 1024 bytes. .B \-e Print output in extent format, even for block-mapped files. .TP +.B \-E +Display the contents of ext4's extent status cache. This feature is not +supported on all kernels, and is only supported on ext4 file systems. +.TP +.TP +.B -P +Pre-load the ext4's extent status cache for the file. This feature is not +supported on all kernels, and is only supported on ext4 file systems. .B \-k Use 1024\-byte blocksize for output (identical to '\-b 1024'). .TP diff --git a/misc/filefrag.c b/misc/filefrag.c index 1eec146d8..c845bec3d 100644 --- a/misc/filefrag.c +++ b/misc/filefrag.c @@ -55,9 +55,11 @@ extern int optind; int verbose = 0; int blocksize; /* Use specified blocksize (default 1kB) */ int sync_file = 0; /* fsync file before getting the mapping */ +int precache_file = 0; /* precache the file before getting the mapping */ int xattr_map = 0; /* get xattr mapping */ int force_bmap; /* force use of FIBMAP instead of FIEMAP */ int force_extent; /* print output in extent format always */ +int use_extent_cache; /* Use extent cache */ int logical_width = 8; int physical_width = 10; const char *ext_fmt = "%4d: %*llu..%*llu: %*llu..%*llu: %6llu: %s\n"; @@ -145,6 +147,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, unsigned long long logical_blk; unsigned long long ext_len; unsigned long long ext_blks; + unsigned long long ext_blks_phys; __u32 fe_flags, mask; char flags[256] = ""; @@ -161,13 +164,15 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, physical_blk = fm_extent->fe_physical >> blk_shift; } - if (expected) + fe_flags = fm_extent->fe_flags; + if (expected && + !(fe_flags & FIEMAP_EXTENT_UNKNOWN) && + !(fe_flags & EXT4_FIEMAP_EXTENT_HOLE)) sprintf(flags, ext_fmt == hex_fmt ? "%*llx: " : "%*llu: ", physical_width, expected >> blk_shift); else sprintf(flags, "%.*s ", physical_width, " "); - fe_flags = fm_extent->fe_flags; print_flag(&fe_flags, FIEMAP_EXTENT_LAST, flags, "last,"); print_flag(&fe_flags, FIEMAP_EXTENT_UNKNOWN, flags, "unknown_loc,"); print_flag(&fe_flags, FIEMAP_EXTENT_DELALLOC, flags, "delalloc,"); @@ -179,6 +184,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, print_flag(&fe_flags, FIEMAP_EXTENT_UNWRITTEN, flags, "unwritten,"); print_flag(&fe_flags, FIEMAP_EXTENT_MERGED, flags, "merged,"); print_flag(&fe_flags, FIEMAP_EXTENT_SHARED, flags, "shared,"); + print_flag(&fe_flags, EXT4_FIEMAP_EXTENT_HOLE, flags, "hole,"); /* print any unknown flags as hex values */ for (mask = 1; fe_flags != 0 && mask != 0; mask <<= 1) { char hex[sizeof(mask) * 2 + 4]; /* 2 chars/byte + 0x, + NUL */ @@ -197,10 +203,17 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, if (flags[0] != '\0') flags[strnlen(flags, sizeof(flags)) - 1] = '\0'; + if ((fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN) || + (fm_extent->fe_flags & EXT4_FIEMAP_EXTENT_HOLE)) { + ext_len = 0; + ext_blks_phys = 0; + } else + ext_blks_phys = ext_blks; + 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, + physical_width, physical_blk + ext_blks_phys, ext_len, flags); } @@ -217,6 +230,7 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, unsigned long long expected_dense = 0; unsigned long flags = 0; unsigned int i; + unsigned long cmd = FS_IOC_FIEMAP; int fiemap_header_printed = 0; int tot_extents = 0, n = 0; int last = 0; @@ -228,14 +242,20 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, if (sync_file) flags |= FIEMAP_FLAG_SYNC; + if (precache_file) + flags |= FIEMAP_FLAG_CACHE; + if (xattr_map) flags |= FIEMAP_FLAG_XATTR; + if (use_extent_cache) + cmd = EXT4_IOC_GET_ES_CACHE; + do { fiemap->fm_length = ~0ULL; fiemap->fm_flags = flags; fiemap->fm_extent_count = count; - rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap); + rc = ioctl(fd, cmd, (unsigned long) fiemap); if (rc < 0) { static int fiemap_incompat_printed; @@ -462,18 +482,39 @@ static int frag_report(const char *filename) else blk_shift = int_log2(blksize); - width = int_log10(numblocks); + if (use_extent_cache) + width = 10; + else + width = int_log10(numblocks); if (width > logical_width) logical_width = width; - if (verbose) - printf("File size of %s is %llu (%llu block%s of %d bytes)\n", + if (verbose) { + __u32 state; + + printf("File size of %s is %llu (%llu block%s of %d bytes)", filename, (unsigned long long)st.st_size, numblocks * blksize >> blk_shift, numblocks == 1 ? "" : "s", 1 << blk_shift); + if (use_extent_cache && + ioctl(fd, EXT4_IOC_GETSTATE, &state) == 0 && + (state & EXT4_STATE_FLAG_EXT_PRECACHED)) + fputs(" -- pre-cached", stdout); + fputc('\n', stdout); + } if (!force_bmap) { rc = filefrag_fiemap(fd, blk_shift, &num_extents, &st); expected = 0; + if (rc < 0 && + (use_extent_cache || precache_file || xattr_map)) { + if (rc != -EBADR) + fprintf(stderr, "%s: %s: %s\n ", + filename, + use_extent_cache ? + "EXT4_IOC_GET_ES_CACHE" : + "FS_IOC_FIEMAP", strerror(-rc)); + goto out_close; + } } if (force_bmap || rc < 0) { /* FIEMAP failed, try FIBMAP instead */ @@ -517,7 +558,7 @@ out_close: static void usage(const char *progname) { - fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeksvxX] file ...\n", + fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeEksvxX] file ...\n", progname); exit(1); } @@ -527,7 +568,7 @@ int main(int argc, char**argv) char **cpp; int rc = 0, c; - while ((c = getopt(argc, argv, "Bb::eksvxX")) != EOF) { + while ((c = getopt(argc, argv, "Bb::eEkPsvxX")) != EOF) { switch (c) { case 'B': force_bmap++; @@ -569,6 +610,9 @@ int main(int argc, char**argv) blocksize = 1024; } break; + case 'E': + use_extent_cache++; + /* fallthrough */ case 'e': force_extent++; if (!verbose) @@ -577,6 +621,9 @@ int main(int argc, char**argv) case 'k': blocksize = 1024; break; + case 'P': + precache_file++; + break; case 's': sync_file++; break; |