diff --git a/lib/ext2fs/fiemap.h b/lib/ext2fs/fiemap.h index 895cd0b..e1e1f75 100644 --- a/lib/ext2fs/fiemap.h +++ b/lib/ext2fs/fiemap.h @@ -17,9 +17,12 @@ struct fiemap_extent { __u64 fe_physical; /* physical offset in bytes for the start * of the extent from the beginning of the disk */ __u64 fe_length; /* length in bytes for this extent */ - __u64 fe_reserved64[2]; + __u64 fe_reserved64[1]; + __u64 fe_loglength;/* logical extent length + * if FIEMAP_EXTENT_LOGLENGTH */ __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */ - __u32 fe_reserved[3]; + __u32 fe_reserved[2]; + __u32 fe_pdev; /* physical dev_t if FIEMAP_EXTENT_PHYSICAL */ }; struct fiemap { @@ -44,6 +47,7 @@ struct fiemap { #define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */ #define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) +#define FIEMAP_FLAG_PHYSICAL 0x80000000 /* report physical device extents */ #define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */ #define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */ @@ -66,5 +70,10 @@ struct fiemap { * merged for efficiency. */ #define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other * files. */ +#define FIEMAP_EXTENT_LOGLENGTH 0x20000000 /* fe_loglength is valid. */ +#define FIEMAP_EXTENT_MORESTRIPE 0x40000000 /* One ore more physical + * extent will follow. */ +#define FIEMAP_EXTENT_PHYSICAL 0x80000000 /* This extent represents + * physical device */ #endif /* _LINUX_FIEMAP_H */ diff --git a/misc/filefrag.8.in b/misc/filefrag.8.in index a6d7b27..bd82642 100644 --- a/misc/filefrag.8.in +++ b/misc/filefrag.8.in @@ -8,7 +8,7 @@ filefrag \- report on file fragmentation .BI \-b blocksize ] [ -.B \-BeksvxX +.B \-BekPsvxX ] [ .I files... @@ -46,6 +46,16 @@ Print output in extent format, even for block-mapped files. .BI \-k Use 1024\-byte blocksize for output (identical to '\-b 1024'). .TP +.B \-P +Report physical fragmentation. +This option is currently valid only for BTRFS files which have "virtual" +medium offsets that do not directly represent physical medium offsets. +If this option is given with the -v option, +the physical deivce ID (major and minor IDs) +instead of "expected" offsets and actual physical mudium offsets +are reported. If the BTRFS filesystem has redundancy (i.e. RAID1 or RAID10), +all underlying physical extents are reported for each logical extent. +.TP .B \-s Sync the file before requesting the mapping. .TP diff --git a/misc/filefrag.c b/misc/filefrag.c index 929a33b..29a0816 100644 --- a/misc/filefrag.c +++ b/misc/filefrag.c @@ -54,6 +54,7 @@ int logical_width = 8; int physical_width = 10; const char *ext_fmt = "%4d: %*llu..%*llu: %*llu..%*llu: %6llu: %s\n"; const char *hex_fmt = "%4d: %*llx..%*llx: %*llx..%*llx: %6llx: %s\n"; +int physical = 0; #define FILEFRAG_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) @@ -120,8 +121,8 @@ static void print_extent_header(void) logical_width * 2 + 3, "logical_offset:", physical_width * 2 + 3, "physical_offset:", - physical_width + 1, - "expected:"); + physical ? 0 : physical_width + 1, + physical ? "device:" : "expected:"); } static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, @@ -132,6 +133,8 @@ 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 lext_blks; + unsigned long long logical_len; char flags[256] = ""; /* For inline data all offsets should be in bytes, not blocks */ @@ -140,10 +143,20 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, ext_len = fm_extent->fe_length >> blk_shift; ext_blks = (fm_extent->fe_length - 1) >> blk_shift; + logical_len = (fm_extent->fe_flags & FIEMAP_EXTENT_LOGLENGTH) ? + fm_extent->fe_loglength : fm_extent->fe_length; + lext_blks = (logical_len - 1) >> blk_shift; logical_blk = fm_extent->fe_logical >> blk_shift; physical_blk = fm_extent->fe_physical >> blk_shift; - if (expected) + if (physical) { + if (fm_extent->fe_flags & FIEMAP_EXTENT_PHYSICAL) + sprintf(flags, "%3d:%-3d ", + major(fm_extent->fe_pdev), + minor(fm_extent->fe_pdev)); + else + strcat(flags, " "); + } else if (expected) sprintf(flags, ext_fmt == hex_fmt ? "%*llx: " : "%*llu: ", physical_width, expected >> blk_shift); else @@ -168,7 +181,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, if (fm_extent->fe_flags & FIEMAP_EXTENT_SHARED) strcat(flags, "shared,"); - if (fm_extent->fe_logical + fm_extent->fe_length >= (__u64) st->st_size) + if (fm_extent->fe_logical + logical_len >= (__u64) st->st_size) strcat(flags, "eof,"); /* Remove trailing comma, if any */ @@ -176,7 +189,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, flags[strlen(flags) - 1] = '\0'; printf(ext_fmt, cur_ex, logical_width, logical_blk, - logical_width, logical_blk + ext_blks, + logical_width, logical_blk + lext_blks, physical_width, physical_blk, physical_width, physical_blk + ext_blks, ext_len, flags); @@ -207,7 +220,12 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, if (xattr_map) flags |= FIEMAP_FLAG_XATTR; + if (physical) + flags |= FIEMAP_FLAG_PHYSICAL; + do { + __u64 next_start = 0; + fiemap->fm_length = ~0ULL; fiemap->fm_flags = flags; fiemap->fm_extent_count = count; @@ -243,17 +261,26 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, print_extent_info(&fm_ext[i], n, expected, blk_shift, st); + next_start = fm_ext[i].fe_logical + + ((fm_ext[i].fe_flags & FIEMAP_EXTENT_LOGLENGTH) ? + fm_ext[i].fe_loglength : + fm_ext[i].fe_length); expected = fm_ext[i].fe_physical + fm_ext[i].fe_length; if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST) last = 1; - n++; + if (!physical || + !(fm_ext[i].fe_flags & FIEMAP_EXTENT_MORESTRIPE)) { + n++; + } + if (physical && + !(fm_ext[i].fe_flags & FIEMAP_EXTENT_MORESTRIPE)) + break; } - fiemap->fm_start = (fm_ext[i - 1].fe_logical + - fm_ext[i - 1].fe_length); + fiemap->fm_start = next_start; } while (last == 0); - *num_extents = tot_extents; + *num_extents = physical ? n : tot_extents; return 0; } @@ -449,7 +476,7 @@ out_close: static void usage(const char *progname) { - fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeklsvxX] file ...\n", + fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeklPsvxX] file ...\n", progname); exit(1); } @@ -459,7 +486,7 @@ int main(int argc, char**argv) char **cpp; int c; - while ((c = getopt(argc, argv, "Bb::eksvxX")) != EOF) + while ((c = getopt(argc, argv, "Bb::ekPsvxX")) != EOF) switch (c) { case 'B': force_bmap++; @@ -511,6 +538,9 @@ int main(int argc, char**argv) case 'x': xattr_map++; break; + case 'P': + physical = 1; + break; case 'X': ext_fmt = hex_fmt; break;