diff options
Diffstat (limited to 'xlators/protocol/client')
-rw-r--r-- | xlators/protocol/client/src/client-common.c | 32 | ||||
-rw-r--r-- | xlators/protocol/client/src/client-common.h | 6 | ||||
-rw-r--r-- | xlators/protocol/client/src/client-helpers.c | 28 | ||||
-rw-r--r-- | xlators/protocol/client/src/client-rpc-fops_v2.c | 141 | ||||
-rw-r--r-- | xlators/protocol/client/src/client.c | 36 | ||||
-rw-r--r-- | xlators/protocol/client/src/client.h | 22 |
6 files changed, 265 insertions, 0 deletions
diff --git a/xlators/protocol/client/src/client-common.c b/xlators/protocol/client/src/client-common.c index 7708c820918..64db98d661b 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 5214eae128e..a2043d8742a 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 849fdfca0bc..55e87b3c370 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 ca180c1db4b..8f3ee41e5c5 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 38723b43b45..c8e84f6e1b7 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 5fc75a84628..71f84f3ca89 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; |