Currently the fiemap implementation of xfs_io doesn't support making ranged queries. This patch implements the '-r' parameter, taking up to 2 arguments - the starting offset and the length of the region to be queried. This also requires changing of the final hole range is calculated. Namely, it's now being done as [last_logical, logical addres of next extent] rather than being statically determined by [last_logical, filesize]. Signed-off-by: Nikolay Borisov <nborisov@xxxxxxxx> --- V3: * Fixed a bug where incorrect extent index was shown if we didn't print a hole. This was due to statically returning 2 at the end of print_(plain|verbose) Now, the actual number of printed extents inside the 2 functions is used. This bug is visible only with the -r parameter * Fixed a bug where 1 additional extent would be printed. This was a result of the aforementioned bug fix, since now printing function can return 1 and still have printed an extent and no hole. This can happen when you use -r parameter, this is now fixed and a comment explaining it is put. * Reworked the handling of the new params by making them arguments to the -r parameter. V2: * Incorporated Daricks feedback - removed variables which weren't introduced until the next patch as a result the build with this patch was broken. This is fixed now io/fiemap.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++------- man/man8/xfs_io.8 | 5 ++- 2 files changed, 107 insertions(+), 17 deletions(-) diff --git a/io/fiemap.c b/io/fiemap.c index 08391f69d9bd..018f3d064ab2 100644 --- a/io/fiemap.c +++ b/io/fiemap.c @@ -27,6 +27,9 @@ static cmdinfo_t fiemap_cmd; static int max_extents = -1; +static __u64 covered_length = 0; +static __u64 len = -1LL; +static bool range_limit = false; static void fiemap_help(void) @@ -79,7 +82,7 @@ print_hole( boff_w, _("hole"), tot_w, lstart - llast); } - + covered_length += BBTOB(lstart - llast); } static int @@ -90,7 +93,8 @@ print_verbose( int tot_w, int flg_w, int cur_extent, - __u64 last_logical) + __u64 last_logical, + __u64 limit) { __u64 lstart; __u64 llast; @@ -99,6 +103,7 @@ print_verbose( char lbuf[48]; char bbuf[48]; char flgbuf[16]; + int num_printed = 0; llast = BTOBBT(last_logical); lstart = BTOBBT(extent->fe_logical); @@ -120,10 +125,11 @@ print_verbose( print_hole(foff_w, boff_w, tot_w, cur_extent, 0, false, llast, lstart); cur_extent++; + num_printed = 1; } - if (cur_extent == max_extents) - return 1; + if (cur_extent == max_extents || (range_limit && covered_length >= limit)) + return num_printed; snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", lstart, lstart + len - 1ULL); @@ -132,7 +138,9 @@ print_verbose( printf("%4d: %-*s %-*s %*llu %*s\n", cur_extent, foff_w, lbuf, boff_w, bbuf, tot_w, len, flg_w, flgbuf); - return 2; + num_printed++; + + return num_printed; } static int @@ -140,12 +148,14 @@ print_plain( struct fiemap_extent *extent, int lflag, int cur_extent, - __u64 last_logical) + __u64 last_logical, + __u64 limit) { __u64 lstart; __u64 llast; __u64 block; __u64 len; + int num_printed = 0; llast = BTOBBT(last_logical); lstart = BTOBBT(extent->fe_logical); @@ -155,20 +165,23 @@ print_plain( if (lstart != llast) { print_hole(0, 0, 0, cur_extent, lflag, true, llast, lstart); cur_extent++; + num_printed = 1; } - if (cur_extent == max_extents) - return 1; + if (cur_extent == max_extents || (range_limit && covered_length >= limit)) + return num_printed; printf("\t%d: [%llu..%llu]: %llu..%llu", cur_extent, lstart, lstart + len - 1ULL, block, block + len - 1ULL); + num_printed++; + if (lflag) printf(_(" %llu blocks\n"), len); else printf("\n"); - return 2; + return num_printed; } /* @@ -256,9 +269,12 @@ fiemap_f( int tot_w = 5; /* 5 since its just one number */ int flg_w = 5; __u64 last_logical = 0; + size_t fsblocksize, fssectsize; struct stat st; - while ((c = getopt(argc, argv, "aln:v")) != EOF) { + init_cvtnum(&fsblocksize, &fssectsize); + + while ((c = getopt(argc, argv, "aln:vr")) != EOF) { switch (c) { case 'a': fiemap_flags |= FIEMAP_FLAG_XATTR; @@ -272,6 +288,50 @@ fiemap_f( case 'v': vflag++; break; + case 'r': + /* Parse the first option which is mandatory */ + if (optind < argc && argv[optind][0] != '-') { + off64_t 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++; + } else { + fprintf(stderr, _("Invalid offset argument for" + " -r\n")); + exitcode = 1; + return 0; + } + + if (optind < argc) { + /* first check if what follows doesn't begin + * with '-' which means it would be a param and + * not an argument + */ + if (argv[optind][0] == '-') { + optind--; + break; + + } + + off64_t length = cvtnum(fsblocksize, + fssectsize, + argv[optind]); + if (length < 0) { + printf("non-numeric len argument --" + " %s\n", argv[optind]); + return 0; + } + len = length; + range_limit = true; + } + break; + default: return command_usage(&fiemap_cmd); } @@ -317,14 +377,23 @@ fiemap_f( num_printed = print_verbose(extent, foff_w, boff_w, tot_w, flg_w, cur_extent, - last_logical); + last_logical, + len); } else num_printed = print_plain(extent, lflag, cur_extent, - last_logical); + last_logical, + len); cur_extent += num_printed; last_logical = extent->fe_logical + extent->fe_length; + /* If num_printed > 0 then we dunno if we have printed + * a hole or an extent and a hole but we don't really + * care. Termination of the loop is still going to be + * correct + */ + if (num_printed) + covered_length += extent->fe_length; if (extent->fe_flags & FIEMAP_EXTENT_LAST) { last = 1; @@ -333,6 +402,9 @@ fiemap_f( if (cur_extent == max_extents) break; + + if (range_limit && covered_length >= len) + goto out; } } @@ -348,9 +420,26 @@ fiemap_f( return 0; } - if (cur_extent && last_logical < st.st_size) + if (last_logical < st.st_size && + (!range_limit || covered_length < len)) { + int end; + + ret = __fiemap(fiemap, map_size, fiemap_flags, last_logical, + st.st_size); + if (ret < 0) { + exitcode = 1; + goto out; + } + + if (!fiemap->fm_mapped_extents) + end = BTOBBT(st.st_size); + else + end = BTOBBT(fiemap->fm_extents[0].fe_logical); + + print_hole(foff_w, boff_w, tot_w, cur_extent, lflag, !vflag, - BTOBBT(last_logical), BTOBBT(st.st_size)); + BTOBBT(last_logical), end); + } out: free(fiemap); @@ -365,7 +454,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] [-r 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 0fd9b951199c..5a00e02c94b7 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 " ] [ \-r " 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 -- 2.7.4 -- 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