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 v1 -> v2 Add "-a" and "-r" options. Simplify the output. v2 -> v3 Refactor for configure.in -> configure.ac change. SEEK_DATA with -1 offset behaves badly on older Linux. Display error message as "ERR <errno>". Signed-off-by: Mark Tinguely <tinguely@xxxxxxx> --- configure.ac | 1 include/builddefs.in | 1 io/Makefile | 5 + io/init.c | 1 io/io.h | 6 + io/lseek.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++ m4/package_libcdev.m4 | 15 ++++ man/man8/xfs_io.8 | 35 ++++++++++ 8 files changed, 233 insertions(+) Index: b/configure.ac =================================================================== --- a/configure.ac +++ b/configure.ac @@ -109,6 +109,7 @@ AC_HAVE_GETMNTINFO AC_HAVE_FALLOCATE AC_HAVE_FIEMAP AC_HAVE_PREADV +AC_HAVE_LSEEK_DATA AC_HAVE_SYNC_FILE_RANGE AC_HAVE_BLKID_TOPO($enable_blkid) 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_LSEEK_DATA = @have_lseek_data@ HAVE_SYNC_FILE_RANGE = @have_sync_file_range@ GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall Index: b/io/Makefile =================================================================== --- a/io/Makefile +++ b/io/Makefile @@ -80,6 +80,11 @@ ifeq ($(HAVE_PREADV),yes) LCFLAGS += -DHAVE_PREADV -DHAVE_PWRITEV endif +ifeq ($(HAVE_LSEEK_DATA),yes) +LCFLAGS += -DHAVE_LSEEK_DATA +CFILES += lseek.c +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(); + lseek_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_LSEEK_DATA +extern void lseek_init(void); +#else +#define lseek_init() do { } while (0) +#endif + #ifdef HAVE_FADVISE extern void fadvise_init(void); #else Index: b/io/lseek.c =================================================================== --- /dev/null +++ b/io/lseek.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2012 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 <linux/fs.h> + +#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" + +static cmdinfo_t lseek_cmd; + +static void +lseek_help(void) +{ + printf(_( +"\n" +" returns the next hole and/or data offset at or after the specified offset\n" +"\n" +" Example:\n" +" 'lseek -d 512' - offset of data at or following offset 512\n" +" 'lseek -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 specied 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")); +} + +#define LSEEK_DFLAG 1 << 0 +#define LSEEK_HFLAG 1 << 1 +#define LSEEK_RFLAG 1 << 2 + +static int +lseek_f( + int argc, + char **argv) +{ + off64_t offset, roff; + size_t fsblocksize, fssectsize; + int cseg; + int flag; + int i, c; + + flag = 0; + init_cvtnum(&fsblocksize, &fssectsize); + + while ((c = getopt(argc, argv, "adhr")) != EOF) { + switch (c) { + case 'a': + flag |= LSEEK_HFLAG; + /* fall through to pick up the DFLAG */ + case 'd': + flag |= LSEEK_DFLAG; + break; + case 'h': + flag |= LSEEK_HFLAG; + break; + case 'r': + flag |= LSEEK_RFLAG; + break; + default: + return command_usage(&lseek_cmd); + } + } + /* must have hole or data specified and an offset */ + if (!(flag & (LSEEK_DFLAG | LSEEK_HFLAG)) || + optind != argc - 1) + return command_usage(&lseek_cmd); + + offset = cvtnum(fsblocksize, fssectsize, argv[optind]); + + /* recursively display all information, decide where to start. */ + roff = lseek64(file->fd, offset, SEEK_DATA); + if (roff == offset) + cseg = LSEEK_DFLAG; + else + cseg = LSEEK_HFLAG; + + printf("Type offset\n"); + + /* loop to handle the data / hole entries in assending order. + * Only display the EOF when the initial offset was greater + * the end of file. + */ + for (i = 0; flag & LSEEK_RFLAG || i < 2; i++) { + if (cseg == LSEEK_DFLAG) { + if (flag & LSEEK_DFLAG) { + roff = lseek64(file->fd, offset, SEEK_DATA); + if (roff == -1) { + if (i < 2) { + if (errno == ENXIO) + printf("data EOF\n"); + else + printf("data ERR %d\n", + errno); + } + break; + } else + printf("data %lld\n", roff); + } + /* set the offset and type for the next iteration */ + cseg = LSEEK_HFLAG; + roff = lseek64(file->fd, offset, SEEK_HOLE); + if (roff != -1) + offset = roff; + continue; + } + + /* cseg == LSEEK_HFLAG */ + if (flag & LSEEK_HFLAG) { + roff = lseek64(file->fd, offset, SEEK_HOLE); + if (roff == -1) { + if (i < 2) { + if (errno == ENXIO) + printf("hole EOF\n"); + else + printf("hole ERR %d\n", errno); + } + break; + } else + printf("hole %lld\n", roff); + } + /* set the offset and type for the next iteration */ + cseg = LSEEK_DFLAG; + roff = lseek64(file->fd, offset, SEEK_DATA); + if (roff != -1) + offset = roff; + } + return 0; +} + +void +lseek_init(void) +{ + lseek_cmd.name = "lseek"; + lseek_cmd.altname = "seek"; + lseek_cmd.cfunc = lseek_f; + lseek_cmd.argmin = 2; + lseek_cmd.argmax = 5; + lseek_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; + lseek_cmd.args = _("-a | -d | -h [-r] off"); + lseek_cmd.oneline = _("locate the next data and/or hole"); + lseek_cmd.help = lseek_help; + + add_command(&lseek_cmd); +} Index: b/m4/package_libcdev.m4 =================================================================== --- a/m4/package_libcdev.m4 +++ b/m4/package_libcdev.m4 @@ -153,6 +153,21 @@ AC_DEFUN([AC_HAVE_PREADV], AC_SUBST(have_preadv) ]) +# +# Check if we have a working fadvise system call +# +AC_DEFUN([AC_HAVE_LSEEK_DATA], + [ AC_MSG_CHECKING([for lseek SEEK_DATA]) + AC_TRY_COMPILE([ +#include <linux/fs.h> + ], [ + lseek(0, 0, SEEK_DATA); + ], have_lseek_data=yes + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + AC_SUBST(have_lseek_data) + ]) + # # Check if we have a sync_file_range libc call (Linux) # Index: b/man/man8/xfs_io.8 =================================================================== --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -377,6 +377,41 @@ must be specified as another open file .RB ( \-f ) or by path .RB ( \-i ). +.TP +.BI "lseek \-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