Message ID | 20240903093729.1282981-2-aalbersh@redhat.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | xfs_io: add fiemap -s flag to print number of extents | expand |
NACK haven't noticed that FIEMAP also doesn't count holes ignore On 2024-09-03 11:37:30, Andrey Albershteyn wrote: > FS_IOC_FIEMAP has an option to return total number of extents > without copying each one of them. This could be pretty handy for > checking if large file is heavily fragmented. The same can be done > with calling FS_IOC_FIEMAP and counting lines with wc but > FS_IOC_FIEMAP is limited to ~76mil extents (FIEMAP_MAX_EXTENTS). The > other option is FS_IOC_FSGETXATTR which is much faster than > iterating through all extents, but it doesn't include holes. > > Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> > --- > io/fiemap.c | 27 +++++++++++++++++++++++---- > 1 file changed, 23 insertions(+), 4 deletions(-) > > diff --git a/io/fiemap.c b/io/fiemap.c > index b41f71bfd027..d4e55a82f6db 100644 > --- a/io/fiemap.c > +++ b/io/fiemap.c > @@ -42,6 +42,13 @@ fiemap_help(void) > "\n")); > } > > +static void > +print_total( > + struct fiemap *fiemap) > +{ > + printf("Extents total: %d\n", fiemap->fm_mapped_extents); > +} > + > static void > print_hole( > int foff_w, > @@ -223,9 +230,11 @@ fiemap_f( > int done = 0; > int lflag = 0; > int vflag = 0; > + int sflag = 0; > int fiemap_flags = FIEMAP_FLAG_SYNC; > int c; > int i; > + int ext_arr_size = 0; > int map_size; > int ret; > int cur_extent = 0; > @@ -242,7 +251,7 @@ fiemap_f( > > init_cvtnum(&fsblocksize, &fssectsize); > > - while ((c = getopt(argc, argv, "aln:v")) != EOF) { > + while ((c = getopt(argc, argv, "aln:sv")) != EOF) { > switch (c) { > case 'a': > fiemap_flags |= FIEMAP_FLAG_XATTR; > @@ -253,6 +262,9 @@ fiemap_f( > case 'n': > max_extents = atoi(optarg); > break; > + case 's': > + sflag++; > + break; > case 'v': > vflag++; > break; > @@ -285,8 +297,9 @@ fiemap_f( > range_end = start_offset + length; > } > > - map_size = sizeof(struct fiemap) + > - (EXTENT_BATCH * sizeof(struct fiemap_extent)); > + if (!sflag) > + ext_arr_size = (EXTENT_BATCH * sizeof(struct fiemap_extent)); > + map_size = sizeof(struct fiemap) + ext_arr_size; > fiemap = malloc(map_size); > if (!fiemap) { > fprintf(stderr, _("%s: malloc of %d bytes failed.\n"), > @@ -302,7 +315,8 @@ fiemap_f( > fiemap->fm_flags = fiemap_flags; > fiemap->fm_start = last_logical; > fiemap->fm_length = range_end - last_logical; > - fiemap->fm_extent_count = EXTENT_BATCH; > + if (!sflag) > + fiemap->fm_extent_count = EXTENT_BATCH; > > ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap); > if (ret < 0) { > @@ -313,6 +327,11 @@ fiemap_f( > return 0; > } > > + if (sflag) { > + print_total(fiemap); > + goto out; > + } > + > /* No more extents to map, exit */ > if (!fiemap->fm_mapped_extents) > break; > -- > 2.44.1 >
diff --git a/io/fiemap.c b/io/fiemap.c index b41f71bfd027..d4e55a82f6db 100644 --- a/io/fiemap.c +++ b/io/fiemap.c @@ -42,6 +42,13 @@ fiemap_help(void) "\n")); } +static void +print_total( + struct fiemap *fiemap) +{ + printf("Extents total: %d\n", fiemap->fm_mapped_extents); +} + static void print_hole( int foff_w, @@ -223,9 +230,11 @@ fiemap_f( int done = 0; int lflag = 0; int vflag = 0; + int sflag = 0; int fiemap_flags = FIEMAP_FLAG_SYNC; int c; int i; + int ext_arr_size = 0; int map_size; int ret; int cur_extent = 0; @@ -242,7 +251,7 @@ fiemap_f( init_cvtnum(&fsblocksize, &fssectsize); - while ((c = getopt(argc, argv, "aln:v")) != EOF) { + while ((c = getopt(argc, argv, "aln:sv")) != EOF) { switch (c) { case 'a': fiemap_flags |= FIEMAP_FLAG_XATTR; @@ -253,6 +262,9 @@ fiemap_f( case 'n': max_extents = atoi(optarg); break; + case 's': + sflag++; + break; case 'v': vflag++; break; @@ -285,8 +297,9 @@ fiemap_f( range_end = start_offset + length; } - map_size = sizeof(struct fiemap) + - (EXTENT_BATCH * sizeof(struct fiemap_extent)); + if (!sflag) + ext_arr_size = (EXTENT_BATCH * sizeof(struct fiemap_extent)); + map_size = sizeof(struct fiemap) + ext_arr_size; fiemap = malloc(map_size); if (!fiemap) { fprintf(stderr, _("%s: malloc of %d bytes failed.\n"), @@ -302,7 +315,8 @@ fiemap_f( fiemap->fm_flags = fiemap_flags; fiemap->fm_start = last_logical; fiemap->fm_length = range_end - last_logical; - fiemap->fm_extent_count = EXTENT_BATCH; + if (!sflag) + fiemap->fm_extent_count = EXTENT_BATCH; ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap); if (ret < 0) { @@ -313,6 +327,11 @@ fiemap_f( return 0; } + if (sflag) { + print_total(fiemap); + goto out; + } + /* No more extents to map, exit */ if (!fiemap->fm_mapped_extents) break;
FS_IOC_FIEMAP has an option to return total number of extents without copying each one of them. This could be pretty handy for checking if large file is heavily fragmented. The same can be done with calling FS_IOC_FIEMAP and counting lines with wc but FS_IOC_FIEMAP is limited to ~76mil extents (FIEMAP_MAX_EXTENTS). The other option is FS_IOC_FSGETXATTR which is much faster than iterating through all extents, but it doesn't include holes. Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> --- io/fiemap.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)