From patchwork Fri Jul 1 19:45:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schumaker, Anna" X-Patchwork-Id: 9210349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BA0CD60752 for ; Fri, 1 Jul 2016 19:45:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9D532286C7 for ; Fri, 1 Jul 2016 19:45:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8F917286D4; Fri, 1 Jul 2016 19:45:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from oss.sgi.com (oss.sgi.com [192.48.182.195]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6E393286C7 for ; Fri, 1 Jul 2016 19:45:31 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id B30AA7CA4; Fri, 1 Jul 2016 14:45:29 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay1.corp.sgi.com [137.38.102.111]) by oss.sgi.com (Postfix) with ESMTP id 396667CA3 for ; Fri, 1 Jul 2016 14:45:27 -0500 (CDT) Received: from cuda.sgi.com (cuda3.sgi.com [192.48.176.15]) by relay1.corp.sgi.com (Postfix) with ESMTP id EF08C8F8040 for ; Fri, 1 Jul 2016 12:45:26 -0700 (PDT) X-ASG-Debug-ID: 1467402322-04cb6c063e308f90001-NocioJ Received: from mx142.netapp.com (mx142.netapp.com [216.240.21.19]) by cuda.sgi.com with ESMTP id CRK1q2Zz9ZJ8wAgG (version=TLSv1.2 cipher=RC4-SHA bits=128 verify=NO) for ; Fri, 01 Jul 2016 12:45:23 -0700 (PDT) X-Barracuda-Envelope-From: Anna.Schumaker@netapp.com X-Barracuda-Effective-Source-IP: mx142.netapp.com[216.240.21.19] X-Barracuda-Apparent-Source-IP: 216.240.21.19 X-IronPort-AV: E=Sophos;i="5.26,558,1459839600"; d="scan'208";a="120787104" Received: from vmwexchts04-prd.hq.netapp.com ([10.122.105.32]) by mx142-out.netapp.com with ESMTP; 01 Jul 2016 12:45:22 -0700 Received: from smtp1.corp.netapp.com (10.57.156.124) by VMWEXCHTS04-PRD.hq.netapp.com (10.122.105.32) with Microsoft SMTP Server id 15.0.1156.6; Fri, 1 Jul 2016 12:45:17 -0700 Received: from gouda.nowheycreamery.com.hq.netapp.com ([10.63.236.161]) by smtp1.corp.netapp.com (8.13.1/8.13.1/NTAP-1.6) with ESMTP id u61JjK1C013088; Fri, 1 Jul 2016 12:45:21 -0700 (PDT) From: Anna Schumaker To: , Subject: [PATCH] xfs_io: implement 'copy_range' command Date: Fri, 1 Jul 2016 15:45:20 -0400 X-ASG-Orig-Subj: [PATCH] xfs_io: implement 'copy_range' command Message-ID: <20160701194520.28088-1-Anna.Schumaker@Netapp.com> X-Mailer: git-send-email 2.9.0 MIME-Version: 1.0 X-Barracuda-Connect: mx142.netapp.com[216.240.21.19] X-Barracuda-Start-Time: 1467402323 X-Barracuda-Encrypted: RC4-SHA X-Barracuda-URL: https://192.48.176.15:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 7073 X-Virus-Scanned: by bsmtpd at sgi.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 0.50 X-Barracuda-Spam-Status: No, SCORE=0.50 using per-user scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=2.7 tests=BSF_SC0_MV0713 X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.30930 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_SC0_MV0713 Custom rule MV0713 Cc: anna.schumaker@netapp.com X-BeenThere: xfs@oss.sgi.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: XFS Filesystem from SGI List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: xfs-bounces@oss.sgi.com Sender: xfs-bounces@oss.sgi.com X-Virus-Scanned: ClamAV using ClamSMTP Implements a new xfs_io command, named 'copy_range', which is supposed to be used to copy a range of data from one file to another. Signed-off-by: Anna Schumaker --- configure.ac | 1 + include/builddefs.in | 1 + io/Makefile | 5 ++ io/copy_file_range.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 + io/io.h | 6 ++ m4/package_libcdev.m4 | 17 ++++++ 7 files changed, 179 insertions(+) create mode 100644 io/copy_file_range.c diff --git a/configure.ac b/configure.ac index 83f9020..464b314 100644 --- a/configure.ac +++ b/configure.ac @@ -122,6 +122,7 @@ AC_HAVE_GETMNTINFO AC_HAVE_FALLOCATE AC_HAVE_FIEMAP AC_HAVE_PREADV +AC_HAVE_COPY_FILE_RANGE AC_HAVE_SYNC_FILE_RANGE AC_HAVE_MNTENT AC_HAVE_FLS diff --git a/include/builddefs.in b/include/builddefs.in index b5ce336..7153d7a 100644 --- 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_COPY_FILE_RANGE = @have_copy_file_range@ HAVE_SYNC_FILE_RANGE = @have_sync_file_range@ HAVE_READDIR = @have_readdir@ HAVE_MNTENT = @have_mntent@ diff --git a/io/Makefile b/io/Makefile index 0b53f41..62bc03b 100644 --- a/io/Makefile +++ b/io/Makefile @@ -59,6 +59,11 @@ CFILES += inject.c resblks.c LCFLAGS += -DHAVE_INJECT -DHAVE_RESBLKS endif +ifeq ($(HAVE_COPY_FILE_RANGE),yes) +CFILES += copy_file_range.c +LCFLAGS += -DHAVE_COPY_FILE_RANGE +endif + ifeq ($(HAVE_SYNC_FILE_RANGE),yes) CFILES += sync_file_range.c LCFLAGS += -DHAVE_SYNC_FILE_RANGE diff --git a/io/copy_file_range.c b/io/copy_file_range.c new file mode 100644 index 0000000..eddc634 --- /dev/null +++ b/io/copy_file_range.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016 Netapp, 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will 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 to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "command.h" +#include "input.h" +#include "init.h" +#include "io.h" + +static cmdinfo_t copy_range_cmd; + +static void +copy_range_help(void) +{ + printf(_("\n\ + Copies a range of bytes from a file into the open file, overwriting any data\n\ + already there.\n\ +\n\ + Example:\n\ + 'copy_range -s 100 -d 200 -l 300 some_file' - copies 300 bytes from some_file\n\ + at offset 100 into the open\n\ + file at offset 200\n\ + 'copy_range some_file' - copies all bytes from some_file into the open file\n\ + at position 0\n\ +")); +} + +static loff_t +copy_file_range(int fd, loff_t *src, loff_t *dst, size_t len) +{ + loff_t ret; + + do { + ret = syscall(__NR_copy_file_range, fd, src, file->fd, dst, len, 0); + if (ret == -1) + return errno; + len -= ret; + } while (len > 0); + + return 0; +} + +static off64_t +copy_src_filesize(int fd) +{ + struct stat64 st; + + if (fstat64(fd, &st) < 0) { + perror("fstat64"); + return -1; + }; + return st.st_size; +} + +static int +copy_dst_truncate(void) +{ + int ret = ftruncate64(file->fd, 0); + if (ret < 0) + perror("ftruncate64"); + return ret; +} + +static int +copy_range_f(int argc, char **argv) +{ + loff_t src = 0; + loff_t dst = 0; + size_t len = 0; + char *sp; + int opt; + int ret; + int fd; + + while ((opt = getopt(argc, argv, "s:d:l:")) != -1) { + switch (opt) { + case 's': + src = strtoull(optarg, &sp, 10); + if (!sp || sp == optarg) { + printf(_("invalid source offset -- %s\n"), sp); + return 0; + } + break; + case 'd': + dst = strtoull(optarg, &sp, 10); + if (!sp || sp == optarg) { + printf(_("invalid destination offset -- %s\n"), sp); + return 0; + } + break; + case 'l': + len = strtoull(optarg, &sp, 10); + if (!sp || sp == optarg) { + printf(_("invalid length -- %s\n"), sp); + return 0; + } + break; + } + } + + if (optind != argc - 1) + return command_usage(©_range_cmd); + + fd = openfile(argv[optind], NULL, IO_READONLY, 0); + if (fd < 0) + return 0; + + if (src == 0 && dst == 0 && len == 0) { + len = copy_src_filesize(fd); + copy_dst_truncate(); + } + + ret = copy_file_range(fd, &src, &dst, len); + close(fd); + return ret; +} + +void +copy_range_init(void) +{ + copy_range_cmd.name = "copy_range"; + copy_range_cmd.cfunc = copy_range_f; + copy_range_cmd.argmin = 1; + copy_range_cmd.argmax = 7; + copy_range_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; + copy_range_cmd.args = _("[-s src_off] [-d dst_off] [-l len] src_file"); + copy_range_cmd.oneline = _("Copy a range of data between two files"); + copy_range_cmd.help = copy_range_help; + + add_command(©_range_cmd); +} diff --git a/io/init.c b/io/init.c index 51f1f5c..efe7390 100644 --- a/io/init.c +++ b/io/init.c @@ -56,6 +56,7 @@ init_commands(void) { attr_init(); bmap_init(); + copy_range_init(); fadvise_init(); file_init(); flink_init(); diff --git a/io/io.h b/io/io.h index 172b1f8..2bc7ac4 100644 --- a/io/io.h +++ b/io/io.h @@ -150,6 +150,12 @@ extern void fiemap_init(void); #define fiemap_init() do { } while (0) #endif +#ifdef HAVE_COPY_FILE_RANGE +extern void copy_range_init(void); +#else +#define copy_range_init() do { } while (0) +#endif + #ifdef HAVE_SYNC_FILE_RANGE extern void sync_range_init(void); #else diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4 index 0165310..7a847e9 100644 --- a/m4/package_libcdev.m4 +++ b/m4/package_libcdev.m4 @@ -154,6 +154,23 @@ AC_DEFUN([AC_HAVE_PREADV], ]) # +# Check if we have a copy_file_range system call (Linux) +# +AC_DEFUN([AC_HAVE_COPY_FILE_RANGE], + [ AC_MSG_CHECKING([for copy_file_range]) + AC_TRY_LINK([ +#define _GNU_SOURCE +#include +#include + ], [ + syscall(__NR_copy_file_range, 0, 0, 0, 0, 0, 0); + ], have_copy_file_range=yes + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + AC_SUBST(have_copy_file_range) + ]) + +# # Check if we have a sync_file_range libc call (Linux) # AC_DEFUN([AC_HAVE_SYNC_FILE_RANGE],