Re: [PATCH] fiemap: Refactor fiemap + implement range parameters

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 11.08.2017 14:55, Nikolay Borisov wrote:
> fiemap's code was rather complicated for the simple task it did so this
> patch aims to rectify the situation. The main changes are:
> 
> * Add a start_offset, len parameters, this allows to specify a range of the
> file for which we want information, if those parameters are omitted the old
> behavior is retained i.e. we get information for the whole file.
> 
> * We now always allocate as many struct fiemap_extent structs as necessary
> to hold the information for the passed range (or the whole file)
> 
> * Made max_extents, blocksize global variables. They are never modified apart
> from the initilization of the program.
> 
> * Eliminated the outer while loop, now that we allocate enough extent to
> perform a single fiemap ioctl call there is no need for it.
> 
> * As a result the -n parameter works correctly for -n 1
> 
> * Also changed the way the last hole is being calculated, so far every time
> the outter while loop finished the extenet from last_logical .. file size would
> be output as a hole. This was not always true
> 
> Signed-off-by: Nikolay Borisov <nborisov@xxxxxxxx>
> ---
> 
> Hello, 
> 
> Here is more or less a major cleanup of the fiemap code. I've tested it with a 
> file with with the following layout HDHDHDHDHDHD (H - hole, D-data) and 
> varying permutation of the arguments and so far everthing seems to work as 
> expected. The biggest benefit I see is that the code is easier to follow now.

Ping


> 
> 
>  io/fiemap.c       | 187 +++++++++++++++++++++++++++++-------------------------
>  man/man8/xfs_io.8 |   5 +-
>  2 files changed, 104 insertions(+), 88 deletions(-)
> 
> diff --git a/io/fiemap.c b/io/fiemap.c
> index 75e882057362..5659f16d767d 100644
> --- a/io/fiemap.c
> +++ b/io/fiemap.c
> @@ -24,6 +24,8 @@
>  #include "io.h"
>  
>  static cmdinfo_t fiemap_cmd;
> +static const __u64 blocksize = 512;
> +static int max_extents = 0;
>  
>  static void
>  fiemap_help(void)
> @@ -34,6 +36,7 @@ fiemap_help(void)
>  "\n"
>  " Example:\n"
>  " 'fiemap -v' - tabular format verbose map\n"
> +" 'fiemap 0 4k' - print fiemap extents for 0-4k range\n"
>  "\n"
>  " fiemap prints the map of disk blocks used by the current file.\n"
>  " The map lists each extent used by the file, as well as regions in the\n"
> @@ -52,12 +55,10 @@ fiemap_help(void)
>  static void
>  print_verbose(
>  	struct fiemap_extent	*extent,
> -	int			blocksize,
>  	int			foff_w,
>  	int			boff_w,
>  	int			tot_w,
>  	int			flg_w,
> -	int			max_extents,
>  	int			*cur_extent,
>  	__u64			*last_logical)
>  {
> @@ -85,6 +86,7 @@ print_verbose(
>  			flg_w, _("FLAGS"));
>  	}
>  
> +
>  	if (lstart != llast) {
>  		snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", llast,
>  			 lstart - 1ULL);
> @@ -94,7 +96,7 @@ print_verbose(
>  		memset(lbuf, 0, sizeof(lbuf));
>  	}
>  
> -	if ((*cur_extent + 1) == max_extents)
> +	if (max_extents && *cur_extent == max_extents)
>  		return;
>  
>  	snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", lstart,
> @@ -112,8 +114,6 @@ static void
>  print_plain(
>  	struct fiemap_extent	*extent,
>  	int			lflag,
> -	int			blocksize,
> -	int			max_extents,
>  	int			*cur_extent,
>  	__u64			*last_logical)
>  {
> @@ -137,7 +137,7 @@ print_plain(
>  		(*cur_extent)++;
>  	}
>  
> -	if ((*cur_extent + 1) == max_extents)
> +	if (max_extents && *cur_extent == max_extents)
>  		return;
>  
>  	printf("\t%d: [%llu..%llu]: %llu..%llu", *cur_extent,
> @@ -159,13 +159,12 @@ print_plain(
>  static void
>  calc_print_format(
>  	struct fiemap		*fiemap,
> -	__u64			blocksize,
>  	int			*foff_w,
>  	int			*boff_w,
>  	int			*tot_w,
>  	int			*flg_w)
>  {
> -	int 			i;
> +	int			i;
>  	char			lbuf[32];
>  	char			bbuf[32];
>  	__u64			logical;
> @@ -193,15 +192,28 @@ calc_print_format(
>  	}
>  }
>  
> +static ssize_t
> +get_extent_num(int fd, __u64 startoffset, __u64 len)
> +{
> +	struct fiemap fiemap = { 0 } ;
> +	fiemap.fm_start = startoffset;
> +	fiemap.fm_length = len;
> +	if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long)&fiemap) < 0) {
> +		fprintf(stderr, _("%s: Failed to query fiemap extent count.\n"),
> +			progname);
> +		return -1;
> +	}
> +
> +	return fiemap.fm_mapped_extents;
> +}
> +
>  int
>  fiemap_f(
>  	int		argc,
>  	char		**argv)
>  {
>  	struct fiemap	*fiemap;
> -	int		max_extents = 0;
> -	int		num_extents = 32;
> -	int		last = 0;
> +	int		num_extents;
>  	int		lflag = 0;
>  	int		vflag = 0;
>  	int		fiemap_flags = FIEMAP_FLAG_SYNC;
> @@ -210,24 +222,29 @@ fiemap_f(
>  	int		map_size;
>  	int		ret;
>  	int		cur_extent = 0;
> -	int		foff_w = 16;	/* 16 just for a good minimum range */
> +	int		foff_w = 16; /* 16 just for a good minimum range */
>  	int		boff_w = 16;
>  	int		tot_w = 5;	/* 5 since its just one number */
>  	int		flg_w = 5;
> -	__u64		blocksize = 512;
>  	__u64		last_logical = 0;
> -	struct stat	st;
> +	__u64		len = -1LL;
> +	size_t		fsblocksize, fssectsize;
> +	off64_t		start_offset = 0;
> +	__u64		end_offset;
> +	__u64		llast;
> +	bool		last_extent = false;
> +
> +	init_cvtnum(&fsblocksize, &fssectsize);
>  
>  	while ((c = getopt(argc, argv, "aln:v")) != EOF) {
>  		switch (c) {
>  		case 'a':
>  			fiemap_flags |= FIEMAP_FLAG_XATTR;
>  			break;
> -		case 'l':
> -			lflag = 1;
> -			break;
>  		case 'n':
>  			max_extents = atoi(optarg);
> +		case 'l':
> +			lflag = 1;
>  			break;
>  		case 'v':
>  			vflag++;
> @@ -237,8 +254,35 @@ fiemap_f(
>  		}
>  	}
>  
> -	if (max_extents)
> -		num_extents = min(num_extents, max_extents);
> +	if (optind < argc) {
> +		start_offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
> +		if (start_offset < 0) {
> +			printf("non-numeric offset argument -- %s\n", argv[optind]);
> +			return 0;
> +		}
> +		last_logical = start_offset;
> +		optind++;
> +	}
> +
> +	if (optind < argc) {
> +		off64_t length = cvtnum(fsblocksize, fssectsize, argv[optind]);
> +		if (length < 0) {
> +			printf("non-numeric len argument -- %s\n", argv[optind]);
> +			return 0;
> +		}
> +		len = length;
> +	}
> +
> +
> +	end_offset = (start_offset + len) / blocksize;
> +
> +	ret = get_extent_num(file->fd, last_logical, len);
> +	if (ret < 0) {
> +		exitcode = 1;
> +		return 0;
> +	}
> +	num_extents = ret;
> +
>  	map_size = sizeof(struct fiemap) +
>  		(num_extents * sizeof(struct fiemap_extent));
>  	fiemap = malloc(map_size);
> @@ -251,92 +295,63 @@ fiemap_f(
>  
>  	printf("%s:\n", file->name);
>  
> -	while (!last && ((cur_extent + 1) != max_extents)) {
> -		if (max_extents)
> -			num_extents = min(num_extents,
> -					  max_extents - (cur_extent + 1));
> -
> -		memset(fiemap, 0, map_size);
> -		fiemap->fm_flags = fiemap_flags;
> -		fiemap->fm_start = last_logical;
> -		fiemap->fm_length = -1LL;
> -		fiemap->fm_extent_count = num_extents;
> -
> -		ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
> -		if (ret < 0) {
> -			fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
> -				"%s\n", progname, file->name, strerror(errno));
> -			free(fiemap);
> -			exitcode = 1;
> -			return 0;
> -		}
> +	memset(fiemap, 0, map_size);
> +	fiemap->fm_flags = fiemap_flags;
> +	fiemap->fm_start = last_logical;
> +	fiemap->fm_length = len;
> +	fiemap->fm_extent_count = num_extents;
>  
> -		/* No more extents to map, exit */
> -		if (!fiemap->fm_mapped_extents)
> -			break;
> +	ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
> +	if (ret < 0) {
> +		fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
> +			"%s\n", progname, file->name, strerror(errno));
> +		free(fiemap);
> +		exitcode = 1;
> +		return 0;
> +	}
> +
> +	for (i = 0; i < fiemap->fm_mapped_extents; i++) {
> +		struct fiemap_extent	*extent;
>  
> -		for (i = 0; i < fiemap->fm_mapped_extents; i++) {
> -			struct fiemap_extent	*extent;
> -
> -			extent = &fiemap->fm_extents[i];
> -			if (vflag) {
> -				if (cur_extent == 0) {
> -					calc_print_format(fiemap, blocksize,
> -							  &foff_w, &boff_w,
> -							  &tot_w, &flg_w);
> -				}
> -
> -				print_verbose(extent, blocksize, foff_w,
> -					      boff_w, tot_w, flg_w,
> -					      max_extents, &cur_extent,
> -					      &last_logical);
> -			} else
> -				print_plain(extent, lflag, blocksize,
> -					    max_extents, &cur_extent,
> -					    &last_logical);
> -
> -			if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
> -				last = 1;
> -				break;
> +		extent = &fiemap->fm_extents[i];
> +		if (vflag) {
> +			if (cur_extent == 0) {
> +				calc_print_format(fiemap, &foff_w, &boff_w,
> +						  &tot_w, &flg_w);
>  			}
>  
> -			if ((cur_extent + 1) == max_extents)
> -				break;
> -		}
> -	}
> +			print_verbose(extent, foff_w, boff_w, tot_w, flg_w,
> +				      &cur_extent, &last_logical);
> +		} else
> +			print_plain(extent, lflag, &cur_extent, &last_logical);
>  
> -	if ((cur_extent + 1) == max_extents)
> -		goto out;
> +		if (max_extents && cur_extent == max_extents)
> +			goto out;
> +
> +		if (extent->fe_flags & FIEMAP_EXTENT_LAST)
> +			last_extent = true;
>  
> -	memset(&st, 0, sizeof(st));
> -	if (fstat(file->fd, &st)) {
> -		fprintf(stderr, "%s: fstat failed: %s\n", progname,
> -			strerror(errno));
> -		free(fiemap);
> -		exitcode = 1;
> -		return 0;
>  	}
>  
> -	if (cur_extent && last_logical < st.st_size) {
> -		char	lbuf[32];
> +	llast = last_logical / blocksize;
> +	if (!last_extent && llast < end_offset) {
> +		char lbuf[32];
> +		__u64 difference = end_offset - llast;
> +		snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", llast, llast + difference);
>  
> -		snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
> -			 last_logical / blocksize, (st.st_size / blocksize) - 1);
>  		if (vflag) {
>  			printf("%4d: %-*s %-*s %*llu\n", cur_extent,
>  			       foff_w, lbuf, boff_w, _("hole"), tot_w,
> -			       (st.st_size - last_logical) / blocksize);
> +			       difference);
>  		} else {
>  			printf("\t%d: %s %s", cur_extent, lbuf,
>  			       _("hole"));
>  			if (lflag)
> -				printf(_(" %llu blocks\n"),
> -				       (st.st_size - last_logical) / blocksize);
> +				printf(_(" %llu blocks\n"), len / blocksize);
>  			else
>  				printf("\n");
>  		}
>  	}
> -
>  out:
>  	free(fiemap);
>  	return 0;
> @@ -350,7 +365,7 @@ fiemap_init(void)
>  	fiemap_cmd.argmin = 0;
>  	fiemap_cmd.argmax = -1;
>  	fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
> -	fiemap_cmd.args = _("[-alv] [-n nx]");
> +	fiemap_cmd.args = _("[-alv] [-n nx] [start offset [len]]");
>  	fiemap_cmd.oneline = _("print block mapping for a file");
>  	fiemap_cmd.help = fiemap_help;
>  
> diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> index 273b9c54c52d..125db9181851 100644
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -295,11 +295,12 @@ Prints the block mapping for the current open file. Refer to the
>  .BR xfs_bmap (8)
>  manual page for complete documentation.
>  .TP
> -.BI "fiemap [ \-alv ] [ \-n " nx " ]"
> +.BI "fiemap [ \-alv ] [ \-n " nx " ] [ " offset " [ " len " ]]"
>  Prints the block mapping for the current open file using the fiemap
>  ioctl.  Options behave as described in the
>  .BR xfs_bmap (8)
> -manual page.
> +manual page. Optionally, this command also supports passing the start offset 
> +from where to begin the fiemap and the length of that region.
>  .TP
>  .BI "fsmap [ \-d | \-l | \-r ] [ \-m | \-v ] [ \-n " nx " ] [ " start " ] [ " end " ]
>  Prints the mapping of disk blocks used by the filesystem hosting the current
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux