xfs
[Top] [All Lists]

review: add a splice command to xfs_io

To: dgc@xxxxxxxxxxxxxxxxx
Subject: review: add a splice command to xfs_io
From: Nathan Scott <nathans@xxxxxxx>
Date: Fri, 1 Sep 2006 16:54:50 +1000
Cc: xfs@xxxxxxxxxxx
Sender: xfs-bounce@xxxxxxxxxxx
User-agent: Mutt/1.2.5i
Yo Dave,

Here's some code which should help exercising the splice functionality
from a QA test.  Needs a /usr/include/sys/splice.h (attached also, but
glibc will get this at some point I guess).  No QA test yet though - I
will hack something up there on Monday (its beer o'clock).

cheers.

-- 
Nathan

Index: xfsprogs/io/init.c
===================================================================
--- xfsprogs.orig/io/init.c     2006-09-01 09:34:40.679409500 +1000
+++ xfsprogs/io/init.c  2006-09-01 09:36:18.193313250 +1000
@@ -74,6 +74,7 @@ init_commands(void)
        resblks_init();
        sendfile_init();
        shutdown_init();
+       splice_init();
        truncate_init();
 }
 
Index: xfsprogs/io/io.h
===================================================================
--- xfsprogs.orig/io/io.h       2006-09-01 09:34:40.595404250 +1000
+++ xfsprogs/io/io.h    2006-09-01 09:36:04.013341500 +1000
@@ -131,6 +131,12 @@ extern void                sendfile_init(void);
 #define sendfile_init()        do { } while (0)
 #endif
 
+#ifdef HAVE_SPLICE
+extern void            splice_init(void);
+#else
+#define splice_init()  do { } while (0)
+#endif
+
 #ifdef HAVE_MADVISE
 extern void            madvise_init(void);
 #else
Index: xfsprogs/io/splice.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ xfsprogs/io/splice.c        2006-09-01 16:46:41.929606500 +1000
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2006 Silicon Graphics, Inc.
+ * 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/splice.h>
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t splice_cmd;
+
+static void
+splice_help(void)
+{
+       printf(_(
+"\n"
+" splice part or all of the current open file to a second file\n"
+"\n"
+" Example:\n"
+" 'splice 100m 400m 4k out' - splices 4 kilobytes at 100 megabytes offset\n"
+"                             into the open file, to 200m offset in \"out\"\n"
+"\n"
+" Copies data between one file descriptor and another.  Because this copying\n"
+" is done within the kernel, splice does not need to transfer data to and\n"
+" from user space.\n"
+" -i <path> -- input file, instead of current file descriptor\n"
+" -m -- move pages instead of copying\n"
+" -n -- operate in non-blocking I/O mode\n"
+" Offsets in both the source and target files are optional, as is the size,\n"
+" as follows:  If one of these arguments is given it's the transfer size.  
If\n"
+" two are given they are offsets.  If three are given - offset, offset, 
size.\n"
+" Finally, if none of these arguments are given the entire input file will 
be\n"
+" spliced to the output file.\n"
+"\n"));
+}
+
+static int
+splice_buffer(
+       int             in_fd,
+       off64_t         in_offset,
+       int             out_fd,
+       off64_t         out_offset,
+       size_t          bsize,
+       int             flags,
+       long long       *total)
+{
+       long long       bytes_remaining = *total;
+       ssize_t         bytes, ibytes, obytes;
+       int             pipefds[2];
+       int             ops = 0;
+
+       *total = 0;
+       if (pipe(pipefds) < 0) {
+               perror("pipe");
+               return -1;
+       }
+       while (bytes_remaining > 0) {
+               ibytes = min(bytes_remaining, bsize);
+               bytes = splice(in_fd, &in_offset,
+                               pipefds[1], NULL, ibytes, flags);
+               if (bytes == 0)
+                       break;
+               if (bytes < 0) {
+                       perror("splice(in)");
+                       return -1;
+               }
+               ops++;
+               ibytes = obytes = bytes;
+               while (obytes > 0) {
+                       bytes = splice(pipefds[0], NULL,
+                                       out_fd, &out_offset, obytes, flags);
+                       if (bytes < 0) {
+                               perror("splice(out)");
+                               return -1;
+                       }
+                       ops++;
+                       obytes -= bytes;
+               }
+               *total += ibytes;
+               if (ibytes >= bytes_remaining)
+                       break;
+               bytes_remaining -= ibytes;
+       }
+       return ops;
+}
+
+static int
+splice_f(
+       int             argc,
+       char            **argv)
+{
+       off64_t         inoff, outoff;
+       long long       count, total;
+       size_t          blocksize, sectsize;
+       struct stat64   instat;
+       struct timeval  t1, t2;
+       char            s1[64], s2[64], ts[64];
+       char            *infile = NULL;
+       int             Cflag, qflag, flags;
+       int             c, infd = -1, outfd = -1;
+
+       Cflag = qflag = flags = 0;
+       init_cvtnum(&blocksize, &sectsize);
+       while ((c = getopt(argc, argv, "i:mnqC")) != EOF) {
+               switch (c) {
+               case 'C':
+                       Cflag = 1;
+                       break;
+               case 'q':
+                       qflag = 1;
+                       break;
+               case 'm':
+                       flags |= SPLICE_F_MOVE;
+                       break;
+               case 'n':
+                       flags |= SPLICE_F_NONBLOCK;
+                       break;
+               case 'i':
+                       infile = optarg;
+                       break;
+               default:
+                       return command_usage(&splice_cmd);
+               }
+       }
+
+       /*
+        * If no more arguments are given, splice the whole input file
+        * If one of these arguments is given it's the transfer size
+        * If two are given they are file offsets
+        * If three are given - offset, offset, size
+        */
+
+       if (optind >= argc)
+               return command_usage(&splice_cmd);
+
+       if (optind == argc - 1) {
+               inoff = outoff = 0;
+               count = -1;
+       } else if (optind == argc - 2) {
+               inoff = outoff = 0;
+               count = cvtnum(blocksize, sectsize, argv[optind]);
+               if (count < 0) {
+                       printf(_("non-numeric length argument -- %s\n"),
+                               argv[optind]);
+                       return 0;
+               }
+               optind++;
+       } else if (optind == argc - 3 || optind == argc - 4) {
+               inoff = cvtnum(blocksize, sectsize, argv[optind]);
+               if (inoff < 0) {
+                       printf(_("non-numeric offset argument -- %s\n"),
+                               argv[optind]);
+                       return 0;
+               }
+               optind++;
+               outoff = cvtnum(blocksize, sectsize, argv[optind]);
+               if (outoff < 0) {
+                       printf(_("non-numeric offset argument -- %s\n"),
+                               argv[optind]);
+                       return 0;
+               }
+               optind++;
+               if (optind == argc - 1) {
+                       count = -1;
+               } else {
+                       count = cvtnum(blocksize, sectsize, argv[optind]);
+                       if (count < 0) {
+                               printf(_("non-numeric length argument -- %s\n"),
+                                       argv[optind]);
+                               return 0;
+                       }
+                       optind++;
+               }
+       } else
+               return command_usage(&splice_cmd);
+
+       if (((outfd = openfile(argv[optind], NULL, IO_CREAT, 0644)) < 0))
+               return 0;
+
+       if (!infile)
+               infd = file->fd;
+       else if ((infd = openfile(infile, NULL, IO_READONLY, 0)) < 0)
+               goto done;
+
+       if (fstat64(infd, &instat) < 0) {
+               perror("fstat64");
+               goto done;
+       }
+       if (count == -1)
+               count = instat.st_size;
+       total = count;
+       blocksize = instat.st_blksize;
+
+       gettimeofday(&t1, NULL);
+       c = splice_buffer(infd, inoff, outfd, outoff, blocksize, flags, &total);
+       if (c < 0)
+               goto done;
+       if (qflag)
+               goto done;
+       gettimeofday(&t2, NULL);
+       t2 = tsub(t2, t1);
+
+       /* Finally, report back -- -C gives a parsable format */
+       timestr(&t2, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+       if (!Cflag) {
+               cvtstr((double)total, s1, sizeof(s1));
+               cvtstr(tdiv((double)total, t2), s2, sizeof(s2));
+               printf(_("spliced %lld/%lld bytes from offset %lld to offset 
%lld\n"),
+                       total, count, (long long)inoff, (long long)outoff);
+               printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
+                       s1, c, ts, s2, tdiv((double)c, t2));
+       } else {/* bytes,ops,time,bytes/sec,ops/sec */
+               printf("%lld,%d,%s,%.3f,%.3f\n",
+                       total, c, ts,
+                       tdiv((double)total, t2), tdiv((double)c, t2));
+       }
+done:
+       if (infile)
+               close(infd);
+       close(outfd);
+       return 0;
+}
+
+void
+splice_init(void)
+{
+       splice_cmd.name = _("splice");
+       splice_cmd.cfunc = splice_f;
+       splice_cmd.argmin = 1;
+       splice_cmd.argmax = -1;
+       splice_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
+       splice_cmd.args =
+               _("[-i infile] [inoff [outoff [len]]] outfile");
+       splice_cmd.oneline =
+               _("Splice copy data between two file descriptors via a pipe");
+       splice_cmd.help = splice_help;
+
+       add_command(&splice_cmd);
+}
Index: xfsprogs/io/Makefile
===================================================================
--- xfsprogs.orig/io/Makefile   2006-09-01 09:32:31.319325000 +1000
+++ xfsprogs/io/Makefile        2006-09-01 12:03:24.598944250 +1000
@@ -44,6 +44,13 @@ else
 LSRCFILES += sendfile.c
 endif
 
+ifeq ($(HAVE_SPLICE),yes)
+CFILES += splice.c
+LCFLAGS += -DHAVE_SPLICE
+else
+LSRCFILES += splice.c
+endif
+
 ifeq ($(PKG_PLATFORM),irix)
 LSRCFILES += inject.c resblks.c
 else
Index: xfsprogs/aclocal.m4
===================================================================
--- xfsprogs.orig/aclocal.m4    2006-09-01 12:04:54.696575000 +1000
+++ xfsprogs/aclocal.m4 2006-09-01 12:06:48.043658750 +1000
@@ -157,9 +157,9 @@ AC_DEFUN([AC_PACKAGE_GLOBALS],
     AC_SUBST(pkg_platform)
   ])
 
-# 
+#
 # Check if we have a working fadvise system call
-# 
+#
 AC_DEFUN([AC_HAVE_FADVISE],
   [ AC_MSG_CHECKING([for fadvise ])
     AC_TRY_COMPILE([
@@ -174,9 +174,9 @@ AC_DEFUN([AC_HAVE_FADVISE],
     AC_SUBST(have_fadvise)
   ])
 
-# 
+#
 # Check if we have a working madvise system call
-# 
+#
 AC_DEFUN([AC_HAVE_MADVISE],
   [ AC_MSG_CHECKING([for madvise ])
     AC_TRY_COMPILE([
@@ -191,9 +191,9 @@ AC_DEFUN([AC_HAVE_MADVISE],
     AC_SUBST(have_madvise)
   ])
 
-# 
+#
 # Check if we have a working mincore system call
-# 
+#
 AC_DEFUN([AC_HAVE_MINCORE],
   [ AC_MSG_CHECKING([for mincore ])
     AC_TRY_COMPILE([
@@ -208,9 +208,9 @@ AC_DEFUN([AC_HAVE_MINCORE],
     AC_SUBST(have_mincore)
   ])
 
-# 
+#
 # Check if we have a working sendfile system call
-# 
+#
 AC_DEFUN([AC_HAVE_SENDFILE],
   [ AC_MSG_CHECKING([for sendfile ])
     AC_TRY_COMPILE([
@@ -226,6 +226,23 @@ AC_DEFUN([AC_HAVE_SENDFILE],
   ])
 
 #
+# Check if we have a working splice system call
+#
+AC_DEFUN([AC_HAVE_SPLICE],
+  [ AC_MSG_CHECKING([for splice ])
+    AC_TRY_COMPILE([
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#include <sys/splice.h>
+    ], [
+         splice(0, 0, 0, 0, 0, 0);
+    ], have_splice=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_splice)
+  ])
+
+#
 # Check if we have a getmntent libc call (IRIX, Linux)
 #
 AC_DEFUN([AC_HAVE_GETMNTENT],
Index: xfsprogs/configure.in
===================================================================
--- xfsprogs.orig/configure.in  2006-09-01 12:04:54.612569750 +1000
+++ xfsprogs/configure.in       2006-09-01 12:06:39.123101250 +1000
@@ -52,6 +52,7 @@ AC_HAVE_FADVISE
 AC_HAVE_MADVISE
 AC_HAVE_MINCORE
 AC_HAVE_SENDFILE
+AC_HAVE_SPLICE
 AC_HAVE_GETMNTENT
 AC_HAVE_GETMNTINFO
 
Index: xfsprogs/m4/package_libcdev.m4
===================================================================
--- xfsprogs.orig/m4/package_libcdev.m4 2006-09-01 12:05:03.605131750 +1000
+++ xfsprogs/m4/package_libcdev.m4      2006-09-01 12:06:29.186480250 +1000
@@ -1,6 +1,6 @@
-# 
+#
 # Check if we have a working fadvise system call
-# 
+#
 AC_DEFUN([AC_HAVE_FADVISE],
   [ AC_MSG_CHECKING([for fadvise ])
     AC_TRY_COMPILE([
@@ -15,9 +15,9 @@ AC_DEFUN([AC_HAVE_FADVISE],
     AC_SUBST(have_fadvise)
   ])
 
-# 
+#
 # Check if we have a working madvise system call
-# 
+#
 AC_DEFUN([AC_HAVE_MADVISE],
   [ AC_MSG_CHECKING([for madvise ])
     AC_TRY_COMPILE([
@@ -32,9 +32,9 @@ AC_DEFUN([AC_HAVE_MADVISE],
     AC_SUBST(have_madvise)
   ])
 
-# 
+#
 # Check if we have a working mincore system call
-# 
+#
 AC_DEFUN([AC_HAVE_MINCORE],
   [ AC_MSG_CHECKING([for mincore ])
     AC_TRY_COMPILE([
@@ -49,9 +49,9 @@ AC_DEFUN([AC_HAVE_MINCORE],
     AC_SUBST(have_mincore)
   ])
 
-# 
+#
 # Check if we have a working sendfile system call
-# 
+#
 AC_DEFUN([AC_HAVE_SENDFILE],
   [ AC_MSG_CHECKING([for sendfile ])
     AC_TRY_COMPILE([
@@ -67,6 +67,23 @@ AC_DEFUN([AC_HAVE_SENDFILE],
   ])
 
 #
+# Check if we have a working splice system call
+#
+AC_DEFUN([AC_HAVE_SPLICE],
+  [ AC_MSG_CHECKING([for splice ])
+    AC_TRY_COMPILE([
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#include <sys/splice.h>
+    ], [
+         splice(0, 0, 0, 0, 0, 0);
+    ], have_splice=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_splice)
+  ])
+
+#
 # Check if we have a getmntent libc call (IRIX, Linux)
 #
 AC_DEFUN([AC_HAVE_GETMNTENT],
Index: xfsprogs/include/builddefs.in
===================================================================
--- xfsprogs.orig/include/builddefs.in  2006-09-01 14:58:42.038205250 +1000
+++ xfsprogs/include/builddefs.in       2006-09-01 14:59:00.475357500 +1000
@@ -90,6 +90,7 @@ HAVE_FADVISE = @have_fadvise@
 HAVE_MADVISE = @have_madvise@
 HAVE_MINCORE = @have_mincore@
 HAVE_SENDFILE = @have_sendfile@
+HAVE_SPLICE = @have_splice@
 HAVE_GETMNTENT = @have_getmntent@
 HAVE_GETMNTINFO = @have_getmntinfo@
 

Attachment: splice.h
Description: Text document

<Prev in Thread] Current Thread [Next in Thread>
  • review: add a splice command to xfs_io, Nathan Scott <=