summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Hernandez <xhernandez@datalab.es>2017-01-10 17:21:56 +0100
committerKaleb KEITHLEY <kkeithle@redhat.com>2017-02-18 12:22:29 -0500
commit621fedf8aeb3e972db33b3eefa6cbdbef104d6a6 (patch)
treeaf15bcd0f4c927c1bcc271bc441c90fea7a39f54
parent3cda64115596f0501bb58209f819655bced22c18 (diff)
posix: Fix creation of files with S_ISVTX on FreeBSD
On FreeBSD the S_ISVTX flag is completely ignored when creating a regular file. Since gluster needs to create files with this flag set, specialy for DHT link files, it's necessary to force the flag. This fix does this by calling fchmod() after creating a file that must have this flag set. Change-Id: I51eecfe4642974df6106b9084a0b144835a4997a BUG: 1411228 Signed-off-by: Xavier Hernandez <xhernandez@datalab.es> Reviewed-on: https://review.gluster.org/16417 Smoke: Gluster Build System <jenkins@build.gluster.org> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> CentOS-regression: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Raghavendra Bhat <raghavendra@redhat.com> Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
-rw-r--r--libglusterfs/src/syscall.c47
-rw-r--r--libglusterfs/src/syscall.h6
-rw-r--r--xlators/cluster/ec/src/ec-code.c2
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.c2
-rw-r--r--xlators/storage/posix/src/posix.c6
5 files changed, 43 insertions, 20 deletions
diff --git a/libglusterfs/src/syscall.c b/libglusterfs/src/syscall.c
index 7336e06891a..4e4c6a728da 100644
--- a/libglusterfs/src/syscall.c
+++ b/libglusterfs/src/syscall.c
@@ -57,25 +57,44 @@ sys_fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
int
-sys_openat(int dirfd, const char *pathname, int flags, ...)
-{
- mode_t mode = 0;
- if (flags & O_CREAT) {
- va_list ap;
- va_start(ap, flags);
- mode = va_arg(ap, int);
- va_end(ap);
- }
+sys_openat(int dirfd, const char *pathname, int flags, int mode)
+{
+ int fd;
#ifdef GF_DARWIN_HOST_OS
if (fchdir(dirfd) < 0)
return -1;
- return open (pathname, flags, mode);
-#else
- return openat (dirfd, pathname, flags, mode);
-#endif
+ fd = open (pathname, flags, mode);
+ /* TODO: Shouldn't we restore the old current directory */
+#else /* GF_DARWIN_HOST_OS */
+ fd = openat (dirfd, pathname, flags, mode);
+#ifdef __FreeBSD__
+ /* On FreeBSD S_ISVTX flag is ignored for an open() with O_CREAT set.
+ * We need to force the flag using fchmod(). */
+ if ((fd >= 0) &&
+ ((flags & O_CREAT) != 0) && ((mode & S_ISVTX) != 0)) {
+ sys_fchmod(fd, mode);
+ /* TODO: It's unlikely that fchmod could fail here. However,
+ if it fails we cannot always restore the old state
+ (if the file existed, we cannot recover it). We would
+ need many more system calls to correctly handle all
+ possible cases and it doesn't worth it. For now we
+ simply ignore the error. */
+ }
+#endif /* __FreeBSD__ */
+#endif /* !GF_DARWIN_HOST_OS */
+
+ return fd;
}
+
+int
+sys_open(const char *pathname, int flags, int mode)
+{
+ return sys_openat(AT_FDCWD, pathname, flags, mode);
+}
+
+
DIR *
sys_opendir (const char *name)
{
@@ -256,7 +275,7 @@ sys_utimes (const char *filename, const struct timeval times[2])
int
sys_creat (const char *pathname, mode_t mode)
{
- return creat (pathname, mode);
+ return sys_open(pathname, O_CREAT | O_TRUNC | O_WRONLY, mode);
}
diff --git a/libglusterfs/src/syscall.h b/libglusterfs/src/syscall.h
index 1a2658b94f1..b1bcad138c5 100644
--- a/libglusterfs/src/syscall.h
+++ b/libglusterfs/src/syscall.h
@@ -63,8 +63,12 @@ sys_fstat (int fd, struct stat *buf);
int
sys_fstatat (int dirfd, const char *pathname, struct stat *buf,
int flags);
+
+int
+sys_open (const char *pathname, int flags, int mode);
+
int
-sys_openat (int dirfd, const char *pathname, int flags, ...);
+sys_openat (int dirfd, const char *pathname, int flags, int mode);
DIR *sys_opendir (const char *name);
diff --git a/xlators/cluster/ec/src/ec-code.c b/xlators/cluster/ec/src/ec-code.c
index 9647a08287c..25a501e61b7 100644
--- a/xlators/cluster/ec/src/ec-code.c
+++ b/xlators/cluster/ec/src/ec-code.c
@@ -963,7 +963,7 @@ ec_code_detect(xlator_t *xl, const char *def)
return NULL;
}
- file.fd = sys_openat(AT_FDCWD, PROC_CPUINFO, O_RDONLY);
+ file.fd = sys_open(PROC_CPUINFO, O_RDONLY, 0);
if (file.fd < 0) {
goto out;
}
diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c
index 88361877efe..11d4b8bc79f 100644
--- a/xlators/mgmt/glusterd/src/glusterd.c
+++ b/xlators/mgmt/glusterd/src/glusterd.c
@@ -947,7 +947,7 @@ check_prepare_mountbroker_root (char *mountbroker_root)
dfd0 = dup (dfd);
for (;;) {
- ret = sys_openat (dfd, "..", O_RDONLY);
+ ret = sys_openat (dfd, "..", O_RDONLY, 0);
if (ret != -1) {
dfd2 = ret;
ret = sys_fstat (dfd2, &st2);
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index c989d5527a1..aa7e7404099 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -2006,7 +2006,7 @@ posix_unlink (call_frame_t *frame, xlator_t *this,
if (fdstat_requested ||
(priv->background_unlink && IA_ISREG (loc->inode->ia_type))) {
- fd = open (real_path, O_RDONLY);
+ fd = sys_open (real_path, O_RDONLY, 0);
if (fd == -1) {
op_ret = -1;
op_errno = errno;
@@ -2867,7 +2867,7 @@ posix_create (call_frame_t *frame, xlator_t *this,
if (priv->o_direct)
_flags |= O_DIRECT;
- _fd = open (real_path, _flags, mode);
+ _fd = sys_open (real_path, _flags, mode);
if (_fd == -1) {
op_errno = errno;
@@ -3028,7 +3028,7 @@ posix_open (call_frame_t *frame, xlator_t *this,
if (priv->o_direct)
flags |= O_DIRECT;
- _fd = open (real_path, flags, 0);
+ _fd = sys_open (real_path, flags, 0);
if (_fd == -1) {
op_ret = -1;
op_errno = errno;
s='right'>27
-rw-r--r--xlators/features/changelog/lib/src/Makefile.am2
-rwxr-xr-xxlators/features/utime/src/utime-gen-fops-c.py18
-rwxr-xr-xxlators/features/utime/src/utime-gen-fops-h.py2
-rw-r--r--xlators/features/utime/src/utime-helpers.c9
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.c114
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.h36
-rw-r--r--xlators/protocol/client/src/client-common.c32
-rw-r--r--xlators/protocol/client/src/client-common.h6
-rw-r--r--xlators/protocol/client/src/client-helpers.c28
-rw-r--r--xlators/protocol/client/src/client-rpc-fops_v2.c141
-rw-r--r--xlators/protocol/client/src/client.c36
-rw-r--r--xlators/protocol/client/src/client.h22
-rw-r--r--xlators/protocol/server/src/server-common.c10
-rw-r--r--xlators/protocol/server/src/server-common.h5
-rw-r--r--xlators/protocol/server/src/server-helpers.c8
-rw-r--r--xlators/protocol/server/src/server-resolve.c39
-rw-r--r--xlators/protocol/server/src/server-rpc-fops_v2.c130
-rw-r--r--xlators/protocol/server/src/server.h14
-rw-r--r--xlators/storage/posix/src/posix-helpers.c20
-rw-r--r--xlators/storage/posix/src/posix-inode-fd-ops.c268
-rw-r--r--xlators/storage/posix/src/posix-messages.h3
-rw-r--r--xlators/storage/posix/src/posix-metadata.c78
-rw-r--r--xlators/storage/posix/src/posix-metadata.h5
-rw-r--r--xlators/storage/posix/src/posix.c1
-rw-r--r--xlators/storage/posix/src/posix.h7
57 files changed, 1911 insertions, 19 deletions
diff --git a/api/src/Makefile.am b/api/src/Makefile.am
index 6ed30bc99f6..7f9a7d17b35 100644
--- a/api/src/Makefile.am
+++ b/api/src/Makefile.am
@@ -19,7 +19,7 @@ libgfapi_la_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
-I$(top_srcdir)/rpc/xdr/src \
-I$(top_builddir)/rpc/xdr/src \
-DDATADIR=\"$(localstatedir)\" \
- -D__USE_FILE_OFFSET64
+ -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64
AM_CFLAGS = -Wall $(GF_CFLAGS)
diff --git a/api/src/gfapi.aliases b/api/src/gfapi.aliases
index a71422c8577..0e52c38d346 100644
--- a/api/src/gfapi.aliases
+++ b/api/src/gfapi.aliases
@@ -188,3 +188,4 @@ _pub_glfs_ftruncate _glfs_ftruncate$GFAPI_future
_pub_glfs_ftruncate_async _glfs_ftruncate_async$GFAPI_future
_pub_glfs_discard_async _glfs_discard_async$GFAPI_future
_pub_glfs_zerofill_async _glfs_zerofill_async$GFAPI_future
+_pub_glfs_copy_file_range _glfs_copy_file_range$GFAPI_future \ No newline at end of file
diff --git a/api/src/gfapi.map b/api/src/gfapi.map
index c47323781fb..1be2953ce9a 100644
--- a/api/src/gfapi.map
+++ b/api/src/gfapi.map
@@ -255,5 +255,6 @@ GFAPI_future {
glfs_ftruncate_async;
glfs_discard_async;
glfs_zerofill_async;
+ glfs_copy_file_range;
} GFAPI_4.1.6;
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index 2a1cc73ccee..f59990aed1f 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -1333,6 +1333,161 @@ invalid_fs:
}
ssize_t
+pub_glfs_copy_file_range(struct glfs_fd *glfd_in, off64_t *off_in,
+ struct glfs_fd *glfd_out, off64_t *off_out, size_t len,
+ unsigned int flags, struct stat *statbuf,
+ struct stat *prestat, struct stat *poststat)
+{
+ xlator_t *subvol = NULL;
+ int ret = -1;
+ fd_t *fd_in = NULL;
+ fd_t *fd_out = NULL;
+ struct iatt preiatt =
+ {
+ 0,
+ },
+ iattbuf =
+ {
+ 0,
+ },
+ postiatt = {
+ 0,
+ };
+ dict_t *fop_attr = NULL;
+ off64_t pos_in;
+ off64_t pos_out;
+
+ DECLARE_OLD_THIS;
+ __GLFS_ENTRY_VALIDATE_FD(glfd_in, invalid_fs);
+ __GLFS_ENTRY_VALIDATE_FD(glfd_out, invalid_fs);
+
+ GF_REF_GET(glfd_in);
+ GF_REF_GET(glfd_out);
+
+ if (glfd_in->fs != glfd_out->fs) {
+ ret = -1;
+ errno = EXDEV;
+ goto out;
+ }
+
+ subvol = glfs_active_subvol(glfd_in->fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
+
+ fd_in = glfs_resolve_fd(glfd_in->fs, subvol, glfd_in);
+ if (!fd_in) {
+ ret = -1;
+ errno = EBADFD;
+ goto out;
+ }
+
+ fd_out = glfs_resolve_fd(glfd_out->fs, subvol, glfd_out);
+ if (!fd_out) {
+ ret = -1;
+ errno = EBADFD;
+ goto out;
+ }
+
+ /*
+ * This is based on how the vfs layer in the kernel handles
+ * copy_file_range call. Upon receiving it follows the
+ * below method to consider the offset.
+ * if (off_in != NULL)
+ * use the value off_in to perform the op
+ * else if off_in == NULL
+ * use the current file offset position to perform the op
+ *
+ * For gfapi, glfd->offset is used. For a freshly opened
+ * fd, the offset is set to 0.
+ */
+ if (off_in)
+ pos_in = *off_in;
+ else
+ pos_in = glfd_in->offset;
+
+ if (off_out)
+ pos_out = *off_out;
+ else
+ pos_out = glfd_out->offset;
+
+ ret = get_fop_attr_thrd_key(&fop_attr);
+ if (ret)
+ gf_msg_debug("gfapi", 0, "Getting leaseid from thread failed");
+
+ ret = syncop_copy_file_range(subvol, fd_in, pos_in, fd_out, pos_out, len,
+ flags, &iattbuf, &preiatt, &postiatt, fop_attr,
+ NULL);
+ DECODE_SYNCOP_ERR(ret);
+
+ if (ret >= 0) {
+ pos_in += ret;
+ pos_out += ret;
+
+ if (off_in)
+ *off_in = pos_in;
+ if (off_out)
+ *off_out = pos_out;
+
+ if (statbuf)
+ glfs_iatt_to_stat(glfd_in->fs, &iattbuf, statbuf);
+ if (prestat)
+ glfs_iatt_to_stat(glfd_in->fs, &preiatt, prestat);
+ if (poststat)
+ glfs_iatt_to_stat(glfd_in->fs, &postiatt, poststat);
+ }
+
+ if (ret <= 0)
+ goto out;
+
+ /*
+ * If *off_in is NULL, then there is no offset info that can
+ * obtained from the input argument. Hence follow below method.
+ * If *off_in is NULL, then
+ * glfd->offset = offset + ret;
+ * else
+ * do nothing.
+ *
+ * According to the man page of copy_file_range, if off_in is
+ * NULL, then the offset of the source file is advanced by
+ * the return value of the fop. The same applies to off_out as
+ * well. Otherwise, if *off_in is not NULL, then the offset
+ * is not advanced by the filesystem. The entity which sends
+ * the copy_file_range call is supposed to advance the offset
+ * value in its buffer (pointed to by *off_in or *off_out)
+ * by the return value of copy_file_range.
+ */
+ if (!off_in)
+ glfd_in->offset += ret;
+
+ if (!off_out)
+ glfd_out->offset += ret;
+
+out:
+ if (fd_in)
+ fd_unref(fd_in);
+ if (fd_out)
+ fd_unref(fd_out);
+ if (glfd_in)
+ GF_REF_PUT(glfd_in);
+ if (glfd_out)
+ GF_REF_PUT(glfd_out);
+ if (fop_attr)
+ dict_unref(fop_attr);
+
+ glfs_subvol_done(glfd_in->fs, subvol);
+
+ __GLFS_EXIT_FS;
+
+invalid_fs:
+ return ret;
+}
+
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_copy_file_range, future);
+
+ssize_t
pub_glfs_pwritev(struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,
off_t offset, int flags)
{
diff --git a/api/src/glfs.h b/api/src/glfs.h
index cd642a5ea20..160a784222f 100644
--- a/api/src/glfs.h
+++ b/api/src/glfs.h
@@ -42,6 +42,38 @@
#include <sys/statvfs.h>
#include <inttypes.h>
+/*
+ * For off64_t to be defined, we need both
+ * __USE_LARGEFILE64 to be true and __off64_t_defnined to be
+ * false. But, making __USE_LARGEFILE64 true causes other issues
+ * such as redinition of stat and fstat to stat64 and fstat64
+ * respectively which again causes compilation issues.
+ * Without off64_t being defined, this will not compile as
+ * copy_file_range uses off64_t. Hence define it here. First
+ * check whether __off64_t_defined is true or not. <unistd.h>
+ * sets that flag when it defines off64_t. If __off64_t_defined
+ * is false and __USE_FILE_OFFSET64 is true, then go on to define
+ * off64_t using __off64_t.
+ */
+#ifndef GF_BSD_HOST_OS
+#if defined(__USE_FILE_OFFSET64) && !defined(__off64_t_defined)
+typedef __off64_t off64_t;
+#endif /* defined(__USE_FILE_OFFSET64) && !defined(__off64_t_defined) */
+#else
+#include <stdio.h>
+#ifndef _OFF64_T_DECLARED
+/*
+ * Including <stdio.h> (done above) should actually define
+ * _OFF64_T_DECLARED with off64_t data type being available
+ * for consumption. But, off64_t data type is not recognizable
+ * for FreeBSD versions less than 11. Hence, int64_t is typedefed
+ * to off64_t.
+ */
+#define _OFF64_T_DECLARED
+typedef int64_t off64_t;
+#endif /* _OFF64_T_DECLARED */
+#endif /* GF_BSD_HOST_OS */
+
#if defined(HAVE_SYS_ACL_H) || (defined(USE_POSIX_ACLS) && USE_POSIX_ACLS)
#include <sys/acl.h>
#else
@@ -594,6 +626,13 @@ off_t
glfs_lseek(glfs_fd_t *fd, off_t offset, int whence) __THROW
GFAPI_PUBLIC(glfs_lseek, 3.4.0);
+ssize_t
+glfs_copy_file_range(struct glfs_fd *glfd_in, off64_t *off_in,
+ struct glfs_fd *glfd_out, off64_t *off_out, size_t len,
+ unsigned int flags, struct stat *statbuf,
+ struct stat *prestat, struct stat *poststat) __THROW
+ GFAPI_PUBLIC(glfs_copy_file_range, future);
+
int
glfs_truncate(glfs_t *fs, const char *path, off_t length) __THROW
GFAPI_PUBLIC(glfs_truncate, 3.7.15);
diff --git a/configure.ac b/configure.ac
index 3ddb6f073a5..d3c8f8b9514 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1018,6 +1018,25 @@ if test "x${have_posix_fallocate}" = "xyes"; then
AC_DEFINE(HAVE_POSIX_FALLOCATE, 1, [define if posix_fallocate exists])
fi
+# On fedora-29, copy_file_range syscall and the libc API both are present.
+# Whereas, on some machines such as centos-7, RHEL-7, the API is not there.
+# Only the system call is present. So, this change is to determine whether
+# the API is present or not. If not, then check whether the system call is
+# present or not. Accordingly sys_copy_file_range function will first call
+# the API if it is there. Otherwise it will call syscall(SYS_copy_file_range).
+AC_CHECK_FUNC([copy_file_range], [have_copy_file_range=yes])
+if test "x${have_copy_file_range}" = "xyes"; then
+ AC_DEFINE(HAVE_COPY_FILE_RANGE, 1, [define if copy_file_range exists])
+else
+ OLD_CFLAGS=${CFLAGS}
+ CFLAGS="-D_GNU_SOURCE"
+ AC_CHECK_DECL([SYS_copy_file_range], , , [#include <sys/syscall.h>])
+ if test "x${ac_cv_have_decl_SYS_copy_file_range}" = "xyes"; then
+ AC_DEFINE(HAVE_COPY_FILE_RANGE_SYS, 1, [define if SYS_copy_file_range is available])
+ fi
+ CFLAGS=${OLD_CFLAGS}
+fi
+
BUILD_NANOSECOND_TIMESTAMPS=no
AC_CHECK_FUNC([utimensat], [have_utimensat=yes])
if test "x${have_utimensat}" = "xyes"; then
diff --git a/glusterfs-api.pc.in b/glusterfs-api.pc.in
index 6af4e108f7f..4a2edb7bf07 100644
--- a/glusterfs-api.pc.in
+++ b/glusterfs-api.pc.in
@@ -9,4 +9,4 @@ Description: GlusterFS API
Version: @GFAPI_VERSION@
Requires: @PKGCONFIG_UUID@
Libs: -L${libdir} @GFAPI_LIBS@ -lgfapi -lglusterfs -lgfrpc -lgfxdr
-Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64 -DUSE_POSIX_ACLS=@USE_POSIX_ACLS@
+Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64 -DUSE_POSIX_ACLS=@USE_POSIX_ACLS@
diff --git a/libgfchangelog.pc.in b/libgfchangelog.pc.in
index e2ff1fb6214..79eac2ad2d3 100644
--- a/libgfchangelog.pc.in
+++ b/libgfchangelog.pc.in
@@ -9,4 +9,4 @@ Description: GlusterFS Changelog Consumer Library
Version: @LIBGFCHANGELOG_VERSION@
Requires: @PKGCONFIG_UUID@
Libs: -L${libdir} -lgfchangelog -lglusterfs
-Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64
+Cflags: -I${includedir} -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
index 1d06f1586a9..970f4b74978 100644
--- a/libglusterfs/src/Makefile.am
+++ b/libglusterfs/src/Makefile.am
@@ -6,7 +6,7 @@ libglusterfs_la_CFLAGS = $(GF_CFLAGS) $(GF_DARWIN_LIBGLUSTERFS_CFLAGS) \
libglusterfs_la_CPPFLAGS = $(GF_CPPFLAGS) -D__USE_FILE_OFFSET64 \
-DXLATORDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator\" \
-DXLATORPARENTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)\" \
- -DXXH_NAMESPACE=GF_ \
+ -DXXH_NAMESPACE=GF_ -D__USE_LARGEFILE64 \
-I$(top_srcdir)/rpc/xdr/src/ -I$(top_builddir)/rpc/xdr/src/ \
-I$(top_srcdir)/rpc/rpc-lib/src/ -I$(CONTRIBDIR)/rbtree \
-I$(CONTRIBDIR)/libexecinfo ${ARGP_STANDALONE_CPPFLAGS} \
diff --git a/libglusterfs/src/call-stub.c b/libglusterfs/src/call-stub.c
index 96454dfaeb5..886dfa52ccc 100644
--- a/libglusterfs/src/call-stub.c
+++ b/libglusterfs/src/call-stub.c
@@ -1818,6 +1818,51 @@ out:
}
call_stub_t *
+fop_copy_file_range_stub(call_frame_t *frame, fop_copy_file_range_t fn,
+ fd_t *fd_in, off64_t off_in, fd_t *fd_out,
+ off64_t off_out, size_t len, uint32_t flags,
+ dict_t *xdata)
+{
+ call_stub_t *stub = NULL;
+
+ GF_VALIDATE_OR_GOTO("call-stub", frame, out);
+ GF_VALIDATE_OR_GOTO("call-stub", fn, out);
+
+ stub = stub_new(frame, 1, GF_FOP_COPY_FILE_RANGE);
+ GF_VALIDATE_OR_GOTO("call-stub", stub, out);
+
+ stub->fn.copy_file_range = fn;
+
+ args_copy_file_range_store(&stub->args, fd_in, off_in, fd_out, off_out, len,
+ flags, xdata);
+
+out:
+ return stub;
+}
+
+call_stub_t *
+fop_copy_file_range_cbk_stub(call_frame_t *frame, fop_copy_file_range_cbk_t fn,
+ int32_t op_ret, int32_t op_errno,
+ struct iatt *stbuf, struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata)
+{
+ call_stub_t *stub = NULL;
+
+ GF_VALIDATE_OR_GOTO("call-stub", frame, out);
+ GF_VALIDATE_OR_GOTO("call-stub", fn, out);
+
+ stub = stub_new(frame, 0, GF_FOP_COPY_FILE_RANGE);
+ GF_VALIDATE_OR_GOTO("call-stub", stub, out);
+
+ stub->fn_cbk.copy_file_range = fn;
+ args_copy_file_range_cbk_store(&stub->args_cbk, op_ret, op_errno, stbuf,
+ prebuf_dst, postbuf_dst, xdata);
+
+out:
+ return stub;
+}
+
+call_stub_t *
fop_put_stub(call_frame_t *frame, fop_put_t fn, loc_t *loc, mode_t mode,
mode_t umask, uint32_t flags, struct iovec *vector, int32_t count,
off_t offset, struct iobref *iobref, dict_t *xattr, dict_t *xdata)
@@ -2213,6 +2258,13 @@ call_resume_wind(call_stub_t *stub)
stub->args.iobref, stub->args.xattr, stub->args.xdata);
break;
+ case GF_FOP_COPY_FILE_RANGE:
+ stub->fn.copy_file_range(
+ stub->frame, stub->frame->this, stub->args.fd,
+ stub->args.off_in, stub->args.fd_dst, stub->args.off_out,
+ stub->args.size, stub->args.flags, stub->args.xdata);
+ break;
+
default:
gf_msg_callingfn("call-stub", GF_LOG_ERROR, EINVAL,
LG_MSG_INVALID_ENTRY,
@@ -2439,6 +2491,12 @@ call_resume_unwind(call_stub_t *stub)
stub->args_cbk.xdata);
break;
+ case GF_FOP_COPY_FILE_RANGE:
+ STUB_UNWIND(stub, copy_file_range, &stub->args_cbk.stat,
+ &stub->args_cbk.prestat, &stub->args_cbk.poststat,
+ stub->args_cbk.xdata);
+ break;
+
default:
gf_msg_callingfn("call-stub", GF_LOG_ERROR, EINVAL,
LG_MSG_INVALID_ENTRY,
diff --git a/libglusterfs/src/default-args.c b/libglusterfs/src/default-args.c
index 479974e1637..cfceabd1f46 100644
--- a/libglusterfs/src/default-args.c
+++ b/libglusterfs/src/default-args.c
@@ -1541,6 +1541,48 @@ args_namelink_store(default_args_t *args, loc_t *loc, dict_t *xdata)
return 0;
}
+int
+args_copy_file_range_store(default_args_t *args, fd_t *fd_in, off64_t off_in,
+ fd_t *fd_out, off64_t off_out, size_t len,
+ uint32_t flags, dict_t *xdata)
+{
+ if (fd_in)
+ args->fd = fd_ref(fd_in);
+ if (fd_out)
+ args->fd_dst = fd_ref(fd_out);
+ args->size = len;
+ args->off_in = off_in;
+ args->off_out = off_out;
+ args->flags = flags;
+
+ if (xdata)
+ args->xdata = dict_ref(xdata);
+
+ return 0;
+}
+
+int
+args_copy_file_range_cbk_store(default_args_cbk_t *args, int32_t op_ret,
+ int32_t op_errno, struct iatt *stbuf,
+ struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata)
+{
+ args->op_ret = op_ret;
+ args->op_errno = op_errno;
+ if (op_ret >= 0) {
+ if (postbuf_dst)
+ args->poststat = *postbuf_dst;
+ if (prebuf_dst)
+ args->prestat = *prebuf_dst;
+ if (stbuf)
+ args->stat = *stbuf;
+ }
+ if (xdata)
+ args->xdata = dict_ref(xdata);
+
+ return 0;
+}
+
void
args_cbk_wipe(default_args_cbk_t *args_cbk)
{
diff --git a/libglusterfs/src/defaults-tmpl.c b/libglusterfs/src/defaults-tmpl.c
index 97de8193dcb..5bf64e8c6c6 100644
--- a/libglusterfs/src/defaults-tmpl.c
+++ b/libglusterfs/src/defaults-tmpl.c
@@ -84,6 +84,7 @@ struct xlator_fops _default_fops = {
.put = default_put,
.icreate = default_icreate,
.namelink = default_namelink,
+ .copy_file_range = default_copy_file_range,
};
struct xlator_fops *default_fops = &_default_fops;
diff --git a/libglusterfs/src/generator.py b/libglusterfs/src/generator.py
index c17d450502d..5b7aa4764a0 100755
--- a/libglusterfs/src/generator.py
+++ b/libglusterfs/src/generator.py
@@ -599,6 +599,19 @@ ops['namelink'] = (
('cbk-arg', 'xdata', 'dict_t *'),
)
+ops['copy_file_range'] = (
+ ('fop-arg', 'fd_in', 'fd_t *'),
+ ('fop-arg', 'off_in', 'off64_t '),
+ ('fop-arg', 'fd_out', 'fd_t *'),
+ ('fop-arg', 'off_out', 'off64_t '),
+ ('fop-arg', 'len', 'size_t'),
+ ('fop-arg', 'flags', 'uint32_t'),
+ ('fop-arg', 'xdata', 'dict_t *'),
+ ('cbk-arg', 'stbuf', 'struct iatt *'),
+ ('cbk-arg', 'prebuf_dst', 'struct iatt *'),
+ ('cbk-arg', 'postbuf_dst', 'struct iatt *'),
+ ('cbk-arg', 'xdata', 'dict_t *'),
+)
#####################################################################
xlator_cbks['forget'] = (
('fn-arg', 'this', 'xlator_t *'),
diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c
index 35482545ab3..4fec0638926 100644
--- a/libglusterfs/src/globals.c
+++ b/libglusterfs/src/globals.c
@@ -77,6 +77,7 @@ const char *gf_fop_list[GF_FOP_MAXVALUE] = {
[GF_FOP_PUT] = "PUT",
[GF_FOP_ICREATE] = "ICREATE",
[GF_FOP_NAMELINK] = "NAMELINK",
+ [GF_FOP_COPY_FILE_RANGE] = "COPY_FILE_RANGE",
};
const char *gf_upcall_list[GF_UPCALL_FLAGS_MAXVALUE] = {
diff --git a/libglusterfs/src/glusterfs/call-stub.h b/libglusterfs/src/glusterfs/call-stub.h
index bfed0fbc14a..c01c935e73d 100644
--- a/libglusterfs/src/glusterfs/call-stub.h
+++ b/libglusterfs/src/glusterfs/call-stub.h
@@ -81,6 +81,7 @@ typedef struct _call_stub {
fop_put_t put;
fop_icreate_t icreate;
fop_namelink_t namelink;
+ fop_copy_file_range_t copy_file_range;
} fn;
union {
@@ -136,6 +137,7 @@ typedef struct _call_stub {
fop_put_cbk_t put;
fop_icreate_cbk_t icreate;
fop_namelink_cbk_t namelink;
+ fop_copy_file_range_cbk_t copy_file_range;
} fn_cbk;
default_args_t args;
@@ -589,6 +591,18 @@ fop_namelink_cbk_stub(call_frame_t *frame, fop_namelink_cbk_t fn,
int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
struct iatt *postbuf, dict_t *xdata);
+call_stub_t *
+fop_copy_file_range_stub(call_frame_t *frame, fop_copy_file_range_t fn,
+ fd_t *fd_in, off64_t off_in, fd_t *fd_out,
+ off64_t off_out, size_t len, uint32_t flags,
+ dict_t *xdata);
+
+call_stub_t *
+fop_copy_file_range_cbk_stub(call_frame_t *frame, fop_copy_file_range_cbk_t fn,
+ int32_t op_ret, int32_t op_errno,
+ struct iatt *stbuf, struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata);
+
void
call_resume(call_stub_t *stub);
void
diff --git a/libglusterfs/src/glusterfs/compat.h b/libglusterfs/src/glusterfs/compat.h
index 38c07b5ae7c..9374b79f9af 100644
--- a/libglusterfs/src/glusterfs/compat.h
+++ b/libglusterfs/src/glusterfs/compat.h
@@ -116,6 +116,25 @@
#include <limits.h>
#include <libgen.h>
+/*
+ * This is where things like off64_t are defined.
+ * So include it before declaring _OFF64_T_DECLARED.
+ * If the freebsd version has support for off64_t
+ * including stdio.h should be sufficient.
+ */
+#include <stdio.h>
+
+#ifndef _OFF64_T_DECLARED
+/*
+ * Including <stdio.h> (done above) should actually define
+ * _OFF64_T_DECLARED with off64_t data type being available
+ * for consumption. But, off64_t data type is not recognizable
+ * for FreeBSD versions less than 11. Hence, int64_t is typedefed
+ * to off64_t.
+ */
+#define _OFF64_T_DECLARED
+typedef int64_t off64_t;
+#endif /* _OFF64_T_DECLARED */
#ifndef XATTR_CREATE
enum {
diff --git a/libglusterfs/src/glusterfs/default-args.h b/libglusterfs/src/glusterfs/default-args.h
index f15f558202b..ca7526fcab6 100644
--- a/libglusterfs/src/glusterfs/default-args.h
+++ b/libglusterfs/src/glusterfs/default-args.h
@@ -234,6 +234,12 @@ void
args_lease_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno,
struct gf_lease *lease, dict_t *xdata);
+int
+args_copy_file_range_cbk_store(default_args_cbk_t *args, int32_t op_ret,
+ int32_t op_errno, struct iatt *stbuf,
+ struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata);
+
void
args_cbk_wipe(default_args_cbk_t *args_cbk);
@@ -439,6 +445,11 @@ args_icreate_store(default_args_t *args, loc_t *loc, mode_t mode,
int
args_namelink_store(default_args_t *args, loc_t *loc, dict_t *xdata);
+int
+args_copy_file_range_store(default_args_t *args, fd_t *fd_in, off64_t off_in,
+ fd_t *fd_out, off_t off64_out, size_t len,
+ uint32_t flags, dict_t *xdata);
+
void
args_cbk_init(default_args_cbk_t *args_cbk);
#endif /* _DEFAULT_ARGS_H */
diff --git a/libglusterfs/src/glusterfs/defaults.h b/libglusterfs/src/glusterfs/defaults.h
index 5d6b8e28a51..5a818eeb91a 100644
--- a/libglusterfs/src/glusterfs/defaults.h
+++ b/libglusterfs/src/glusterfs/defaults.h
@@ -48,10 +48,20 @@ typedef struct {
} default_args_cbk_t;
typedef struct {
- loc_t loc; /* @old in rename(), link() */
- loc_t loc2; /* @new in rename(), link() */
- fd_t *fd;
+ loc_t loc; /* @old in rename(), link() */
+ loc_t loc2; /* @new in rename(), link() */
+ fd_t *fd; /* for all the fd based ops */
+ fd_t *fd_dst; /* Only for copy_file_range destination */
off_t offset;
+ /*
+ * According to the man page of copy_file_range,
+ * the offsets for source and destination file
+ * are of type loff_t. But the type loff_t is
+ * linux specific and is actual a typedef of
+ * off64_t.
+ */
+ off64_t off_in; /* For copy_file_range source fd */
+ off64_t off_out; /* For copy_file_range destination fd only */
int mask;
size_t size;
mode_t mode;
@@ -323,6 +333,11 @@ int32_t
default_namelink(call_frame_t *frame, xlator_t *this, loc_t *loc,
dict_t *xdata);
+int32_t
+default_copy_file_range(call_frame_t *frame, xlator_t *this, fd_t *fd_in,
+ off64_t off_in, fd_t *fd_out, off64_t off_out,
+ size_t len, uint32_t flags, dict_t *xdata);
+
/* Resume */
int32_t
default_getspec_resume(call_frame_t *frame, xlator_t *this, const char *key,
@@ -542,6 +557,11 @@ default_put_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
int32_t count, off_t off, struct iobref *iobref,
dict_t *xattr, dict_t *xdata);
+int32_t
+default_copy_file_range_resume(call_frame_t *frame, xlator_t *this, fd_t *fd_in,
+ off_t off64_in, fd_t *fd_out, off64_t off_out,
+ size_t len, uint32_t flags, dict_t *xdata);
+
/* _cbk_resume */
int32_t
@@ -813,6 +833,13 @@ int32_t
default_namelink_resume(call_frame_t *frame, xlator_t *this, loc_t *loc,
dict_t *xdata);
+int32_t
+default_copy_file_range_cbk_resume(call_frame_t *frame, void *cookie,
+ xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct iatt *stbuf,
+ struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata);
+
/* _CBK */
int32_t
default_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
@@ -1072,6 +1099,12 @@ default_namelink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
struct iatt *postbuf, dict_t *xdata);
int32_t
+default_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ struct iatt *stbuf, struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata);
+
+int32_t
default_lookup_failure_cbk(call_frame_t *frame, int32_t op_errno);
int32_t
@@ -1231,6 +1264,9 @@ int32_t
default_namelink_failure_cbk(call_frame_t *frame, int32_t op_errno);
int32_t
+default_copy_file_range_failure_cbk(call_frame_t *frame, int32_t op_errno);
+
+int32_t
default_mem_acct_init(xlator_t *this);
void
diff --git a/libglusterfs/src/glusterfs/syncop.h b/libglusterfs/src/glusterfs/syncop.h
index 203abe92b57..7a6167b0488 100644
--- a/libglusterfs/src/glusterfs/syncop.h
+++ b/libglusterfs/src/glusterfs/syncop.h
@@ -138,8 +138,19 @@ typedef struct syncbarrier syncbarrier_t;
struct syncargs {
int op_ret;
int op_errno;
+
+ /*
+ * The below 3 iatt structures are used in the fops
+ * whose callbacks get struct iatt as one of the
+ * a return arguments. Currently, the maximum number
+ * of iatt structures returned is 3 for some fops
+ * such as mknod, copy_file_range, mkdir etc. So
+ * all the following 3 iatt structures would be used
+ * for those fops.
+ */
struct iatt iatt1;
struct iatt iatt2;
+ struct iatt iatt3;
dict_t *xattr;
struct statvfs statvfs_buf;
struct iovec *vector;
@@ -634,4 +645,17 @@ syncop_entrylk(xlator_t *subvol, const char *volume, loc_t *loc,
const char *basename, entrylk_cmd cmd, entrylk_type type,
dict_t *xdata_in, dict_t **xdata_out);
+int
+syncop_copy_file_range(xlator_t *subvol, fd_t *fd_in, off64_t off_in,
+ fd_t *fd_out, off64_t off_out, size_t len,
+ uint32_t flags, struct iatt *stbuf,
+ struct iatt *preiatt_dst, struct iatt *postiatt_dst,
+ dict_t *xdata_in, dict_t **xdata_out);
+
+int
+syncop_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int op_ret, int op_errno, struct iatt *stbuf,
+ struct iatt *prebuf_dst, struct iatt *postbuf_dst,
+ dict_t *xdata);
+
#endif /* _SYNCOP_H */
diff --git a/libglusterfs/src/glusterfs/syscall.h b/libglusterfs/src/glusterfs/syscall.h
index faaf694b22c..6b33c141a5e 100644
--- a/libglusterfs/src/glusterfs/syscall.h
+++ b/libglusterfs/src/glusterfs/syscall.h
@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
+#include <stdio.h>
/* GF follows the Linux XATTR definition, which differs in Darwin. */
#define GF_XATTR_CREATE 0x1 /* set value, fail if attr already exists */
@@ -228,4 +229,32 @@ sys_socket(int domain, int type, int protocol);
int
sys_accept(int sock, struct sockaddr *sockaddr, socklen_t *socklen, int flags);
+#ifdef GF_BSD_HOST_OS
+#ifndef _OFF64_T_DECLARED
+/*
+ * Including <stdio.h> (done above) should actually define
+ * _OFF64_T_DECLARED with off64_t data type being available
+ * for consumption. But, off64_t data type is not recognizable
+ * for FreeBSD versions less than 11. Hence, int64_t is typedefed
+ * to off64_t.
+ */
+#define _OFF64_T_DECLARED
+typedef int64_t off64_t;
+#endif /* _OFF64_T_DECLARED */
+#endif /* GF_BSD_HOST_OS */
+
+/*
+ * According to the man page of copy_file_range, both off_in and off_out are
+ * pointers to the data type loff_t (i.e. loff_t *). But, freebsd does not
+ * have (and recognize) loff_t. Since loff_t is 64 bits, use off64_t
+ * instead. Since it's a pointer type it should be okay. It just needs
+ * to be a pointer-to-64-bit pointer for both 32- and 64-bit platforms.
+ * off64_t is recognized by freebsd.
+ * TODO: In future, when freebsd can recognize loff_t, probably revisit this
+ * and change the off_in and off_out to (loff_t *).
+ */
+ssize_t
+sys_copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out,
+ size_t len, unsigned int flags);
+
#endif /* __SYSCALL_H__ */
diff --git a/libglusterfs/src/glusterfs/xlator.h b/libglusterfs/src/glusterfs/xlator.h
index 4137d12eb27..12d507bc021 100644
--- a/libglusterfs/src/glusterfs/xlator.h
+++ b/libglusterfs/src/glusterfs/xlator.h
@@ -23,6 +23,7 @@
#include "glusterfs/list.h"
#include "glusterfs/latency.h"
#include "glusterfs/compat-uuid.h"
+#include "glusterfs/syscall.h"
#define FIRST_CHILD(xl) (xl->children->xlator)
#define SECOND_CHILD(xl) (xl->children->next->xlator)
@@ -354,6 +355,11 @@ typedef int32_t (*fop_namelink_cbk_t)(call_frame_t *frame, void *cookie,
int32_t op_errno, struct iatt *prebuf,
struct iatt *postbuf, dict_t *xdata);
+typedef int32_t (*fop_copy_file_range_cbk_t)(
+ call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
+ int32_t op_errno, struct iatt *stbuf, struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst, dict_t *xdata);
+
typedef int32_t (*fop_lookup_t)(call_frame_t *frame, xlator_t *this, loc_t *loc,
dict_t *xdata);
@@ -544,6 +550,11 @@ typedef int32_t (*fop_icreate_t)(call_frame_t *frame, xlator_t *this,
typedef int32_t (*fop_namelink_t)(call_frame_t *frame, xlator_t *this,
loc_t *loc, dict_t *xdata);
+typedef int32_t (*fop_copy_file_range_t)(call_frame_t *frame, xlator_t *this,
+ fd_t *fd_in, off64_t off_in,
+ fd_t *fd_out, off64_t off_out,
+ size_t len, uint32_t flags,
+ dict_t *xdata);
/* WARNING: make sure the list is in order with FOP definition in
`rpc/xdr/src/glusterfs-fops.x`.
@@ -609,6 +620,7 @@ struct xlator_fops {
fop_put_t put;
fop_icreate_t icreate;
fop_namelink_t namelink;
+ fop_copy_file_range_t copy_file_range;
/* these entries are used for a typechecking hack in STACK_WIND _only_ */
/* make sure to add _cbk variables only after defining regular fops as
@@ -673,6 +685,7 @@ struct xlator_fops {
fop_put_cbk_t put_cbk;
fop_icreate_cbk_t icreate_cbk;
fop_namelink_cbk_t namelink_cbk;
+ fop_copy_file_range_cbk_t copy_file_range_cbk;
};
typedef int32_t (*cbk_forget_t)(xlator_t *this, inode_t *inode);
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
index baf44de64ad..6ca6a639456 100644
--- a/libglusterfs/src/libglusterfs.sym
+++ b/libglusterfs/src/libglusterfs.sym
@@ -92,6 +92,8 @@ args_xattrop_cbk_store
args_xattrop_store
args_zerofill_cbk_store
args_zerofill_store
+args_copy_file_range_cbk_store
+args_copy_file_range_store
bin_to_data
call_resume
call_resume_keep_stub
@@ -351,6 +353,10 @@ default_put
default_put_cbk
default_put_failure_cbk
default_put_resume
+default_copy_file_range
+default_copy_file_range_cbk
+default_copy_file_range_failure_cbk
+default_copy_file_range_resume
__dentry_grep
dht_is_linkfile
dict_add
@@ -471,6 +477,8 @@ fd_unref
_fini
fop_access_stub
fop_create_stub
+fop_copy_file_range_stub
+fop_copy_file_range_cbk_stub
fop_discard_stub
fop_entrylk_stub
fop_enum_to_pri_string
@@ -933,6 +941,7 @@ synclock_unlock
syncop_access
syncop_close
syncop_create
+syncop_copy_file_range
syncopctx_getctx
syncopctx_setfsgid
syncopctx_setfsgroups
@@ -1006,6 +1015,7 @@ sys_chmod
sys_chown
sys_close
sys_closedir
+sys_copy_file_range
sys_creat
sys_fallocate
sys_fchmod
diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c
index b70953725ce..bf70daf95c3 100644
--- a/libglusterfs/src/syncop.c
+++ b/libglusterfs/src/syncop.c
@@ -3397,4 +3397,65 @@ syncop_namelink_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
__wake(args);
return 0;
-} \ No newline at end of file
+}
+
+int
+syncop_copy_file_range(xlator_t *subvol, fd_t *fd_in, off64_t off_in,
+ fd_t *fd_out, off64_t off_out, size_t len,
+ uint32_t flags, struct iatt *stbuf,
+ struct iatt *preiatt_dst, struct iatt *postiatt_dst,
+ dict_t *xdata_in, dict_t **xdata_out)
+{
+ struct syncargs args = {
+ 0,
+ };
+
+ SYNCOP(subvol, (&args), syncop_copy_file_range_cbk,
+ subvol->fops->copy_file_range, fd_in, off_in, fd_out, off_out, len,
+ flags, xdata_in);
+
+ if (stbuf) {
+ *stbuf = args.iatt1;
+ }
+ if (preiatt_dst) {
+ *preiatt_dst = args.iatt2;
+ }
+ if (postiatt_dst) {
+ *postiatt_dst = args.iatt3;
+ }
+
+ if (xdata_out) {
+ *xdata_out = args.xdata;
+ } else if (args.xdata) {
+ dict_unref(args.xdata);