* [PATCH] xfs_io: support splice data between two files
@ 2018-12-08 15:29 Zorro Lang
0 siblings, 0 replies; 3+ messages in thread
From: Zorro Lang @ 2018-12-08 15:29 UTC (permalink / raw)
To: linux-xfs
Add splice command into xfs_io, by calling splice(2) system call.
Signed-off-by: Zorro Lang <zlang@redhat.com>
---
Hi,
As subject, I'd like to add splice into xfs_io, then will try to add it
splice testing into fsstress. Last week we find a XFS regression by
doing splice test on overlayfs over XFS. So I think, although copy_file_range
maybe do splice if there's not clone_range can be used, but we'd better
have a separate splice command/test.
Thanks,
Zorro
io/Makefile | 2 +-
io/init.c | 1 +
io/io.h | 1 +
io/splice.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++
man/man8/xfs_io.8 | 26 +++++++
5 files changed, 223 insertions(+), 1 deletion(-)
create mode 100644 io/splice.c
diff --git a/io/Makefile b/io/Makefile
index 484e2b5a..06d21dd5 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -12,7 +12,7 @@ CFILES = init.c \
attr.c bmap.c crc32cselftest.c cowextsize.c encrypt.c file.c freeze.c \
fsync.c getrusage.c imap.c inject.c label.c link.c mmap.c open.c \
parent.c pread.c prealloc.c pwrite.c reflink.c resblks.c scrub.c \
- seek.c shutdown.c stat.c swapext.c sync.c truncate.c utimes.c
+ seek.c shutdown.c splice.c stat.c swapext.c sync.c truncate.c utimes.c
LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG)
diff --git a/io/init.c b/io/init.c
index 83f08f2d..fc191aa7 100644
--- a/io/init.c
+++ b/io/init.c
@@ -79,6 +79,7 @@ init_commands(void)
seek_init();
sendfile_init();
shutdown_init();
+ splice_init();
stat_init();
swapext_init();
sync_init();
diff --git a/io/io.h b/io/io.h
index 6469179e..9a0b71f0 100644
--- a/io/io.h
+++ b/io/io.h
@@ -110,6 +110,7 @@ extern void quit_init(void);
extern void resblks_init(void);
extern void seek_init(void);
extern void shutdown_init(void);
+extern void splice_init(void);
extern void stat_init(void);
extern void swapext_init(void);
extern void sync_init(void);
diff --git a/io/splice.c b/io/splice.c
new file mode 100644
index 00000000..cd76b710
--- /dev/null
+++ b/io/splice.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+
+#include "command.h"
+#include "input.h"
+#include <fcntl.h>
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t splice_cmd;
+
+static void
+splice_help(void)
+{
+ printf(_(
+"\n"
+" Splice a range of bytes from the given offset between files through pipe\n"
+"\n"
+" Example:\n"
+" 'splice filename 0 4096 32768' - splice 32768 bytes from filename at offset\n"
+" 0 into the open file at position 4096\n"
+" 'splice filename' - splice all bytes from filename into the open file at\n"
+" ' position 0\n"
+"\n"
+" Copies data between one file and another. Because this copying is done\n"
+" within the kernel, sendfile does not need to transfer data to and from user\n"
+" space.\n"
+" -m -- SPLICE_F_MOVE flag, attempt to move pages instead of copying.\n"
+" Offset and length in the source/destination file can be optionally specified.\n"
+"\n"));
+}
+
+static uint64_t
+splice_file(
+ int fd,
+ off64_t soffset,
+ off64_t doffset,
+ size_t length,
+ unsigned int flag,
+ int *ops)
+{
+ off64_t soff = soffset;
+ off64_t doff = doffset;
+ ssize_t rc = 0;
+ size_t len = length;
+ uint64_t total = 0;
+ int filedes[2];
+
+ if (pipe(filedes) < 0) {
+ perror("pipe");
+ return -1;
+ }
+
+ *ops = 0;
+ while (len > 0 || !*ops) {
+ /* move to pipe buffer */
+ rc = splice(fd, &soff, filedes[1], NULL, len, flag);
+ if (rc < 0) {
+ perror("splice to pipe");
+ goto out_close;
+ }
+ /* move from pipe buffer to dst file */
+ rc = splice(filedes[0], NULL, file->fd, &doff, len, flag);
+ if (rc < 0) {
+ perror("splice from pipe");
+ goto out_close;
+ }
+ (*ops)++;
+ len -= rc;
+ total += rc;
+ }
+
+out_close:
+ close(filedes[0]);
+ close(filedes[1]);
+ return total;
+}
+
+static int
+splice_f(
+ int argc,
+ char **argv)
+{
+ off64_t soffset, doffset;
+ long long count, total;
+ size_t blocksize, sectsize;
+ struct timeval t1, t2;
+ char *infile = NULL;
+ int Cflag, qflag;
+ int splice_flag = 0;
+ int c, fd = -1;
+ int ops = 0;
+
+ Cflag = qflag = 0;
+ soffset = doffset=0;
+ init_cvtnum(&blocksize, §size);
+
+ while ((c = getopt(argc, argv, "Cqm")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'm':
+ splice_flag |= SPLICE_F_MOVE;
+ break;
+ default:
+ return command_usage(&splice_cmd);
+ }
+ }
+
+ if (optind != argc - 4 && optind != argc - 1)
+ return command_usage(&splice_cmd);
+
+ infile = argv[optind];
+ if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
+ return 0;
+ optind++;
+
+ if (optind == argc - 3) {
+ soffset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (soffset < 0) {
+ printf(_("non-numeric src offset argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ doffset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (doffset < 0) {
+ printf(_("non-numeric dest offset argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ count = cvtnum(blocksize, sectsize, argv[optind]);
+ if (count < 0) {
+ printf(_("non-positive length argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ /*
+ * splice whole file to another, if doesn't specify src and dst
+ * offset and length
+ */
+ struct stat stat;
+
+ if (fstat(fd, &stat) < 0) {
+ perror("fstat");
+ goto done;
+ }
+ count = stat.st_size;
+ soffset = 0;
+ doffset = 0;
+ }
+
+ gettimeofday(&t1, NULL);
+ total = splice_file(fd, soffset, doffset, count, splice_flag, &ops);
+ if (ops == 0 || qflag)
+ goto done;
+ gettimeofday(&t2, NULL);
+ t2 = tsub(t2, t1);
+
+ report_io_times("spliced", &t2, (long long)doffset, count, total, ops, \
+ Cflag);
+
+done:
+ if (infile)
+ close(fd);
+ return 0;
+}
+
+void
+splice_init(void)
+{
+ splice_cmd.name = "splice";
+ splice_cmd.altname = "spl";
+ splice_cmd.cfunc = splice_f;
+ splice_cmd.argmin = 1;
+ splice_cmd.argmax = -1;
+ splice_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;;
+ splice_cmd.args =
+ _("[-m] infile [src_off dst_off len]");
+ splice_cmd.oneline =
+ _("Splice an entire file, or a number of bytes at a specified offset");
+ splice_cmd.help = splice_help;
+
+ add_command(&splice_cmd);
+}
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index f1099c32..8fb2c0b9 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -782,6 +782,32 @@ bytes of data.
.RE
.PD
.TP
+.BI "splice [ \-C ] [ \-q ] [\-m] infile [src_offset dst_offset length]"
+On filesystems that support the
+.BR splice (2)
+system call, splice data from the
+.I infile
+into the open file. If
+.IR src_offset ,
+.IR dst_offset ,
+and
+.I length
+are omitted the contents of infile will be copied to the beginning of the
+open file, overwriting any data already there.
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.B \-C
+Print timing statistics in a condensed format.
+.TP
+.B \-q
+Do not print timing statistics at all.
+.TP
+.B \-m
+Enable SPLICE_F_MOVE flag, attempt to move pages instead of copying.
+.RE
+.PD
+.TP
.BI utimes " atime_sec atime_nsec mtime_sec mtime_nsec"
The utimes command changes the atime and mtime of the current file.
sec uses UNIX timestamp notation and is the seconds elapsed since
--
2.17.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH] xfs_io: support splice data between two files
@ 2019-04-06 2:35 Zorro Lang
2019-05-13 21:13 ` Eric Sandeen
0 siblings, 1 reply; 3+ messages in thread
From: Zorro Lang @ 2019-04-06 2:35 UTC (permalink / raw)
To: linux-xfs
Add splice command into xfs_io, by calling splice(2) system call.
Signed-off-by: Zorro Lang <zlang@redhat.com>
---
Hi,
I've add splice() test into fsstress.c, due to we find a XFS regression
by doing some splice test on overlayfs over XFS. Although copy_file_range
maybe through splice() code path, but it depends. So a specified splice
operation is helpful to use splice clearly.
Thanks,
Zorro
io/Makefile | 2 +-
io/init.c | 1 +
io/io.h | 1 +
io/splice.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++
man/man8/xfs_io.8 | 26 +++++++
5 files changed, 223 insertions(+), 1 deletion(-)
create mode 100644 io/splice.c
diff --git a/io/Makefile b/io/Makefile
index 484e2b5a..06d21dd5 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -12,7 +12,7 @@ CFILES = init.c \
attr.c bmap.c crc32cselftest.c cowextsize.c encrypt.c file.c freeze.c \
fsync.c getrusage.c imap.c inject.c label.c link.c mmap.c open.c \
parent.c pread.c prealloc.c pwrite.c reflink.c resblks.c scrub.c \
- seek.c shutdown.c stat.c swapext.c sync.c truncate.c utimes.c
+ seek.c shutdown.c splice.c stat.c swapext.c sync.c truncate.c utimes.c
LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG)
diff --git a/io/init.c b/io/init.c
index 83f08f2d..fc191aa7 100644
--- a/io/init.c
+++ b/io/init.c
@@ -79,6 +79,7 @@ init_commands(void)
seek_init();
sendfile_init();
shutdown_init();
+ splice_init();
stat_init();
swapext_init();
sync_init();
diff --git a/io/io.h b/io/io.h
index 6469179e..9a0b71f0 100644
--- a/io/io.h
+++ b/io/io.h
@@ -110,6 +110,7 @@ extern void quit_init(void);
extern void resblks_init(void);
extern void seek_init(void);
extern void shutdown_init(void);
+extern void splice_init(void);
extern void stat_init(void);
extern void swapext_init(void);
extern void sync_init(void);
diff --git a/io/splice.c b/io/splice.c
new file mode 100644
index 00000000..7e2f1aa2
--- /dev/null
+++ b/io/splice.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+
+#include "command.h"
+#include "input.h"
+#include <fcntl.h>
+#include "init.h"
+#include "io.h"
+
+static cmdinfo_t splice_cmd;
+
+static void
+splice_help(void)
+{
+ printf(_(
+"\n"
+" Splice a range of bytes from the given offset between files through pipe\n"
+"\n"
+" Example:\n"
+" 'splice filename 0 4096 32768' - splice 32768 bytes from filename at offset\n"
+" 0 into the open file at position 4096\n"
+" 'splice filename' - splice all bytes from filename into the open file at\n"
+" ' position 0\n"
+"\n"
+" Copies data between one file and another. Because this copying is done\n"
+" within the kernel, sendfile does not need to transfer data to and from user\n"
+" space.\n"
+" -m -- SPLICE_F_MOVE flag, attempt to move pages instead of copying.\n"
+" Offset and length in the source/destination file can be optionally specified.\n"
+"\n"));
+}
+
+static uint64_t
+splice_file(
+ int fd,
+ off64_t soffset,
+ off64_t doffset,
+ size_t length,
+ unsigned int flag,
+ int *ops)
+{
+ off64_t soff = soffset;
+ off64_t doff = doffset;
+ ssize_t rc = 0;
+ size_t len = length;
+ uint64_t total = 0;
+ int filedes[2];
+
+ if (pipe(filedes) < 0) {
+ perror("pipe");
+ return -1;
+ }
+
+ *ops = 0;
+ while (len > 0 || !*ops) {
+ /* move to pipe buffer */
+ rc = splice(fd, &soff, filedes[1], NULL, len, flag);
+ if (rc < 0) {
+ perror("splice to pipe");
+ goto out_close;
+ }
+ /* move from pipe buffer to dst file */
+ rc = splice(filedes[0], NULL, file->fd, &doff, len, flag);
+ if (rc < 0) {
+ perror("splice from pipe");
+ goto out_close;
+ }
+ (*ops)++;
+ len -= rc;
+ total += rc;
+ }
+
+out_close:
+ close(filedes[0]);
+ close(filedes[1]);
+ return total;
+}
+
+static int
+splice_f(
+ int argc,
+ char **argv)
+{
+ off64_t soffset, doffset;
+ long long count, total;
+ size_t blocksize, sectsize;
+ struct timeval t1, t2;
+ char *infile = NULL;
+ int Cflag, qflag;
+ int splice_flag = 0;
+ int c, fd = -1;
+ int ops = 0;
+
+ Cflag = qflag = 0;
+ soffset = doffset=0;
+ init_cvtnum(&blocksize, §size);
+
+ while ((c = getopt(argc, argv, "Cqm")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'm':
+ splice_flag |= SPLICE_F_MOVE;
+ break;
+ default:
+ return command_usage(&splice_cmd);
+ }
+ }
+
+ if (optind != argc - 4 && optind != argc - 1)
+ return command_usage(&splice_cmd);
+
+ infile = argv[optind];
+ if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
+ return 0;
+ optind++;
+
+ if (optind == argc - 3) {
+ soffset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (soffset < 0) {
+ printf(_("non-numeric src offset argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ doffset = cvtnum(blocksize, sectsize, argv[optind]);
+ if (doffset < 0) {
+ printf(_("non-numeric dest offset argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ optind++;
+ count = cvtnum(blocksize, sectsize, argv[optind]);
+ if (count < 0) {
+ printf(_("non-positive length argument -- %s\n"), \
+ argv[optind]);
+ return 0;
+ }
+ } else {
+ /*
+ * splice whole file to another, if doesn't specify src and dst
+ * offset and length
+ */
+ struct stat stat;
+
+ if (fstat(fd, &stat) < 0) {
+ perror("fstat");
+ goto done;
+ }
+ count = stat.st_size;
+ soffset = 0;
+ doffset = 0;
+ }
+
+ gettimeofday(&t1, NULL);
+ total = splice_file(fd, soffset, doffset, count, splice_flag, &ops);
+ if (ops == 0 || qflag)
+ goto done;
+ gettimeofday(&t2, NULL);
+ t2 = tsub(t2, t1);
+
+ report_io_times("spliced", &t2, (long long)doffset, count, total, ops, \
+ Cflag);
+
+done:
+ if (infile)
+ close(fd);
+ return 0;
+}
+
+void
+splice_init(void)
+{
+ splice_cmd.name = "splice";
+ splice_cmd.altname = "spl";
+ splice_cmd.cfunc = splice_f;
+ splice_cmd.argmin = 1;
+ splice_cmd.argmax = -1;
+ splice_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;;
+ splice_cmd.args =
+ _("[-m] infile [src_off dst_off len]");
+ splice_cmd.oneline =
+ _("Splice an entire file, or a number of bytes at a specified offset");
+ splice_cmd.help = splice_help;
+
+ add_command(&splice_cmd);
+}
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 980dcfd3..066a72e7 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -830,6 +830,32 @@ verbose output will be printed.
.RE
.PD
.TP
+.BI "splice [ \-C ] [ \-q ] [\-m] infile [src_offset dst_offset length]"
+On filesystems that support the
+.BR splice (2)
+system call, splice data from the
+.I infile
+into the open file. If
+.IR src_offset ,
+.IR dst_offset ,
+and
+.I length
+are omitted the contents of infile will be copied to the beginning of the
+open file, overwriting any data already there.
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.B \-C
+Print timing statistics in a condensed format.
+.TP
+.B \-q
+Do not print timing statistics at all.
+.TP
+.B \-m
+Enable SPLICE_F_MOVE flag, attempt to move pages instead of copying.
+.RE
+.PD
+.TP
.BI utimes " atime_sec atime_nsec mtime_sec mtime_nsec"
The utimes command changes the atime and mtime of the current file.
sec uses UNIX timestamp notation and is the seconds elapsed since
--
2.17.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] xfs_io: support splice data between two files
2019-04-06 2:35 Zorro Lang
@ 2019-05-13 21:13 ` Eric Sandeen
0 siblings, 0 replies; 3+ messages in thread
From: Eric Sandeen @ 2019-05-13 21:13 UTC (permalink / raw)
To: Zorro Lang, linux-xfs
On 4/5/19 9:35 PM, Zorro Lang wrote:
> Add splice command into xfs_io, by calling splice(2) system call.
>
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> ---
>
> Hi,
>
> I've add splice() test into fsstress.c, due to we find a XFS regression
> by doing some splice test on overlayfs over XFS. Although copy_file_range
> maybe through splice() code path, but it depends. So a specified splice
> operation is helpful to use splice clearly.
Hi Zorro, I'm sorry this has gone so long w/o review. Questions below.
> Thanks,
> Zorro
>
> io/Makefile | 2 +-
> io/init.c | 1 +
> io/io.h | 1 +
> io/splice.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++
> man/man8/xfs_io.8 | 26 +++++++
> 5 files changed, 223 insertions(+), 1 deletion(-)
> create mode 100644 io/splice.c
>
> diff --git a/io/Makefile b/io/Makefile
> index 484e2b5a..06d21dd5 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -12,7 +12,7 @@ CFILES = init.c \
> attr.c bmap.c crc32cselftest.c cowextsize.c encrypt.c file.c freeze.c \
> fsync.c getrusage.c imap.c inject.c label.c link.c mmap.c open.c \
> parent.c pread.c prealloc.c pwrite.c reflink.c resblks.c scrub.c \
> - seek.c shutdown.c stat.c swapext.c sync.c truncate.c utimes.c
> + seek.c shutdown.c splice.c stat.c swapext.c sync.c truncate.c utimes.c
>
> LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
> LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG)
> diff --git a/io/init.c b/io/init.c
> index 83f08f2d..fc191aa7 100644
> --- a/io/init.c
> +++ b/io/init.c
> @@ -79,6 +79,7 @@ init_commands(void)
> seek_init();
> sendfile_init();
> shutdown_init();
> + splice_init();
> stat_init();
> swapext_init();
> sync_init();
> diff --git a/io/io.h b/io/io.h
> index 6469179e..9a0b71f0 100644
> --- a/io/io.h
> +++ b/io/io.h
> @@ -110,6 +110,7 @@ extern void quit_init(void);
> extern void resblks_init(void);
> extern void seek_init(void);
> extern void shutdown_init(void);
> +extern void splice_init(void);
> extern void stat_init(void);
> extern void swapext_init(void);
> extern void sync_init(void);
> diff --git a/io/splice.c b/io/splice.c
> new file mode 100644
> index 00000000..7e2f1aa2
> --- /dev/null
> +++ b/io/splice.c
> @@ -0,0 +1,194 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2019 Red Hat, Inc.
> + * All Rights Reserved.
> + */
> +
> +#include "command.h"
> +#include "input.h"
> +#include <fcntl.h>
> +#include "init.h"
> +#include "io.h"
> +
> +static cmdinfo_t splice_cmd;
> +
> +static void
> +splice_help(void)
> +{
> + printf(_(
> +"\n"
> +" Splice a range of bytes from the given offset between files through pipe\n"
> +"\n"
> +" Example:\n"
> +" 'splice filename 0 4096 32768' - splice 32768 bytes from filename at offset\n"
> +" 0 into the open file at position 4096\n"
> +" 'splice filename' - splice all bytes from filename into the open file at\n"
> +" ' position 0\n"
> +"\n"
> +" Copies data between one file and another. Because this copying is done\n"
> +" within the kernel, sendfile does not need to transfer data to and from user\n"
> +" space.\n"
> +" -m -- SPLICE_F_MOVE flag, attempt to move pages instead of copying.\n"
> +" Offset and length in the source/destination file can be optionally specified.\n"
> +"\n"));
> +}
> +
> +static uint64_t
> +splice_file(
> + int fd,
> + off64_t soffset,
> + off64_t doffset,
> + size_t length,
> + unsigned int flag,
> + int *ops)
> +{
> + off64_t soff = soffset;
> + off64_t doff = doffset;
> + ssize_t rc = 0;
> + size_t len = length;
> + uint64_t total = 0;
> + int filedes[2];
> +
> + if (pipe(filedes) < 0) {
> + perror("pipe");
> + return -1;
> + }
> +
> + *ops = 0;
> + while (len > 0 || !*ops) {
> + /* move to pipe buffer */
> + rc = splice(fd, &soff, filedes[1], NULL, len, flag);
> + if (rc < 0) {
> + perror("splice to pipe");
> + goto out_close;
> + }
> + /* move from pipe buffer to dst file */
> + rc = splice(filedes[0], NULL, file->fd, &doff, len, flag);
> + if (rc < 0) {
> + perror("splice from pipe");
> + goto out_close;
> + }
> + (*ops)++;
> + len -= rc;
> + total += rc;
> + }
> +
> +out_close:
> + close(filedes[0]);
> + close(filedes[1]);
> + return total;
> +}
> +
> +static int
> +splice_f(
> + int argc,
> + char **argv)
> +{
> + off64_t soffset, doffset;
> + long long count, total;
> + size_t blocksize, sectsize;
> + struct timeval t1, t2;
> + char *infile = NULL;
> + int Cflag, qflag;
> + int splice_flag = 0;
> + int c, fd = -1;
> + int ops = 0;
> +
> + Cflag = qflag = 0;
> + soffset = doffset=0;
> + init_cvtnum(&blocksize, §size);
> +
> + while ((c = getopt(argc, argv, "Cqm")) != EOF) {
> + switch (c) {
> + case 'C':
> + Cflag = 1;
> + break;
> + case 'q':
> + qflag = 1;
> + break;
-C and -q are not documented in the usage() output, but maybe that's
ok. Looks like other callers of report_io_times skip that as well, so
maybe it's expected.
> + case 'm':
> + splice_flag |= SPLICE_F_MOVE;
> + break;
> + default:
> + return command_usage(&splice_cmd);
> + }
> + }
> +
> + if (optind != argc - 4 && optind != argc - 1)
> + return command_usage(&splice_cmd);
> +
> + infile = argv[optind];
> + if ((fd = openfile(infile, NULL, IO_READONLY, 0, NULL)) < 0)
> + return 0;
> + optind++;
> +
> + if (optind == argc - 3) {
> + soffset = cvtnum(blocksize, sectsize, argv[optind]);
> + if (soffset < 0) {
> + printf(_("non-numeric src offset argument -- %s\n"), \
> + argv[optind]);
> + return 0;
> + }
> + optind++;
> + doffset = cvtnum(blocksize, sectsize, argv[optind]);
> + if (doffset < 0) {
> + printf(_("non-numeric dest offset argument -- %s\n"), \
> + argv[optind]);
> + return 0;
> + }
> + optind++;
> + count = cvtnum(blocksize, sectsize, argv[optind]);
> + if (count < 0) {
> + printf(_("non-positive length argument -- %s\n"), \
> + argv[optind]);
> + return 0;
For the cvtnum errors, I think I would just say "invalid argument" -
and I'm not sure you can even specify a negative argument this way,
can you? So the "non-positive" error message seems strange.
xfs_io> splice bar 0 0 -4
splice: invalid option -- '4'
also, I notice if "count" is greater than the size of one of (?) the files,
the command seems to hang.
Otherwise, this seems ok, thanks!
-Eric
> + }
> + } else {
> + /*
> + * splice whole file to another, if doesn't specify src and dst
> + * offset and length
> + */
> + struct stat stat;
> +
> + if (fstat(fd, &stat) < 0) {
> + perror("fstat");
> + goto done;
> + }
> + count = stat.st_size;
> + soffset = 0;
> + doffset = 0;
> + }
> +
> + gettimeofday(&t1, NULL);
> + total = splice_file(fd, soffset, doffset, count, splice_flag, &ops);
> + if (ops == 0 || qflag)
> + goto done;
> + gettimeofday(&t2, NULL);
> + t2 = tsub(t2, t1);
> +
> + report_io_times("spliced", &t2, (long long)doffset, count, total, ops, \
> + Cflag);
> +
> +done:
> + if (infile)
> + close(fd);
> + return 0;
> +}
> +
> +void
> +splice_init(void)
> +{
> + splice_cmd.name = "splice";
> + splice_cmd.altname = "spl";
> + splice_cmd.cfunc = splice_f;
> + splice_cmd.argmin = 1;
> + splice_cmd.argmax = -1;
> + splice_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK | CMD_FLAG_ONESHOT;;
> + splice_cmd.args =
> + _("[-m] infile [src_off dst_off len]");
> + splice_cmd.oneline =
> + _("Splice an entire file, or a number of bytes at a specified offset");
> + splice_cmd.help = splice_help;
> +
> + add_command(&splice_cmd);
> +}
> diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
> index 980dcfd3..066a72e7 100644
> --- a/man/man8/xfs_io.8
> +++ b/man/man8/xfs_io.8
> @@ -830,6 +830,32 @@ verbose output will be printed.
> .RE
> .PD
> .TP
> +.BI "splice [ \-C ] [ \-q ] [\-m] infile [src_offset dst_offset length]"
> +On filesystems that support the
> +.BR splice (2)
> +system call, splice data from the
> +.I infile
> +into the open file. If
> +.IR src_offset ,
> +.IR dst_offset ,
> +and
> +.I length
> +are omitted the contents of infile will be copied to the beginning of the
> +open file, overwriting any data already there.
> +.RS 1.0i
> +.PD 0
> +.TP 0.4i
> +.B \-C
> +Print timing statistics in a condensed format.
> +.TP
> +.B \-q
> +Do not print timing statistics at all.
> +.TP
> +.B \-m
> +Enable SPLICE_F_MOVE flag, attempt to move pages instead of copying.
> +.RE
> +.PD
> +.TP
> .BI utimes " atime_sec atime_nsec mtime_sec mtime_nsec"
> The utimes command changes the atime and mtime of the current file.
> sec uses UNIX timestamp notation and is the seconds elapsed since
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2019-05-13 21:13 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-12-08 15:29 [PATCH] xfs_io: support splice data between two files Zorro Lang
-- strict thread matches above, loose matches on Subject: below --
2019-04-06 2:35 Zorro Lang
2019-05-13 21:13 ` Eric Sandeen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox