All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Sandeen <sandeen@sandeen.net>
To: Mark Tinguely <tinguely@sgi.com>
Cc: xfs@oss.sgi.com
Subject: Re: [PATCH] xfs_io: add the lseek() SEEK_DATA/SEEK_HOLE support
Date: Wed, 21 Aug 2013 11:28:28 -0500	[thread overview]
Message-ID: <5214EAAC.80800@sandeen.net> (raw)
In-Reply-To: <5214CB5C.4050608@sgi.com>

On 8/21/13 9:14 AM, Mark Tinguely wrote:
> 
> This patch started as an xfstest to test Jeff's advanced seek_data features. The C code we had for that feature was deemed as an xfs_io feature.

*nod*

Forgive me for looking more carefully now than then, sorry.

Argh, and for missing that you're already on V5, I missed
the previous reviews.  Well, I did find at least one speling eror,
so there's that.  But more below...

> On 08/20/13 18:07, Eric Sandeen wrote:
>> On 8/16/13 3:54 PM, Mark Tinguely wrote:
>>
>>> Add the lseek SEEK_DATA/SEEK_HOLE support into xfs_io.
>>> The result from the lseek() call will be printed to the output.
>>> For example:
>>>
>>> xfs_io>  lseek -h 609k
>>> Type    Offset
>>> hole    630784
>>
>> HOLE not hole, I guess.  ;)
>>
>> I was going to say that's a lot of verbosity for a single output,
>> but I guess the other options might have many lines, so I suppose
>> it makes sense.
>>
>> (I was just thinking about what xfstests might need to do to filter
>> &  parse output...)
> 
> parsing is a bear because there are multiple correct answers.
> There is always a legal hole at EOF and that if SEEK_HOLE is not implemented that is the answer they give.
> 
> Different versions of XFS seek_data code will give different answer to the same test depending on what is supported in that version.
> 
>>
>>> Signed-off-by: Mark Tinguely<tinguely@sgi.com>
>>> ---
>>>   Not trying to be difficult. Dave wanted the single hole/data/hole and data
>>>   seperated from the recursive loop, but doing it that way is basically unrolling
>>>   the loop into a if-then-else and is really terrible. If this is still not
>>>   acceptable, then we can throw this feature into /dev/null.
>>>
>>>   configure.ac          |    1
>>>   include/builddefs.in  |    1
>>>   io/Makefile           |    5 +
>>>   io/init.c             |    1
>>>   io/io.h               |    6 +
>>>   io/seek.c             |  187 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   m4/package_libcdev.m4 |   15 ++++
>>>   man/man8/xfs_io.8     |   35 +++++++++
>>>   8 files changed, 251 insertions(+)
>>>
>>> Index: b/configure.ac
>>> ===================================================================
>>> --- a/configure.ac
>>> +++ b/configure.ac
>>> @@ -110,6 +110,7 @@ AC_HAVE_GETMNTINFO
>>>   AC_HAVE_FALLOCATE
>>>   AC_HAVE_FIEMAP
>>>   AC_HAVE_PREADV
>>> +AC_HAVE_SEEK_DATA
>>>   AC_HAVE_SYNC_FILE_RANGE
>>>   AC_HAVE_BLKID_TOPO($enable_blkid)
>>>   AC_HAVE_READDIR
>>> Index: b/include/builddefs.in
>>> ===================================================================
>>> --- a/include/builddefs.in
>>> +++ b/include/builddefs.in
>>> @@ -102,6 +102,7 @@ HAVE_GETMNTINFO = @have_getmntinfo@
>>>   HAVE_FALLOCATE = @have_fallocate@
>>>   HAVE_FIEMAP = @have_fiemap@
>>>   HAVE_PREADV = @have_preadv@
>>> +HAVE_SEEK_DATA = @have_seek_data@
>>>   HAVE_SYNC_FILE_RANGE = @have_sync_file_range@
>>>   HAVE_READDIR = @have_readdir@
>>>
>>> Index: b/io/Makefile
>>> ===================================================================
>>> --- a/io/Makefile
>>> +++ b/io/Makefile
>>> @@ -85,6 +85,11 @@ CFILES += readdir.c
>>>   LCFLAGS += -DHAVE_READDIR
>>>   endif
>>>
>>> +ifeq ($(HAVE_SEEK_DATA),yes)
>>> +LCFLAGS += -DHAVE_SEEK_DATA
>>> +CFILES += seek.c
>>
>> see below; we should unconditionally compile, but conditionally
>> locally define SEEK_DATA / SEEK_HOLE
>>
> 
> It was put in to check if SEEK_DATA is supported.
> 
> Yes, it expects the user headers to reflect what the kernel is capable of doing.

well, especially on a development system, the installed headers may not
reflect or match the running kernel.

So even if system headers don't have SEEK_DATA it, the running kernel may
still be capable of it, right?

We've done similar things for i.e. fallocate PUNCH_HOLE.

> If you don't want it, then it will be removed.

I think it makes sense to build it & locally define if necessary.
On my RHEL6 root w/ an upstream devel kernel seek.c wouldn't have
built, even though it'd have worked perfectly w/ a local define.

>>> +endif
>>> +
>>>   default: depend $(LTCOMMAND)
>>>
>>>   include $(BUILDRULES)
>>> Index: b/io/init.c
>>> ===================================================================
>>> --- a/io/init.c
>>> +++ b/io/init.c
>>> @@ -64,6 +64,7 @@ init_commands(void)
>>>       help_init();
>>>       imap_init();
>>>       inject_init();
>>> +    seek_init();
>>>       madvise_init();
>>>       mincore_init();
>>>       mmap_init();
>>> Index: b/io/io.h
>>> ===================================================================
>>> --- a/io/io.h
>>> +++ b/io/io.h
>>> @@ -108,6 +108,12 @@ extern void        quit_init(void);
>>>   extern void        shutdown_init(void);
>>>   extern void        truncate_init(void);
>>>
>>> +#ifdef HAVE_SEEK_DATA
>>> +extern void        seek_init(void);
>>> +#else
>>> +#define seek_init()    do { } while (0)
>>> +#endif
>>
>> this can go when we unconditionally compile it in
>>
>>> +
>>>   #ifdef HAVE_FADVISE
>>>   extern void        fadvise_init(void);
>>>   #else
>>> Index: b/io/seek.c
>>> ===================================================================
>>> --- /dev/null
>>> +++ b/io/seek.c
>>> @@ -0,0 +1,187 @@
>>> +/*
>>> + * Copyright (c) 2013 SGI
>>> + * All Rights Reserved.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it would be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program; if not, write the Free Software Foundation,
>>> + * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
>>> + */
>>> +
>>> +#include<libxfs.h>
>>
>> hm, including this clashes w/ the min() define in io/init.h,
>> which is maybe a separate problem down the line, but libxfs.h
>> isn't required anyway for this file, so I'd just drop this include.
>>
>>> +#include<linux/fs.h>
> 
> I think the previous review had a problem with this header which should be removed.

oh yeah, Dave did ask (now that I'm caught up with the last 4 reviews) :(

And yeah it builds fine w/o either libxfs.h or linux/fs.h, so I'd just yank
'em both.

>>> +
>>> +#include<sys/uio.h>
>>> +#include<xfs/xfs.h>
>>> +#include<xfs/command.h>
>>> +#include<xfs/input.h>
>>> +#include<ctype.h>
>>> +#include "init.h"
>>> +#include "io.h"
>>
>> #ifndef HAVE_SEEK_DATA
>> #define SEEK_DATA       3       /* seek to the next data */
>> #define SEEK_HOLE       4       /* seek to the next hole */
>> #endif
>>
>>> +
>>> +static cmdinfo_t seek_cmd;
>>> +
>>> +static void
>>> +seek_help(void)
>>> +{
>>> +    printf(_(
>>> +"\n"
>>> +" returns the next hole and/or data offset at or after the specified offset\n"
>>> +"\n"
>>> +" Example:\n"
>>> +" 'seek -d 512'   - offset of data at or following offset 512\n"
>>> +" 'seek -a -r 0'  - offsets of all data and hole in entire file\n"
>>> +"\n"
>>> +" Returns the offset of the next data and/or hole. There is an implied hole\n"
>>> +" at the end of file.
>>
>> is this expected, given the hole at the end of the file?  This is for a single
>> non-sparse file:
>>
>> xfs_io>  seek -ar 0
>> Type    offset
>> DATA    0
>> HOLE    3022
>> DATA    EOF
>>
>> That last line doesn't make sense, does it?
> 
> Parsing is the reason the entry is there so the output always has
> consistent ending entry - some queries that is the only answer (or
> now no message) no biggy one way or the other.

Hm, ok, clearly you've thought about this more than I have.
It just surprised me...

So let me just think out loud here w/ examples.

For a 1M 100% nonsparse file we get:

# io/xfs_io -c "seek -ar 0" alldata
Type	offset
DATA	0
HOLE	1048576
DATA	EOF

For a 1M 100% sparse file (i_size and no blocks at all) we get:

# io/xfs_io -c "seek -ar 0" allsparse 
Type	offset
HOLE	0
DATA	EOF

For a 1M file w/ only the first 512k w/ data, then hole,
we get:

# io/xfs_io -c "seek -ar 0" endhole 
Type	offset
DATA	0
HOLE	524288
DATA	EOF

For a 1M file w/ 512k of hole and then 512k w/ data, we get:

# io/xfs_io -c "seek -ar 0" starthole 
Type	offset
HOLE	0
DATA	524288
HOLE	1048576
DATA	EOF

So in each case, the "DATA  EOF" at the end seems odd to me.

And in each case above, the output is unique w/o the EOF flag
anwyway, right?

I'm probably missing it; in what cases is the EOF record
useful?  It just seems beyond the scope of SEEK_HOLE/SEEK_DATA.
(i.e. EOF is SEEK_END)

If the EOF is really helpful, maybe it is possible instead to do something like:

# io/xfs_io -c "seek -ar 0" starthole 
Type	offset
HOLE	0
DATA	524288
EOF	1048575
HOLE	1048576

That makes more intuitive sense to me if you really need the EOF
record, but I dunno, what do you think?

>>
>>> If the specified offset is past end of file, or there\n"
>>> +" is no data past the specied offset, EOF is returned.\n"
>>
>> "specified"
>>
>>> +" -a   -- return the next data and hole starting at the specified offset.\n"
>>> +" -d   -- return the next data starting at the specified offset.\n"
>>> +" -h   -- return the next hole starting at the specified offset.\n"
>>> +" -r   -- return all remaining type(s) starting at the specified offset.\n"
>>> +"\n"));
>>> +}
>>> +
>>> +#define    SEEK_DFLAG    (1<<  0)
>>> +#define    SEEK_HFLAG    (1<<  1)
>>> +#define    SEEK_RFLAG    (1<<  2)
>>> +#define    DATA        0
>>> +#define    HOLE        1
>>> +
>>> +struct seekinfo {
>>> +    char        *name;
>>> +    int        seektype;
>>> +    int        mask;
>>> +} seekinfo[] = {
>>> +        {"DATA", SEEK_DATA, SEEK_DFLAG},
>>> +        {"HOLE", SEEK_HOLE, SEEK_HFLAG}
>>
>> I guess "DATA" doesn't get replaced by "0" ?  Sorry, I failed cpp 101.
>> It prints the right thing so I guess not.  ;)
>>
> 
> :) no the defines are subscripts = see "current ="

I did see that, I just wasn't sure if it'd replace it in literal
strings, but apparently not.

> 
>>> +};
>>> +
>>> +void
>>> +seek_output(
>>> +    char    *type,
>>> +    off64_t    offset)
>>> +{
>>> +    if (offset == -1) {
>>> +        if (errno == ENXIO)
>>> +            printf("%s    EOF\n", type);
>>> +        else
>>> +            printf("%s    ERR %d\n", type, errno);
>>> +    } else
>>> +        printf("%s    %ld\n", type, offset);

one more; for 32-bit systems I think this should be

printf("%s    %lld\n", type, (long long)offset);

to avoid a warning; that's what i.e. the pwrite printf's do.

>>> +}
>>> +
>>> +static int
>>> +seek_f(
>>> +    int    argc,
>>> +    char    **argv)
>>> +{
>>> +    off64_t        offset, result;
>>> +    size_t          fsblocksize, fssectsize;
>>> +    int        flag;
>>> +    int        current;    /* specify data or hole */
>>> +    int        c;
>>> +
>>> +    flag = 0;
>>> +    init_cvtnum(&fsblocksize,&fssectsize);
>>> +
>>> +    while ((c = getopt(argc, argv, "adhr")) != EOF) {
>>> +        switch (c) {
>>> +        case 'a':
>>> +            flag |= (SEEK_HFLAG | SEEK_DFLAG);
>>> +            break;
>>> +        case 'd':
>>> +            flag |= SEEK_DFLAG;
>>> +            break;
>>> +        case 'h':
>>> +            flag |= SEEK_HFLAG;
>>> +            break;
>>> +        case 'r':
>>> +            flag |= SEEK_RFLAG;
>>> +            break;
>>> +        default:
>>> +            return command_usage(&seek_cmd);
>>> +        }
>>> +    }
>>> +        /* must have hole or data specified and an offset */

super-nitpick, extra tab before the comment.

>>> +    if (!(flag&  (SEEK_DFLAG | SEEK_HFLAG)) ||
>>> +             optind != argc - 1)
>>> +        return command_usage(&seek_cmd);
>>> +
>>> +    offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
>>
>> need to error check that:
>>
>> xfs_io>  seek -a 8x8
>> Type    offset
>> HOLE    EOF
>>
> 
> Some version of XFS seek_data will treat it as a 0, but okay.

but I mean the error from cvtnum, if you don't give it a valid string;
nothing to do w/ seek_data ...

Thanks,
-Eric

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

  reply	other threads:[~2013-08-21 16:28 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-16 20:54 [PATCH] xfs_io: add the lseek() SEEK_DATA/SEEK_HOLE support Mark Tinguely
2013-08-20 21:26 ` Rich Johnston
2013-08-20 23:07 ` Eric Sandeen
2013-08-21 14:14   ` Mark Tinguely
2013-08-21 16:28     ` Eric Sandeen [this message]
2013-08-21 16:52       ` Mark Tinguely
2013-08-21 18:31         ` Eric Sandeen
2013-08-21 19:20           ` Mark Tinguely
2013-08-21 19:37             ` Eric Sandeen
2013-08-21 19:55               ` Eric Sandeen
2013-08-21 19:58               ` Mark Tinguely
     [not found] <20121022213759.033667921@sgi.com>
2012-10-22 21:38 ` Mark Tinguely
2012-10-22 23:29   ` Dave Chinner
2012-10-23 14:08     ` Mark Tinguely
2012-10-23 12:22   ` Christoph Hellwig

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5214EAAC.80800@sandeen.net \
    --to=sandeen@sandeen.net \
    --cc=tinguely@sgi.com \
    --cc=xfs@oss.sgi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.