Add the lseek() SEEK_DATA/SEEK_HOLE support into xfs_io.
The result from the lseek() call is printed to the output:
xfs_io> lseek -h 609k
lseek for hole starting at offset 623616 result offset 630784
Configure this feature only on Linux distributions that support
SEEK_DATA/SEEK_HOLE.
Signed-off-by: Mark Tinguely <tinguely@xxxxxxx>
---
configure.in | 1
include/builddefs.in | 1
io/Makefile | 5 ++
io/init.c | 1
io/io.h | 6 ++
io/lseek.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++
m4/package_libcdev.m4 | 15 +++++++
man/man8/xfs_io.8 | 7 +++
8 files changed, 137 insertions(+)
Index: b/configure.in
===================================================================
--- a/configure.in
+++ b/configure.in
@@ -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,101 @@
+/*
+ * 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
+ */
+
+#define _LARGEFILE64_SOURCE /* See feature_test_macros(7) */
+#include <sys/types.h>
+#include <unistd.h>
+#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 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"
+"\n"
+" Repositions and returns the offset of either the next data or hole.\n"
+" There is an implied hole at the end of file. If the specified offset is\n"
+" past end of file, or there is no data past the specied offset, the offset\n"
+" -1 is returned.\n"
+" -d -- search for data starting at the specified offset.\n"
+" -h -- search for a hole starting at the specified offset.\n"
+"\n"));
+}
+
+static int
+lseek_f(
+ int argc,
+ char **argv)
+{
+ off64_t offset, res_off;
+ size_t fsblocksize, fssectsize;
+ int flag;
+ int c;
+
+ flag = 0;
+ init_cvtnum(&fsblocksize, &fssectsize);
+
+ while ((c = getopt(argc, argv, "dh")) != EOF) {
+ switch (c) {
+ case 'd':
+ flag = SEEK_DATA;
+ break;
+ case 'h':
+ flag = SEEK_HOLE;
+ break;
+ default:
+ return command_usage(&lseek_cmd);
+ }
+ }
+ if (!flag || optind > 2)
+ return command_usage(&lseek_cmd);
+ offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
+ res_off = lseek64(file->fd, offset, flag);
+ printf("lseek for %s starting at offset %lld result offset %lld\n",
+ (flag == SEEK_DATA) ? "data" : "hole", offset, res_off);
+ 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 = 2;
+ lseek_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+ lseek_cmd.args = _("[-d | -h] off");
+ lseek_cmd.oneline = _("locate and postition to next data 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,13 @@ must be specified as another open file
.RB ( \-f )
or by path
.RB ( \-i ).
+.TP
+.BI "lseek [ \-b " offset " | \-h " offset " ]
+Repositions and prints the file pointer to the next offset containing data
+.RB ( \-d )
+or next offset containing a hole
+.RB ( \-h )
+.TP
.SH MEMORY MAPPED I/O COMMANDS
.TP
|