diff mbox series

xfs_io: add fiemap -s flag to print number of extents

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

Commit Message

Andrey Albershteyn Sept. 3, 2024, 9:37 a.m. UTC
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(-)

Comments

Andrey Albershteyn Sept. 3, 2024, 9:49 a.m. UTC | #1
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 mbox series

Patch

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;