xfs
[Top] [All Lists]

Re: [PATCH] xfs_io: v7 add the lseek() SEEK_DATA/SEEK_HOLE support

To: Mark Tinguely <tinguely@xxxxxxx>
Subject: Re: [PATCH] xfs_io: v7 add the lseek() SEEK_DATA/SEEK_HOLE support
From: Eric Sandeen <sandeen@xxxxxxxxxxx>
Date: Thu, 22 Aug 2013 17:45:28 -0500
Cc: xfs@xxxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <20130822213148.224998379@xxxxxxx>
References: <20130822213148.224998379@xxxxxxx>
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20130801 Thunderbird/17.0.8
On 8/22/13 4:31 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> seek -h 609k
> HOLE  630784
> 
> Signed-off-by: Mark Tinguely <tinguely@xxxxxxx>
> ---
>  version 7 or 8 - Eric what number is this?

Go for 13, for luck!

I think this looks ok, I won't torture you any longer.  If there's anything
to fix up when it really gets used in earnest we can do it then.

(it crossed my mind that for the "-r" and "-a" invocations it might be good to 
print
out the offset which was sent for each SEEK_* "whence," but *shrug*)

Thanks for all the iterations,

Reviewed-by: Eric Sandeen <sandeen@xxxxxxxxxx>

>  I think I added all the old Dave and new Eric changes.
> 
>  Unconditionally compile the feature into xfs_io.
> 
>  (Too) many comments added. This routine basically is a seek and print loop.
> 
>  Removed the ending EOF, except where that was the only entry.
>    No output looked bad.
>    This print the only entry exception changed the loop/if statements.
> 
>  Changed error message to perror.
> 
>  Ran the fine-tune kernel test on the following XFS kernel version:
>   Linux 3.0 no support.
>   Linux 3.1 vfs default support.
>   Linux 3.5 XFS first support.
>   Linux 3.7 XFS fine-tuned support.
> 
>  Each version has different output - as expected. Eric you want the output?

Meh.  We can fix it up as needed.  I'm a bit shocked that we (the grand Linux
"we") didn't just settle on "whatever Solaris did is correct."

>  io/Makefile       |    3 
>  io/init.c         |    1 
>  io/io.h           |    1 
>  io/seek.c         |  197 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  man/man8/xfs_io.8 |   35 +++++++++
>  5 files changed, 236 insertions(+), 1 deletion(-)
> 
> Index: b/io/Makefile
> ===================================================================
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -10,7 +10,8 @@ LSRCFILES = xfs_bmap.sh xfs_freeze.sh xf
>  HFILES = init.h io.h
>  CFILES = init.c \
>       attr.c bmap.c file.c freeze.c fsync.c getrusage.c imap.c mmap.c \
> -     open.c parent.c pread.c prealloc.c pwrite.c shutdown.c truncate.c
> +     open.c parent.c pread.c prealloc.c pwrite.c seek.c shutdown.c \
> +     truncate.c
>  
>  LLDLIBS = $(LIBXCMD) $(LIBHANDLE)
>  LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE)
> 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
> @@ -105,6 +105,7 @@ extern void               pread_init(void);
>  extern void          prealloc_init(void);
>  extern void          pwrite_init(void);
>  extern void          quit_init(void);
> +extern void          seek_init(void);
>  extern void          shutdown_init(void);
>  extern void          truncate_init(void);
>  
> Index: b/io/seek.c
> ===================================================================
> --- /dev/null
> +++ b/io/seek.c
> @@ -0,0 +1,197 @@
> +/*
> + * 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 <xfs/xfs.h>
> +#include <xfs/command.h>
> +#include <xfs/input.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include "init.h"
> +#include "io.h"
> +
> +static cmdinfo_t seek_cmd;
> +
> +static void
> +seek_help(void)
> +{
> +     printf(_(
> +"\n"
> +" returns the next hole and/or data offset at or after the requested 
> 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. If the specified offset is past end of file, or 
> there\n"
> +" is no data past the specified offset, EOF is returned.\n"
> +" -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"));
> +}
> +
> +#ifndef HAVE_SEEK_DATA
> +#define      SEEK_DATA       3       /* seek to the next data */
> +#define      SEEK_HOLE       4       /* seek to the next hole */
> +#endif
> +
> +/* values for flag variable */
> +#define      SEEK_DFLAG      (1 << 0)
> +#define      SEEK_HFLAG      (1 << 1)
> +#define      SEEK_RFLAG      (1 << 2)
> +
> +/* indexes into the seekinfo array */
> +#define      DATA            0
> +#define      HOLE            1
> +
> +struct seekinfo {
> +     char            *name;          /* display item name */
> +     int             seektype;       /* data or hole */
> +     int             mask;           /* compared for print and looping */
> +} seekinfo[] = {
> +             {"DATA", SEEK_DATA, SEEK_DFLAG},
> +             {"HOLE", SEEK_HOLE, SEEK_HFLAG}
> +};
> +
> +/* print item type and offset. catch special cases of eof and error */
> +void
> +seek_output(
> +     char    *type,
> +     off64_t offset)
> +{
> +     if (offset == -1) {
> +             if (errno == ENXIO)
> +                     printf("%s      EOF\n", type);
> +             else
> +                     perror("ERR");
> +     } else
> +             printf("%s      %lld\n", type, (long long)offset);
> +}
> +
> +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);
> +             }
> +     }
> +     if (!(flag & (SEEK_DFLAG | SEEK_HFLAG)) || optind != argc - 1)
> +             return command_usage(&seek_cmd);
> +
> +     offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
> +     if (offset < 0)
> +             return command_usage(&seek_cmd);
> +
> +     /*
> +      * check to see if the offset is a data or hole entry and
> +      * decide if we want to display that type of entry.
> +      */
> +     if (flag & SEEK_HFLAG) {
> +             result = lseek64(file->fd, offset, SEEK_HOLE);
> +             if ((result == offset) || !(flag & SEEK_DFLAG)) {
> +                     /*
> +                      * this offset is a hole or are only displaying holes.
> +                      * if this offset is for data and we are displaying
> +                      * data, then we will fall through below to
> +                      * initialize the data search.
> +                      */
> +                     offset = result;
> +                     current = HOLE;
> +                     goto found_hole;
> +             }
> +     }
> +
> +     /* The offset is not a hole, or we are looking just for data */
> +     current = DATA;
> +     offset = lseek64(file->fd, offset, SEEK_DATA);
> +
> +found_hole:
> +     /*
> +      * At this point we know which type and the offset of the starting
> +      * item. "current" alternates between data / hole entries in
> +      * assending order - this alternation is needed even if only one
> +      * type is to be displayed.
> +      *
> +      * An error or EOF will terminate the display, otherwise "flag"
> +      * determines if there are more items to be displayed.
> +      */
> +     for (c = 0; flag; c++) {
> +             if (offset == -1) {
> +                     /* print error or eof if the only entry */
> +                     if (errno != ENXIO || c == 0 )
> +                             seek_output(seekinfo[current].name, offset);
> +                     return 0;       /* stop on error or EOF */
> +             }
> +
> +             seek_output(seekinfo[current].name, offset);
> +
> +             /*
> +              * When displaying only a single data and/or hole item, mask
> +              * off the item as it is displayed. The loop will end when all
> +              * requested items have been displayed.
> +              */
> +             if (!(flag & SEEK_RFLAG))
> +                     flag &= ~seekinfo[current].mask;
> +
> +             current ^= 1;           /* alternate between data and hole */
> +             offset = lseek64(file->fd, offset, seekinfo[current].seektype);
> +     }
> +     return 0;
> +}
> +
> +void
> +seek_init(void)
> +{
> +     seek_cmd.name = "seek";
> +     seek_cmd.cfunc = seek_f;
> +     seek_cmd.argmin = 2;
> +     seek_cmd.argmax = 5;
> +     seek_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
> +     seek_cmd.args = _("-a | -d | -h [-r] off");
> +     seek_cmd.oneline = _("locate the next data and/or hole");
> +     seek_cmd.help = seek_help;
> +
> +     add_command(&seek_cmd);
> +}
> Index: b/man/man8/xfs_io.8
> ===================================================================
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -418,6 +418,41 @@ to read (in bytes)
>  .RE
>  .PD
>  .TP
> +.TP
> +.BI "seek  \-a | \-d | \-h [ \-r ] offset"
> +On platforms that support the
> +.BR lseek (2)
> +.B SEEK_DATA
> +and
> +.B SEEK_HOLE
> +options, display the offsets of the specified segments.
> +.RS 1.0i
> +.PD 0
> +.TP 0.4i
> +.B \-a
> +Display both
> +.B data
> +and
> +.B hole
> +segments starting at the specified
> +.B offset.
> +.TP
> +.B \-d
> +Display the
> +.B data
> +segment starting at the specified
> +.B offset.
> +.TP
> +.B \-h
> +Display the
> +.B hole
> +segment starting at the specified
> +.B offset.
> +.TP
> +.B \-r
> +Recursively display all the specified segments starting at the specified
> +.B offset.
> +.TP
>  
>  .SH MEMORY MAPPED I/O COMMANDS
>  .TP
> 
> 
> _______________________________________________
> xfs mailing list
> xfs@xxxxxxxxxxx
> http://oss.sgi.com/mailman/listinfo/xfs
> 

<Prev in Thread] Current Thread [Next in Thread>