diff options
author | Raghavendra Bhat <raghavendra@redhat.com> | 2018-11-06 15:27:31 -0500 |
---|---|---|
committer | Amar Tumballi <amarts@redhat.com> | 2018-12-12 15:56:55 +0000 |
commit | 7dadea15c58eb92e5f5727190bf9446dd6fe7a3c (patch) | |
tree | 4ced04de0219407604f30b1663b586f16b54dd06 /libglusterfs | |
parent | 5c723ade196600030ee84621384cceb10fff64d8 (diff) |
copy_file_range support in GlusterFS
* libglusterfs changes to add new fop
* Fuse changes:
- Changes in fuse bridge xlator to receive and send responses
* posix changes to perform the op on the backend filesystem
* protocol and rpc changes for sending and receiving the fop
* gfapi changes for performing the fop
* tools: glfs-copy-file-range tool for testing copy_file_range fop
- Although, copy_file_range support has been added to the upstream
fuse kernel module, no release has been made yet of a kernel
which contains the support. It is expected to come in the
upcoming release of linux-4.20
So, as of now, executing copy_file_range fop on a fused based
filesystem results in fuse kernel module sending read on the
source fd and write on the destination fd.
Therefore a small gfapi based tool has been written to be able
test the copy_file_range fop. This tool is similar (in functionality)
to the example program given in copy_file_range man page.
So, running regular copy_file_range on a fuse mount point and
running gfapi based glfs-copy-file-range tool gives some idea about
how fast, the copy_file_range (or reflink) can be.
On the local machine this was the result obtained.
mount -t glusterfs workstation:new /mnt/glusterfs
[root@workstation ~]# cd /mnt/glusterfs/
[root@workstation glusterfs]# ls
file
[root@workstation glusterfs]# cd
[root@workstation ~]# time /tmp/a.out /mnt/glusterfs/file /mnt/glusterfs/new
real 0m6.495s
user 0m0.000s
sys 0m1.439s
[root@workstation ~]# time glfs-copy-file-range $(hostname) new /tmp/glfs.log /file /rrr
OPEN_SRC: opening /file is success
OPEN_DST: opening /rrr is success
FSTAT_SRC: fstat on /rrr is success
copy_file_range successful
real 0m0.309s
user 0m0.039s
sys 0m0.017s
This tool needs following arguments
1) hostname
2) volume name
3) log file path
4) source file path (relative to the gluster volume root)
5) destination file path (relative to the gluster volume root)
"glfs-copy-file-range <hostname> <volume> <log file path> <source> <destination>"
- Added a testcase as well to run glfs-copy-file-range tool
* io-stats changes to capture the fop for profiling
* NOTE:
- Added conditional check to see whether the copy_file_range syscall
is available or not. If not, then return ENOSYS.
- Added conditional check for kernel minor version in fuse_kernel.h
and fuse-bridge while referring to copy_file_range. And the kernel
minor version is kept as it is. i.e. 24. Increment it in future
when there is a kernel release which contains the support for
copy_file_range fop in fuse kernel module.
* The document which contains a writeup on this enhancement can be found at
https://docs.google.com/document/d/1BSILbXr_knynNwxSyyu503JoTz5QFM_4suNIh2WwrSc/edit
Change-Id: I280069c814dd21ce6ec3be00a884fc24ab692367
updates: #536
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Diffstat (limited to 'libglusterfs')
-rw-r--r-- | libglusterfs/src/Makefile.am | 2 | ||||
-rw-r--r-- | libglusterfs/src/call-stub.c | 58 | ||||
-rw-r--r-- | libglusterfs/src/default-args.c | 42 | ||||
-rw-r--r-- | libglusterfs/src/defaults-tmpl.c | 1 | ||||
-rwxr-xr-x | libglusterfs/src/generator.py | 13 | ||||
-rw-r--r-- | libglusterfs/src/globals.c | 1 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/call-stub.h | 14 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/compat.h | 19 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/default-args.h | 11 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/defaults.h | 42 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/syncop.h | 24 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/syscall.h | 29 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs/xlator.h | 13 | ||||
-rw-r--r-- | libglusterfs/src/libglusterfs.sym | 10 | ||||
-rw-r--r-- | libglusterfs/src/syncop.c | 63 | ||||
-rw-r--r-- | libglusterfs/src/syscall.c | 32 | ||||
-rw-r--r-- | libglusterfs/src/xlator.c | 1 |
17 files changed, 369 insertions, 6 deletions
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); + } + + errno = args.op_errno; + return args.op_ret; +} + +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) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret >= 0) { + args->iatt1 = *stbuf; + args->iatt2 = *prebuf_dst; + args->iatt3 = *postbuf_dst; + } + + __wake(args); + + return 0; +} diff --git a/libglusterfs/src/syscall.c b/libglusterfs/src/syscall.c index c72a8e16b34..1d88c8adac1 100644 --- a/libglusterfs/src/syscall.c +++ b/libglusterfs/src/syscall.c @@ -8,8 +8,8 @@ cases as published by the Free Software Foundation. */ -#include "glusterfs/syscall.h" #include "glusterfs/compat.h" +#include "glusterfs/syscall.h" #include "glusterfs/mem-pool.h" #include "glusterfs/libglusterfs-messages.h" @@ -19,6 +19,9 @@ #include <fcntl.h> #include <unistd.h> #include <stdarg.h> +#ifdef HAVE_COPY_FILE_RANGE_SYS +#include <sys/syscall.h> +#endif #define FS_ERROR_LOG(result) \ do { \ @@ -802,3 +805,30 @@ err: #endif return newsock; } + +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) +{ + /* + * TODO: Add check for other platofrms like freebsd etc if this syscall is + * not generic. + * This is what the function does. + * 1) Check whether copy_file_range API is present. If so call it. + * 2) If copy_file_range API is not present, then check whether + * the system call is there. If so, then use syscall to invoke + * SYS_copy_file_range system call. + * 3) If neither of the above is present, then return ENOSYS. + */ +#ifdef HAVE_COPY_FILE_RANGE + return FS_RET_CHECK( + copy_file_range(fd_in, off_in, fd_out, off_out, len, flags), errno); +#else +#ifdef HAVE_COPY_FILE_RANGE_SYS + return syscall(SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, + flags); +#else + return -ENOSYS; +#endif /* HAVE_COPY_FILE_RANGE_SYS */ +#endif /* HAVE_COPY_FILE_RANGE */ +} diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 1b7c9d46f88..b50848b3476 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -143,6 +143,7 @@ fill_defaults(xlator_t *xl) SET_DEFAULT_FOP(getspec); SET_DEFAULT_FOP(icreate); SET_DEFAULT_FOP(namelink); + SET_DEFAULT_FOP(copy_file_range); if (!xl->cbks) xl->cbks = &default_cbks; |