Re: [PATCH v3 2/2] fiemap: Implement ranged query

Eric Sandeen
2017-11-13T22:22:05Z

On 11/13/17 4:05 PM, Nikolay Borisov wrote:
>
>
> On 13.11.2017 23:44, Dave Chinner wrote:
>> On Mon, Nov 13, 2017 at 05:47:53PM +0200, Nikolay Borisov wrote:
>>> 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@suse.com>
>>> ---
>>> 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
>> .....
>>
>>> @@ -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) {
>>
>> Ok, you're not telling gotopt that "-r" has parameters, so....
>>
>>> 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;
>>
>> .... this is pretty nasty because you're having to check if the next
>> option should be parsed by the main loop or not. This assumes that
>> getopt is giving us the options in the order they were presented on
>> the command line, which is not a good assumption to make as glibc
>> can mutate the order as it parses the listi of know options and
>> arguments.
>>
>> Given that "-r" is the only option that has parameters, then this
>> can be massively simplified just by noting we've seen the rflag, and
>> leaving the non-arg parameter parsing to after the end of the loop.
>> i.e.:
>
>
> You are right this is a bit ugly, but it seems more consistend to me,
> rather than something like
>
> xfs_io -c "fiemap -r -n 10 -v 4k 10k" for example. And the reason why
> I'm using this hackish way and not declaring r as r: in getopt is
> because getopt doesn't recognise when a parameter takes more than 1
> argument.

Sorry for chiming in so late after all the go-rounds, but:

Why not just drop -r entirely, and make fiemap go into ranged mode iff a
range is specified at the end of the command, i.e.:

fiemap [ -alv ] [ -n nx ] [ offset length ]

and if no offset/length is specified, map the whole file. You can parse
the optional last 2 arguments just like pread, write, sync_range, sendfile,
or a host of other commands already do (though some are not optional.)

There are /many/ other xfs_io commands that take offset & length at the
end, so this usage should be very familiar to users.

-Eric