summaryrefslogtreecommitdiffstats
path: root/xlators/protocol
diff options
context:
space:
mode:
authorRaghavendra Bhat <raghavendra@redhat.com>2018-11-06 15:27:31 -0500
committerAmar Tumballi <amarts@redhat.com>2018-12-12 15:56:55 +0000
commit7dadea15c58eb92e5f5727190bf9446dd6fe7a3c (patch)
tree4ced04de0219407604f30b1663b586f16b54dd06 /xlators/protocol
parent5c723ade196600030ee84621384cceb10fff64d8 (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 'xlators/protocol')
-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
12 files changed, 464 insertions, 7 deletions
diff --git a/xlators/protocol/client/src/client-common.c b/xlators/protocol/client/src/client-common.c
index 7708c82..64db98d 100644
--- a/xlators/protocol/client/src/client-common.c
+++ b/xlators/protocol/client/src/client-common.c
@@ -2556,6 +2556,38 @@ out:
}
int
+client_pre_copy_file_range_v2(xlator_t *this, gfx_copy_file_range_req *req,
+ fd_t *fd_in, off64_t off_in, fd_t *fd_out,
+ off64_t off_out, size_t size, int32_t flags,
+ dict_t **xdata)
+{
+ int64_t remote_fd_in = -1;
+ int64_t remote_fd_out = -1;
+ int op_errno = ESTALE;
+
+ CLIENT_GET_REMOTE_FD(this, fd_in, FALLBACK_TO_ANON_FD, remote_fd_in,
+ op_errno, out);
+
+ CLIENT_GET_REMOTE_FD(this, fd_out, FALLBACK_TO_ANON_FD, remote_fd_out,
+ op_errno, out);
+ req->size = size;
+ req->off_in = off_in;
+ req->off_out = off_out;
+ req->fd_in = remote_fd_in;
+ req->fd_out = remote_fd_out;
+ req->flag = flags;
+
+ memcpy(req->gfid1, fd_in->inode->gfid, 16);
+ memcpy(req->gfid2, fd_out->inode->gfid, 16);
+
+ dict_to_xdr(*xdata, &req->xdata);
+
+ return 0;
+out:
+ return -op_errno;
+}
+
+int
client_pre_statfs_v2(xlator_t *this, gfx_statfs_req *req, loc_t *loc,
dict_t *xdata)
{
diff --git a/xlators/protocol/client/src/client-common.h b/xlators/protocol/client/src/client-common.h
index 5214eae..a2043d8 100644
--- a/xlators/protocol/client/src/client-common.h
+++ b/xlators/protocol/client/src/client-common.h
@@ -621,4 +621,10 @@ client_post_rename_v2(xlator_t *this, gfx_rename_rsp *rsp, struct iatt *stbuf,
struct iatt *prenewparent, struct iatt *postnewparent,
dict_t **xdata);
+int
+client_pre_copy_file_range_v2(xlator_t *this, gfx_copy_file_range_req *req,
+ fd_t *fd_in, off64_t off_in, fd_t *fd_out,
+ off64_t off_out, size_t size, int32_t flags,
+ dict_t **xdata);
+
#endif /* __CLIENT_COMMON_H__ */
diff --git a/xlators/protocol/client/src/client-helpers.c b/xlators/protocol/client/src/client-helpers.c
index 849fdfc..55e87b3 100644
--- a/xlators/protocol/client/src/client-helpers.c
+++ b/xlators/protocol/client/src/client-helpers.c
@@ -2459,6 +2459,20 @@ client_handle_fop_requirements_v2(
lease, this, &this_req->compound_req_v2_u.compound_lease_req,
op_errno, out, &args->loc, &args->lease, args->xdata);
break;
+ case GF_FOP_COPY_FILE_RANGE:
+ /*
+ * Not going to handle the copy_file_range fop in compound
+ * operation. This is because, compound operation is going
+ * to be removed. In fact, AFR one of the heavy consumer of
+ * compound operations has stopped using that.
+ * https://github.com/gluster/glusterfs/issues/414
+ * Therefore, sending ENOTSUP error for this fop coming as
+ * comound request. Though, there was no need of handling
+ * "case GF_FOP_COPY_FILE_RANGE" technically, this comment
+ * under the label of GF_FOP_COPY_FILE_RANGE will help in
+ * understanding that this fop does not handle the compund
+ * request and why.
+ */
default:
return ENOTSUP;
}
@@ -2631,6 +2645,14 @@ compound_request_cleanup_v2(gfx_compound_req *req)
case GF_FOP_SEEK:
CLIENT4_COMPOUND_FOP_CLEANUP(curr_req, seek);
break;
+ case GF_FOP_COPY_FILE_RANGE:
+ /*
+ * This fop is not handled in compund operations.
+ * Check the comment added under this fop's section
+ * in the compound_request_cleanup_v2. Therefore
+ * keeping this label only as a placeholder with
+ * a message that, this fop is not handled.
+ */
default:
break;
}
@@ -3004,6 +3026,12 @@ client_process_response_v2(call_frame_t *frame, xlator_t *this,
&this_args_cbk->lease, xdata);
break;
}
+ case GF_FOP_COPY_FILE_RANGE:
+ /*
+ * Not handling this fop. Returning ENOTSUP. Check
+ * the comment added for this fop in the function
+ * client_handle_fop_requirements_v2.
+ */
default:
return -ENOTSUP;
}
diff --git a/xlators/protocol/client/src/client-rpc-fops_v2.c b/xlators/protocol/client/src/client-rpc-fops_v2.c
index ca180c1..8f3ee41 100644
--- a/xlators/protocol/client/src/client-rpc-fops_v2.c
+++ b/xlators/protocol/client/src/client-rpc-fops_v2.c
@@ -2833,6 +2833,72 @@ out:
return 0;
}
+int
+client4_0_copy_file_range_cbk(struct rpc_req *req, struct iovec *iov, int count,
+ void *myframe)
+{
+ gfx_common_3iatt_rsp rsp = {
+ 0,
+ };
+ call_frame_t *frame = NULL;
+ struct iatt stbuf = {
+ 0,
+ };
+ struct iatt prestat = {
+ 0,
+ };
+ struct iatt poststat = {
+ 0,
+ };
+ int ret = 0;
+ xlator_t *this = NULL;
+ dict_t *xdata = NULL;
+ clnt_local_t *local = NULL;
+
+ this = THIS;
+
+ frame = myframe;
+ local = frame->local;
+
+ if (-1 == req->rpc_status) {
+ rsp.op_ret = -1;
+ rsp.op_errno = ENOTCONN;
+ goto out;
+ }
+
+ ret = xdr_to_generic(*iov, &rsp, (xdrproc_t)xdr_gfx_common_3iatt_rsp);
+ if (ret < 0) {
+ gf_msg(this->name, GF_LOG_ERROR, EINVAL, PC_MSG_XDR_DECODING_FAILED,
+ "XDR decoding failed");
+ rsp.op_ret = -1;
+ rsp.op_errno = EINVAL;
+ goto out;
+ }
+
+ ret = client_post_common_3iatt(this, &rsp, &stbuf, &prestat, &poststat,
+ &xdata);
+ if (ret < 0)
+ goto out;
+out:
+ if (rsp.op_ret == -1) {
+ gf_msg(this->name, GF_LOG_WARNING, gf_error_to_errno(rsp.op_errno),
+ PC_MSG_REMOTE_OP_FAILED, "remote operation failed");
+ } else if (rsp.op_ret >= 0) {
+ if (local->attempt_reopen)
+ client_attempt_reopen(local->fd, this);
+ if (local->attempt_reopen_out)
+ client_attempt_reopen(local->fd_out, this);
+ }
+ CLIENT_STACK_UNWIND(copy_file_range, frame, rsp.op_ret,
+ gf_error_to_errno(rsp.op_errno), &stbuf, &prestat,
+ &poststat, xdata);
+
+ if (xdata)
+ dict_unref(xdata);
+
+ return 0;
+}
+
int32_t
client4_0_releasedir(call_frame_t *frame, xlator_t *this, void *data)
{
@@ -5846,6 +5912,80 @@ unwind:
}
int32_t
+client4_0_copy_file_range(call_frame_t *frame, xlator_t *this, void *data)
+{
+ clnt_args_t *args = NULL;
+ clnt_conf_t *conf = NULL;
+ clnt_local_t *local = NULL;
+ gfx_copy_file_range_req req = {
+ {
+ 0,
+ },
+ };
+ int op_errno = ESTALE;
+ int ret = 0;
+
+ if (!frame || !this || !data)
+ goto unwind;
+
+ args = data;
+ conf = this->private;
+
+ ret = client_pre_copy_file_range_v2(this, &req, args->fd, args->off_in,
+ args->fd_out, args->off_out, args->size,
+ args->flags, &args->xdata);
+
+ if (ret) {
+ op_errno = -ret;
+ goto unwind;
+ }
+
+ ret = client_fd_fop_prepare_local(frame, args->fd, req.fd_in);
+ if (ret) {
+ op_errno = -ret;
+ goto unwind;
+ }
+
+ /*
+ * Since frame->local is allocated in above function call
+ * itself, better to use it (with the assumption that it
+ * has been allocated) directly instead of again calling
+ * client_fd_fop_prepare_local or modifying it, as doing
+ * so requires changes in other places as well.
+ */
+
+ local = frame->local;
+ local->fd_out = fd_ref(args->fd_out);
+ local->attempt_reopen_out = client_is_reopen_needed(args->fd_out, this,
+ req.fd_out);
+
+ ret = client_submit_request(
+ this, &req, frame, conf->fops, GFS3_OP_COPY_FILE_RANGE,
+ client4_0_copy_file_range_cbk, NULL, NULL, 0, NULL, 0, NULL,
+ (xdrproc_t)xdr_gfx_copy_file_range_req);
+ if (ret) {
+ /*
+ * If the lower layers fail to submit a request, they'll also
+ * do the unwind for us (see rpc_clnt_submit), so don't unwind
+ * here in such cases.
+ */
+ gf_msg(this->name, GF_LOG_WARNING, 0, PC_MSG_FOP_SEND_FAILED,
+ "failed to send the fop");
+ }
+
+ GF_FREE(req.xdata.pairs.pairs_val);
+
+ return 0;
+
+unwind:
+ CLIENT_STACK_UNWIND(copy_file_range, frame, -1, op_errno, NULL, NULL, NULL,
+ NULL);
+ GF_FREE(req.xdata.pairs.pairs_val);
+
+ return 0;
+}
+
+int32_t
client4_0_fsetattr(call_frame_t *frame, xlator_t *this, void *data)
{
clnt_args_t *args = NULL;
@@ -6257,6 +6397,7 @@ rpc_clnt_procedure_t clnt4_0_fop_actors[GF_FOP_MAXVALUE] = {
[GF_FOP_COMPOUND] = {"COMPOUND", client4_0_compound},
[GF_FOP_ICREATE] = {"ICREATE", client4_0_icreate},
[GF_FOP_NAMELINK] = {"NAMELINK", client4_0_namelink},
+ [GF_FOP_COPY_FILE_RANGE] = {"COPY-FILE-RANGE", client4_0_copy_file_range},
};
rpc_clnt_prog_t clnt4_0_fop_prog = {
diff --git a/xlators/protocol/client/src/client.c b/xlators/protocol/client/src/client.c
index 38723b4..c8e84f6 100644
--- a/xlators/protocol/client/src/client.c
+++ b/xlators/protocol/client/src/client.c
@@ -1129,6 +1129,41 @@ out:
return 0;
}
+int32_t
+client_copy_file_range(call_frame_t *frame, xlator_t *this, fd_t *fd_in,
+ off_t off_in, fd_t *fd_out, off_t off_out, size_t len,
+ uint32_t flags, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ args.fd = fd_in;
+ args.fd_out = fd_out;
+ args.offset = off_in;
+ args.off_out = off_out;
+ args.size = len;
+ args.flags = flags;
+ args.xdata = xdata;
+
+ proc = &conf->fops->proctable[GF_FOP_COPY_FILE_RANGE];
+ if (proc->fn)
+ ret = proc->fn(frame, this, &args);
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(copy_file_range, frame, -1, ENOTCONN, NULL, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
static gf_boolean_t
is_client_rpc_init_command(dict_t *dict, xlator_t *this, char **value)
{
@@ -2898,6 +2933,7 @@ struct xlator_fops fops = {
.icreate = client_icreate,
.namelink = client_namelink,
.put = client_put,
+ .copy_file_range = client_copy_file_range,
};
struct xlator_dumpops dumpops = {
diff --git a/xlators/protocol/client/src/client.h b/xlators/protocol/client/src/client.h
index 5fc75a8..71f84f3 100644
--- a/xlators/protocol/client/src/client.h
+++ b/xlators/protocol/client/src/client.h
@@ -269,6 +269,7 @@ typedef struct client_local {
loc_t loc;
loc_t loc2;
fd_t *fd;
+ fd_t *fd_out; /* used in copy_file_range */
clnt_fd_ctx_t *fdctx;
uint32_t flags;
struct iobref *iobref;
@@ -280,6 +281,11 @@ typedef struct client_local {
pthread_mutex_t mutex;
char *name;
gf_boolean_t attempt_reopen;
+ /*
+ * The below boolean variable is used
+ * only for copy_file_range fop
+ */
+ gf_boolean_t attempt_reopen_out;
/* required for compound fops */
compound_args_t *compound_args;
unsigned int length; /* length of a compound fop */
@@ -289,7 +295,13 @@ typedef struct client_local {
typedef struct client_args {
loc_t *loc;
+ /*
+ * This is the source fd for copy_file_range and
+ * the default fd for any other fd based fop which
+ * requires only one fd (i.e. opetates on one fd)
+ */
fd_t *fd;
+ fd_t *fd_out; /* this is the destination fd for copy_file_range */
const char *linkname;
struct iobref *iobref;
struct iovec *vector;
@@ -301,7 +313,17 @@ typedef struct client_args {
struct gf_flock *flock;
const char *volume;
const char *basename;
+
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; /* used in copy_file_range for source fd */
+ off64_t off_out; /* used in copy_file_range for dst fd */
int32_t mask;
int32_t cmd;
size_t size;
diff --git a/xlators/protocol/server/src/server-common.c b/xlators/protocol/server/src/server-common.c
index 25b3615..0639ac3 100644
--- a/xlators/protocol/server/src/server-common.c
+++ b/xlators/protocol/server/src/server-common.c
@@ -541,6 +541,16 @@ server4_post_common_3iatt(server_state_t *state, gfx_common_3iatt_rsp *rsp,
}
void
+server4_post_common_3iatt_noinode(gfx_common_3iatt_rsp *rsp, struct iatt *stbuf,
+ struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst)
+{
+ gfx_stat_from_iattx(&rsp->stat, stbuf);
+ gfx_stat_from_iattx(&rsp->preparent, prebuf_dst);
+ gfx_stat_from_iattx(&rsp->postparent, postbuf_dst);
+}
+
+void
server4_post_common_2iatt(gfx_common_2iatt_rsp *rsp, struct iatt *prebuf,
struct iatt *postbuf)
{
diff --git a/xlators/protocol/server/src/server-common.h b/xlators/protocol/server/src/server-common.h
index 2844ee9..6200415 100644
--- a/xlators/protocol/server/src/server-common.h
+++ b/xlators/protocol/server/src/server-common.h
@@ -192,3 +192,8 @@ void
server4_post_link(server_state_t *state, gfx_common_3iatt_rsp *rsp,
inode_t *inode, struct iatt *stbuf, struct iatt *pre,
struct iatt *post);
+
+void
+server4_post_common_3iatt_noinode(gfx_common_3iatt_rsp *rsp, struct iatt *stbuf,
+ struct iatt *prebuf_dst,
+ struct iatt *postbuf_dst);
diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c
index c55a422..8ad2d84 100644
--- a/xlators/protocol/server/src/server-helpers.c
+++ b/xlators/protocol/server/src/server-helpers.c
@@ -4948,6 +4948,8 @@ server_populate_compound_response_v2(xlator_t *this, gfx_compound_rsp *rsp,
rsp_args->op_errno = gf_errno_to_error(this_args_cbk->op_errno);
break;
}
+ case GF_FOP_COPY_FILE_RANGE:
+ /* Not handling this fop. */
default:
return ENOTSUP;
}
@@ -5380,6 +5382,12 @@ server_get_compound_resolve_v2(server_state_t *state, gfx_compound_req *req)
memcpy(state->resolve.gfid, this_req.gfid, 16);
break;
}
+ case GF_FOP_COPY_FILE_RANGE:
+ /*
+ * Compound operations is not being used anymore and
+ * planned for subsequent removal. Hence not handling
+ * this fop here.
+ */
default:
return ENOTSUP;
}
diff --git a/xlators/protocol/server/src/server-resolve.c b/xlators/protocol/server/src/server-resolve.c
index 26260a5..ec768ac 100644
--- a/xlators/protocol/server/src/server-resolve.c
+++ b/xlators/protocol/server/src/server-resolve.c
@@ -545,14 +545,39 @@ server_resolve_fd(call_frame_t *frame)
return 0;
}
- state->fd = gf_fd_fdptr_get(serv_ctx->fdtable, fd_no);
-
+ /*
+ * With copy_file_range, there will be 2 fds to resolve.
+ * This same function is called to resolve both the source
+ * fd and the destination fd. As of now, this function does
+ * not have any mechanism to distinguish between the 2 fds
+ * being resolved except for checking the value of state->fd.
+ * The assumption is that, if source fd the one which is
+ * being resolved here, then state->fd would be NULL. If it
+ * is not NULL, then it is the destination fd which is being
+ * resolved.
+ * This method (provided the above assumption is true) is
+ * to achieve the ability to distinguish between 2 fds with
+ * minimum changes being done to this function. If this way
+ * is not correct, then more changes might be needed.
+ */
if (!state->fd) {
- gf_msg("", GF_LOG_INFO, EBADF, PS_MSG_FD_NOT_FOUND,
- "fd not "
- "found in context");
- resolve->op_ret = -1;
- resolve->op_errno = EBADF;
+ state->fd = gf_fd_fdptr_get(serv_ctx->fdtable, fd_no);
+ if (!state->fd) {
+ gf_msg("", GF_LOG_INFO, EBADF, PS_MSG_FD_NOT_FOUND,
+ "fd not "
+ "found in context");
+ resolve->op_ret = -1;
+ resolve->op_errno = EBADF;
+ }
+ } else {
+ state->fd_out = gf_fd_fdptr_get(serv_ctx->fdtable, fd_no);
+ if (!state->fd_out) {
+ gf_msg("", GF_LOG_INFO, EBADF, PS_MSG_FD_NOT_FOUND,
+ "fd not "
+ "found in context");
+ resolve->op_ret = -1;
+ resolve->op_errno = EBADF;
+ }
}
server_resolve_all(frame);
diff --git a/xlators/protocol/server/src/server-rpc-fops_v2.c b/xlators/protocol/server/src/server-rpc-fops_v2.c
index c5a8e48..1657029 100644
--- a/xlators/protocol/server/src/server-rpc-fops_v2.c
+++ b/xlators/protocol/server/src/server-rpc-fops_v2.c
@@ -2259,6 +2259,64 @@ out:
return 0;
}
+int
+server4_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)
+{
+ gfx_common_3iatt_rsp rsp = {
+ 0,
+ };
+ server_state_t *state = NULL;
+ rpcsvc_request_t *req = NULL;
+ char in_gfid[GF_UUID_BUF_SIZE] = {0};
+ char out_gfid[GF_UUID_BUF_SIZE] = {0};
+
+ dict_to_xdr(xdata, &rsp.xdata);
+
+ if (op_ret < 0) {
+ state = CALL_STATE(frame);
+
+ uuid_utoa_r(state->resolve.gfid, in_gfid);
+ uuid_utoa_r(state->resolve2.gfid, out_gfid);
+
+ gf_msg(this->name, fop_log_level(GF_FOP_COPY_FILE_RANGE, op_errno),
+ op_errno, PS_MSG_WRITE_INFO,
+ "%" PRId64 ": COPY_FILE_RANGE %" PRId64 " (%s), %" PRId64
+ " (%s) client: %s, "
+ "error-xlator: %s",
+ frame->root->unique, state->resolve.fd_no, in_gfid,
+ state->resolve2.fd_no, out_gfid, STACK_CLIENT_NAME(frame->root),
+ STACK_ERR_XL_NAME(frame->root));
+ goto out;
+ }
+
+ /*
+ * server4_post_common_3iatt (ex: used by server4_put_cbk and some
+ * other cbks) also performs inode linking along with copying of 3
+ * iatt structures to the response. But, for copy_file_range, linking
+ * of inode is not needed. Therefore a new function is used to
+ * construct the response using 3 iatt structures.
+ * @stbuf: iatt or stat of the source file (or fd)
+ * @prebuf_dst: iatt or stat of destination file (or fd) before the fop
+ * @postbuf_dst: iatt or stat of destination file (or fd) after the fop
+ */
+ server4_post_common_3iatt_noinode(&rsp, stbuf, prebuf_dst, postbuf_dst);
+
+out:
+ rsp.op_ret = op_ret;
+ rsp.op_errno = gf_errno_to_error(op_errno);
+
+ req = frame->local;
+ server_submit_reply(frame, req, &rsp, NULL, 0, NULL,
+ (xdrproc_t)xdr_gfx_common_3iatt_rsp);
+
+ GF_FREE(rsp.xdata.pairs.pairs_val);
+
+ return 0;
+}
+
/* Resume function section */
int
@@ -3448,6 +3506,29 @@ err:
}
int
+server4_copy_file_range_resume(call_frame_t *frame, xlator_t *bound_xl)
+{
+ server_state_t *state = NULL;
+
+ state = CALL_STATE(frame);
+
+ if (state->resolve.op_ret != 0)
+ goto err;
+
+ STACK_WIND(frame, server4_copy_file_range_cbk, bound_xl,
+ bound_xl->fops->copy_file_range, state->fd, state->off_in,
+ state->fd_out, state->off_out, state->size, state->flags,
+ state->xdata);
+
+ return 0;
+err:
+ server4_copy_file_range_cbk(frame, NULL, frame->this, state->resolve.op_ret,
+ state->resolve.op_errno, NULL, NULL, NULL,
+ NULL);
+ return 0;
+}
+
+int
server4_0_stat(rpcsvc_request_t *req)
{
server_state_t *state = NULL;
@@ -6104,6 +6185,53 @@ out:
return ret;
}
+int
+server4_0_copy_file_range(rpcsvc_request_t *req)
+{
+ server_state_t *state = NULL;
+ call_frame_t *frame = NULL;
+ gfx_copy_file_range_req args = {
+ {
+ 0,
+ },
+ };
+ ssize_t len = 0;
+ int ret = -1;
+ int op_errno = 0;
+
+ if (!req)
+ return ret;
+
+ ret = rpc_receive_common(req, &frame, &state, &len, &args,
+ xdr_gfx_copy_file_range_req,
+ GF_FOP_COPY_FILE_RANGE);
+ if (ret != 0) {
+ goto out;
+ }
+
+ state->resolve.type = RESOLVE_MUST;
+ state->resolve.fd_no = args.fd_in;
+ state->resolve2.type = RESOLVE_MUST; /*making this resolve must */
+ state->resolve2.fd_no = args.fd_out;
+ state->off_in = args.off_in;
+ state->off_out = args.off_out;
+ state->size = args.size;
+ state->flags = args.flag;
+ memcpy(state->resolve.gfid, args.gfid1, 16);
+ memcpy(state->resolve2.gfid, args.gfid2, 16);
+
+ xdr_to_dict(&args.xdata, &state->xdata);
+
+ ret = 0;
+ resolve_and_resume(frame, server4_copy_file_range_resume);
+out:
+
+ if (op_errno)
+ SERVER_REQ_SET_ERROR(req, ret);
+
+ return ret;
+}
+
rpcsvc_actor_t glusterfs4_0_fop_actors[] = {
[GFS3_OP_NULL] = {"NULL", GFS3_OP_NULL, server_null, NULL, 0},
[GFS3_OP_STAT] = {"STAT", GFS3_OP_STAT, server4_0_stat, NULL, 0},
@@ -6195,6 +6323,8 @@ rpcsvc_actor_t glusterfs4_0_fop_actors[] = {
DRC_NA},
[GFS3_OP_NAMELINK] = {"NAMELINK", GFS3_OP_NAMELINK, server4_0_namelink,
NULL, 0, DRC_NA},
+ [GFS3_OP_COPY_FILE_RANGE] = {"COPY-FILE-RANGE", GFS3_OP_COPY_FILE_RANGE,
+ server4_0_copy_file_range, NULL, 0, DRC_NA},
};
struct rpcsvc_program glusterfs4_0_fop_prog = {
diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h
index 2a77aba..bdf98c9 100644
--- a/xlators/protocol/server/src/server.h
+++ b/xlators/protocol/server/src/server.h
@@ -180,7 +180,12 @@ struct _server_state {
struct iatt stbuf;
int valid;
+ /*
+ * this fd is used in all the fd based operations PLUS
+ * as a source fd in copy_file_range
+ */
fd_t *fd;
+ fd_t *fd_out; /* destination fd in copy_file_range */
dict_t *params;
int32_t flags;
int wbflags;
@@ -191,6 +196,15 @@ struct _server_state {
size_t size;
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; /* source offset in copy_file_range */
+ off64_t off_out; /* destination offset in copy_file_range */
mode_t mode;
dev_t dev;
size_t nr_count;