NFSD support for async COPY
Subsystems (2)
v9 cover NFSD support for async COPY
From: Olga Kornievskaia <[email protected]>
To do asynchronous copies, NFSD creates a new kthread to handle the request. Upon receiving the COPY, it generates a unique copy stateid (stored in a global list for keeping track of state for OFFLOAD_STATUS to be queried by), starts the thread, and replies back to the client. nfsd4_copy arguments that are allocated on the stack are copies for the kthread.
For the async copy handler, copy is done in the loop for the requested number of bytes. If an error is encountered and partial copy has happened, a successful partial copy is returned in the CB_OFFLOAD. vfs_copy_file_range is called with 4MB chunks for both async and sync, allowing for 4MB granularity of OFFLOAD_STATUS queiry. Once copy is done, the results are queued for the callback workqueue and sent via CB_OFFLOAD.
When the server received an OFFLOAD_CANCEL, it will find the kthread running the copy and will send a SIGPENDING and kthread_stop() and it will interrupt the ongoing do_splice() and once vfs returns we are choosing not to send the CB_OFFLOAD back to the client.
When the server receives an OFFLOAD_STATUS, it will find the kthread running the copy and will locate within the copy state the current number of bytes copied so far.
v9:
-- added module parameter (async_copy_offload_enable) to turns on async copy processing on the server
-- fixes some kbuild errors from the previous submission
Olga Kornievskaia (9):
NFSD CB_OFFLOAD xdr
NFSD OFFLOAD_STATUS xdr
NFSD OFFLOAD_CANCEL xdr
NFSD xdr callback stateid in async COPY reply NFSD introduce async copy feature
NFSD create new stateid for async copy NFSD handle OFFLOAD_CANCEL op
NFSD support OFFLOAD_STATUS
NFSD stop ongoing async copies on client shutdown
fs/nfsd/netns.h | 8 ++ fs/nfsd/nfs4callback.c | 98 +++++++++++++++++ fs/nfsd/nfs4proc.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/nfsd/nfs4state.c | 38 ++++++- fs/nfsd/nfs4xdr.c | 50 +++++++-- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfssvc.c | 6 + fs/nfsd/state.h | 10 ++ fs/nfsd/xdr4.h | 29 +++++ fs/nfsd/xdr4cb.h | 10 ++ 10 files changed, 517 insertions(+), 24 deletions(-)
Signature · 1 line
1.8.3.1
PATCH v9 1/9 NFSD CB_OFFLOAD xdr
--- fs/nfsd/nfs4callback.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/state.h | 1 + fs/nfsd/xdr4.h | 6 ++++ fs/nfsd/xdr4cb.h | 10 ++++++ 4 files changed, 115 insertions(+)
fs/nfsd/nfs4callback.c +98 -0
@@ -39,6 +39,7 @@#include "state.h" #include "netns.h" #include "xdr4cb.h" +#include "xdr4.h" #define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -105,6 +106,7 @@ enum nfs_cb_opnum4 {OP_CB_WANTS_CANCELLED =12 ,OP_CB_NOTIFY_LOCK =13 ,OP_CB_NOTIFY_DEVICEID =14 , +OP_CB_OFFLOAD =15 , OP_CB_ILLEGAL = 10044 };
@@ -683,6 +685,101 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp, }/* +* struct write_response4 { +* stateid4 wr_callback_id<1>; +* length4 wr_count; +* stable_how4 wr_committed; +* verifier4 wr_writeverf; +* }; +* union offload_info4 switch (nfsstat4 coa_status) { +* case NFS4_OK: +* write_response4 coa_resok4; +* default: +* length4 coa_bytes_copied; +* }; +* struct CB_OFFLOAD4args { +* nfs_fh4 coa_fh; +* stateid4 coa_stateid; +* offload_info4 coa_offload_info; +* }; +*/ +static void encode_offload_info4 (struct xdr_stream *xdr, +__be32 nfserr, +const struct nfsd4_copy *cp) +{ +__be32 *p; + + p =xdr_reserve_space (xdr,4 ); + *p++ = nfserr; +if (!nfserr) { + p =xdr_reserve_space (xdr,4 +8 +4 +NFS4_VERIFIER_SIZE ); + p =xdr_encode_empty_array (p); + p =xdr_encode_hyper (p, cp->cp_res.wr_bytes_written); + *p++ =cpu_to_be32 (cp->cp_res.wr_stable_how); + p =xdr_encode_opaque_fixed (p, cp->cp_res.wr_verifier.data, +NFS4_VERIFIER_SIZE ); + }else { + p =xdr_reserve_space (xdr,8 ); +/* We always return success if bytes were written */ + p =xdr_encode_hyper (p,0 ); + } +} + +static void encode_cb_offload4args (struct xdr_stream *xdr, +__be32 nfserr, +const struct knfsd_fh *fh, +const struct nfsd4_copy *cp, +struct nfs4_cb_compound_hdr *hdr) +{ +__be32 *p; + + p =xdr_reserve_space (xdr,4 ); + *p++ =cpu_to_be32 (OP_CB_OFFLOAD ); +encode_nfs_fh4 (xdr, fh); +encode_stateid4 (xdr, &cp->cp_res.cb_stateid); +encode_offload_info4 (xdr, nfserr, cp); + + hdr->nops++; +} + +static void nfs4_xdr_enc_cb_offload (struct rpc_rqst *req, +struct xdr_stream *xdr, +const void *data) +{ +const struct nfsd4_callback *cb = data; +const struct nfsd4_copy *cp = + container_of(cb, struct nfsd4_copy, cp_cb); +struct nfs4_cb_compound_hdr hdr = { + .ident =0 , + .minorversion = cb->cb_clp->cl_minorversion, + }; + +encode_cb_compound4args (xdr, &hdr); +encode_cb_sequence4args (xdr, cb, &hdr); +encode_cb_offload4args (xdr, cp->nfserr, &cp->fh, cp, &hdr); +encode_cb_nops (&hdr); +} + +static int nfs4_xdr_dec_cb_offload (struct rpc_rqst *rqstp, +struct xdr_stream *xdr, +void *data) +{ +struct nfsd4_callback *cb = data; +struct nfs4_cb_compound_hdr hdr; +int status; + + status =decode_cb_compound4res (xdr, &hdr); +if (unlikely (status)) +return status; + +if (cb) { + status =decode_cb_sequence4res (xdr, cb); +if (unlikely (status || cb->cb_seq_status)) +return status; + } +return decode_cb_op_status (xdr,OP_CB_OFFLOAD , &cb->cb_status); +} +/* * RPC procedure tables */ #define PROC (proc, call, argtype, restype) \
@@ -703,6 +800,7 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp,PROC (CB_LAYOUT ,COMPOUND , cb_layout, cb_layout), #endifPROC (CB_NOTIFY_LOCK ,COMPOUND , cb_notify_lock, cb_notify_lock), + PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload), };static unsigned int nfs4_cb_counts[ARRAY_SIZE (nfs4_cb_procedures)];
fs/nfsd/state.h +1 -0
@@ -573,6 +573,7 @@ enum nfsd4_cb_op {NFSPROC4_CLNT_CB_NULL =0 ,NFSPROC4_CLNT_CB_RECALL ,NFSPROC4_CLNT_CB_LAYOUT , +NFSPROC4_CLNT_CB_OFFLOAD ,NFSPROC4_CLNT_CB_SEQUENCE , NFSPROC4_CLNT_CB_NOTIFY_LOCK, };
fs/nfsd/xdr4.h +6 -0
@@ -511,6 +511,7 @@ struct nfsd42_write_res {u64 wr_bytes_written;u32 wr_stable_how;nfs4_verifier wr_verifier; +stateid_t cb_stateid; };struct nfsd4_copy {
@@ -526,6 +527,11 @@ struct nfsd4_copy {/* response */ struct nfsd42_write_res cp_res; + +/* for cb_offload */ +struct nfsd4_callback cp_cb; +__be32 nfserr; +struct knfsd_fh fh; };struct nfsd4_seek {
fs/nfsd/xdr4cb.h +10 -0
@@ -38,3 +38,13 @@#define NFS4_dec_cb_notify_lock_sz (cb_compound_dec_hdr_sz + \ cb_sequence_dec_sz + \ op_dec_sz) +#define enc_cb_offload_info_sz (1 + 1 + 2 + 1 + \ + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) +#define NFS4_enc_cb_offload_sz (cb_compound_enc_hdr_sz + \ + cb_sequence_enc_sz + \ + enc_nfs4_fh_sz + \ + enc_stateid_sz + \ + enc_cb_offload_info_sz) +#define NFS4_dec_cb_offload_sz (cb_compound_dec_hdr_sz + \ + cb_sequence_dec_sz + \ + op_dec_sz)
Signature · 1 line
1.8.3.1
PATCH v9 2/9 NFSD OFFLOAD_STATUS xdr
In reply to Olga Kornievskaia--- fs/nfsd/nfs4proc.c | 20 ++++++++++++++++++++ fs/nfsd/nfs4xdr.c | 27 +++++++++++++++++++++++++-- fs/nfsd/xdr4.h | 10 ++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-)
fs/nfsd/nfs4proc.c +20 -0
@@ -1155,6 +1155,13 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)fput (file);return status; } +static __be32 +nfsd4_offload_status (struct svc_rqst *rqstp, +struct nfsd4_compound_state *cstate, +union nfsd4_op_u *u) +{ +return nfserr_notsupp; +} static __be32 nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
@@ -2052,6 +2059,14 @@ static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) 1 /* cr_synchronous */) * sizeof(__be32); } +static inline u32 nfsd4_offload_status_rsize (struct svc_rqst *rqstp, +struct nfsd4_op *op) +{ +return (op_encode_hdr_size + +2 /* osr_count */ + +1 /* osr_complete<1> optional 0 for now */ ) *sizeof (__be32); +} +#ifdef CONFIG_NFSD_PNFS static inline u32 nfsd4_getdeviceinfo_rsize (struct svc_rqst *rqstp,struct nfsd4_op *op) {
@@ -2465,6 +2480,11 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) .op_name = "OP_SEEK", .op_rsize_bop = nfsd4_seek_rsize, }, + [OP_OFFLOAD_STATUS] = { + .op_func = nfsd4_offload_status, + .op_name = "OP_OFFLOAD_STATUS", + .op_rsize_bop = nfsd4_offload_status_rsize, + }, };/**
fs/nfsd/nfs4xdr.c +25 -2
@@ -1770,6 +1770,13 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str }static __be32 +nfsd4_decode_offload_status (struct nfsd4_compoundargs *argp, +struct nfsd4_offload_status *os) +{ +return nfsd4_decode_stateid (argp, &os->stateid); +} + +static __be32 nfsd4_decode_seek (struct nfsd4_compoundargs *argp,struct nfsd4_seek *seek) {DECODE_HEAD ;
@@ -1876,7 +1883,7 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status, [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -4226,6 +4233,22 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, }static __be32 +nfsd4_encode_offload_status (struct nfsd4_compoundres *resp,__be32 nfserr, +struct nfsd4_offload_status *os) +{ +struct xdr_stream *xdr = &resp->xdr; +__be32 *p; + + p =xdr_reserve_space (xdr,8 +4 ); +if (!p) +return nfserr_resource; + p =xdr_encode_hyper (p, os->count); + *p++ =cpu_to_be32 (0 ); + +return nfserr; +} + +static __be32 nfsd4_encode_seek (struct nfsd4_compoundres *resp,__be32 nfserr,struct nfsd4_seek *seek) {
@@ -4328,7 +4351,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop, [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, - [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_noop, + [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status, [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
fs/nfsd/xdr4.h +10 -0
@@ -545,6 +545,15 @@ struct nfsd4_seek {loff_t seek_pos; }; +struct nfsd4_offload_status { +/* request */ +stateid_t stateid; + +/* response */ +u64 count; +u32 status; +}; +struct nfsd4_op {int opnum;const struct nfsd4_operation * opdesc;
@@ -603,6 +612,7 @@ struct nfsd4_op {struct nfsd4_fallocate deallocate;struct nfsd4_clone clone;struct nfsd4_copy copy; +struct nfsd4_offload_status offload_status;struct nfsd4_seek seek; } u;struct nfs4_replay * replay;
Signature · 1 line
1.8.3.1
PATCH v9 3/9 NFSD OFFLOAD_CANCEL xdr
In reply to Olga Kornievskaia--- fs/nfsd/nfs4proc.c | 14 ++++++++++++++ fs/nfsd/nfs4xdr.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-)
fs/nfsd/nfs4proc.c +14 -0
@@ -1134,6 +1134,14 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) }static __be32 +nfsd4_offload_cancel (struct svc_rqst *rqstp, +struct nfsd4_compound_state *cstate, +union nfsd4_op_u *u) +{ +return 0 ; +} + +static __be32 nfsd4_fallocate (struct svc_rqst *rqstp,struct nfsd4_compound_state *cstate,struct nfsd4_fallocate *fallocate,int flags) {
@@ -2485,6 +2493,12 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) .op_name = "OP_OFFLOAD_STATUS", .op_rsize_bop = nfsd4_offload_status_rsize, }, + [OP_OFFLOAD_CANCEL] = { + .op_func = nfsd4_offload_cancel, + .op_flags = OP_MODIFIES_SOMETHING, + .op_name = "OP_OFFLOAD_CANCEL", + .op_rsize_bop = nfsd4_only_status_rsize, + }, };/**
fs/nfsd/nfs4xdr.c +1 -1
@@ -1882,7 +1882,7 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status, [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status, [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
Signature · 1 line
1.8.3.1
PATCH v9 4/9 NFSD xdr callback stateid in async COPY reply
In reply to Olga Kornievskaia--- fs/nfsd/nfs4xdr.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
fs/nfsd/nfs4xdr.c +17 -4
@@ -4200,15 +4200,27 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,#endif /* CONFIG_NFSD_PNFS */ static __be32 -nfsd42_encode_write_res (struct nfsd4_compoundres *resp,struct nfsd42_write_res *write) +nfsd42_encode_write_res (struct nfsd4_compoundres *resp, +struct nfsd42_write_res *write,bool sync) {__be32 *p; + p =xdr_reserve_space (&resp->xdr,4 ); +if (!p) +return nfserr_resource; - p =xdr_reserve_space (&resp->xdr,4 +8 +4 +NFS4_VERIFIER_SIZE ); +if (sync) + *p++ =cpu_to_be32 (0 ); +else { +__be32 nfserr; + *p++ =cpu_to_be32 (1 ); + nfserr =nfsd4_encode_stateid (&resp->xdr, &write->cb_stateid); +if (nfserr) +return nfserr; + } + p =xdr_reserve_space (&resp->xdr,8 +4 +NFS4_VERIFIER_SIZE );if (!p)return nfserr_resource; - *p++ =cpu_to_be32 (0 ); p =xdr_encode_hyper (p, write->wr_bytes_written); *p++ =cpu_to_be32 (write->wr_stable_how); p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
@@ -4222,7 +4234,8 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, {__be32 *p; - nfserr =nfsd42_encode_write_res (resp, ©->cp_res); + nfserr =nfsd42_encode_write_res (resp, ©->cp_res, + copy->cp_synchronous);if (nfserr)return nfserr;
Signature · 1 line
1.8.3.1
PATCH v9 5/9 NFSD introduce async copy feature
In reply to Olga KornievskaiaFrom: Olga Kornievskaia <[email protected]>
Upon receiving a request for async copy, create a new kthread. If we get asynchronous request, make sure to copy the needed arguments/state from the stack before starting the copy. Then start the thread and reply back to the client indicating copy is asynchronous.
nfsd_copy_file_range() will copy in a loop over the total number of bytes is needed to copy. In case a failure happens in the middle, we ignore the error and return how much we copied so far. Once done creating a workitem for the callback workqueue and send CB_OFFLOAD with the results.
In the following patches the unique stateid will be generated for the async COPY to return, at that point will enable the async feature.
Async copy feature is turned on by an nfsd module parameter async_copy_offload_enable.
--- fs/nfsd/nfs4proc.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++------ fs/nfsd/nfs4state.c | 2 + fs/nfsd/nfssvc.c | 6 ++ fs/nfsd/state.h | 2 + fs/nfsd/xdr4.h | 9 +++ 5 files changed, 163 insertions(+), 17 deletions(-)
fs/nfsd/nfs4proc.c +144 -17
@@ -36,6 +36,7 @@#include <linux/file.h> #include <linux/falloc.h> #include <linux/slab.h> +#include <linux/kthread.h> #include "idmap.h" #include "cache.h"
@@ -1099,38 +1100,164 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) out:return status; } +static void nfsd4_cb_offload_release (struct nfsd4_callback *cb) +{ + struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb); + +kfree (copy); +} + +static int nfsd4_cb_offload_done (struct nfsd4_callback *cb, +struct rpc_task *task) +{ +return 1 ; +} + +static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = { + .release = nfsd4_cb_offload_release, + .done = nfsd4_cb_offload_done +}; + +static __be32 nfsd4_init_copy_res (struct nfsd4_copy *copy,bool sync) +{ +memcpy (©->cp_res.cb_stateid, ©->cp_dst_stateid, +sizeof (copy->cp_dst_stateid)); + copy->cp_res.wr_stable_how =NFS_UNSTABLE ; + copy->cp_synchronous = sync; +gen_boot_verifier (©->cp_res.wr_verifier, copy->cp_clp->net); + +return nfs_ok; +} + +static ssize_t _nfsd_copy_file_range (struct nfsd4_copy *copy) +{ +ssize_t bytes_copied =0 ; +size_t bytes_total = copy->cp_count; +u64 src_pos = copy->cp_src_pos; +u64 dst_pos = copy->cp_dst_pos; + +do { + bytes_copied =nfsd_copy_file_range (copy->file_src, src_pos, + copy->file_dst, dst_pos, bytes_total); +if (bytes_copied <=0 ) +break ; + bytes_total -= bytes_copied; + copy->cp_res.wr_bytes_written += bytes_copied; + src_pos += bytes_copied; + dst_pos += bytes_copied; + }while (bytes_total >0 && !copy->cp_synchronous); +return bytes_copied; +} + +static __be32 nfsd4_do_copy (struct nfsd4_copy *copy,bool sync) +{ +__be32 status; +ssize_t bytes; + + bytes =_nfsd_copy_file_range (copy); +/* for async copy, we ignore the error, client can always retry +* to get the error +*/ +if (bytes <0 && !copy->cp_res.wr_bytes_written) + status =nfserrno (bytes); +else + status =nfsd4_init_copy_res (copy, sync); + +fput (copy->file_src); +fput (copy->file_dst); +return status; +} + +static void dup_copy_fields (struct nfsd4_copy *src,struct nfsd4_copy *dst) +{ + dst->cp_src_pos = src->cp_src_pos; + dst->cp_dst_pos = src->cp_dst_pos; + dst->cp_count = src->cp_count; + dst->cp_synchronous = src->cp_synchronous; +memcpy (&dst->cp_res, &src->cp_res,sizeof (src->cp_res)); +memcpy (&dst->fh, &src->fh,sizeof (src->fh)); + dst->cp_clp = src->cp_clp; + dst->file_dst =get_file (src->file_dst); + dst->file_src =get_file (src->file_src); +} + +static void cleanup_async_copy (struct nfsd4_copy *copy) +{ +fput (copy->file_dst); +fput (copy->file_src); +spin_lock (©->cp_clp->async_lock); +list_del (©->copies); +spin_unlock (©->cp_clp->async_lock); +kfree (copy); +} + +static int nfsd4_do_async_copy (void *data) +{ +struct nfsd4_copy *copy = (struct nfsd4_copy *)data; +struct nfsd4_copy *cb_copy; + + copy->nfserr =nfsd4_do_copy (copy,0 ); + cb_copy =kzalloc (sizeof (struct nfsd4_copy ),GFP_KERNEL ); +if (!cb_copy) + goto out; +memcpy (&cb_copy->cp_res, ©->cp_res,sizeof (copy->cp_res)); + cb_copy->cp_clp = copy->cp_clp; + cb_copy->nfserr = copy->nfserr; +memcpy (&cb_copy->fh, ©->fh,sizeof (copy->fh)); +nfsd4_init_cb (&cb_copy->cp_cb, cb_copy->cp_clp, + &nfsd4_cb_offload_ops,NFSPROC4_CLNT_CB_OFFLOAD ); +nfsd4_run_cb (&cb_copy->cp_cb); +out: +cleanup_async_copy (copy); +return 0 ; +}static __be32 nfsd4_copy (struct svc_rqst *rqstp,struct nfsd4_compound_state *cstate,union nfsd4_op_u *u) {struct nfsd4_copy *copy = &u->copy; -struct file *src, *dst;__be32 status; -ssize_t bytes; +struct nfsd4_copy *async_copy =NULL ; - status =nfsd4_verify_copy (rqstp, cstate, ©->cp_src_stateid, &src, - ©->cp_dst_stateid, &dst); + status =nfsd4_verify_copy (rqstp, cstate, ©->cp_src_stateid, + ©->file_src, ©->cp_dst_stateid, + ©->file_dst);if (status) goto out; - bytes =nfsd_copy_file_range (src, copy->cp_src_pos, - dst, copy->cp_dst_pos, copy->cp_count); - -if (bytes <0 ) - status =nfserrno (bytes); -else { - copy->cp_res.wr_bytes_written = bytes; - copy->cp_res.wr_stable_how =NFS_UNSTABLE ; - copy->cp_synchronous =1 ; -gen_boot_verifier (©->cp_res.wr_verifier,SVC_NET (rqstp)); + copy->cp_clp = cstate->clp; +memcpy (©->fh, &cstate->current_fh.fh_handle, +sizeof (struct knfsd_fh )); +/* for now disable asynchronous copy feature */ + copy->cp_synchronous =1 ; +if (!copy->cp_synchronous && async_copy_offload_enable) { + status =nfserrno (-ENOMEM ); + async_copy =kzalloc (sizeof (struct nfsd4_copy ),GFP_KERNEL ); +if (!async_copy) + goto out; +dup_copy_fields (copy, async_copy); +memcpy (©->cp_res.cb_stateid, ©->cp_dst_stateid, +sizeof (copy->cp_dst_stateid)); + async_copy->copy_task =kthread_create (nfsd4_do_async_copy, + async_copy,"%s" ,"copy thread" ); +if (IS_ERR (async_copy->copy_task)) + goto out_err; +spin_lock (&async_copy->cp_clp->async_lock); +list_add (&async_copy->copies, + &async_copy->cp_clp->async_copies); +spin_unlock (&async_copy->cp_clp->async_lock); +wake_up_process (async_copy->copy_task); status = nfs_ok; + }else { + copy->cp_synchronous =1 ; + status =nfsd4_do_copy (copy,1 ); } - -fput (src); -fput (dst); out:return status; +out_err: +cleanup_async_copy (async_copy); + goto out; } static __be32
fs/nfsd/nfs4state.c +2 -0
@@ -1827,6 +1827,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)#ifdef CONFIG_NFSD_PNFS INIT_LIST_HEAD (&clp->cl_lo_states);#endif +INIT_LIST_HEAD (&clp->async_copies); +spin_lock_init (&clp->async_lock);spin_lock_init (&clp->cl_lock);rpc_init_wait_queue (&clp->cl_cb_waitq,"Backchannel slot table" );return clp;
fs/nfsd/nfssvc.c +6 -0
@@ -30,6 +30,12 @@#define NFSDDBG_FACILITY NFSDDBG_SVC +bool async_copy_offload_enable; +EXPORT_SYMBOL_GPL (async_copy_offload_enable); +module_param (async_copy_offload_enable, bool,0644 ); +MODULE_PARM_DESC (async_copy_offload_enable, +"Enable asynch copy offload. Default: false" ); +extern struct svc_program nfsd_program;static int nfsd (void *vrqstp);
fs/nfsd/state.h +2 -0
@@ -355,6 +355,8 @@ struct nfs4_client {struct rpc_wait_queue cl_cb_waitq;/* backchannel callers may */ /* wait here for slots */ struct net *net; +struct list_head async_copies;/* list of async copies */ +spinlock_t async_lock;/* lock for async copies */ };/* struct nfs4_client_reset
fs/nfsd/xdr4.h +9 -0
@@ -532,7 +532,16 @@ struct nfsd4_copy {struct nfsd4_callback cp_cb;__be32 nfserr;struct knfsd_fh fh; + +struct nfs4_client *cp_clp; + +struct file *file_src; +struct file *file_dst; + +struct list_head copies; +struct task_struct *copy_task; }; +extern bool async_copy_offload_enable;struct nfsd4_seek {/* request */
Signature · 1 line
1.8.3.1
Re: [PATCH v9 5/9] NFSD introduce async copy feature
fs/nfsd/nfs4proc.c static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) · line 1129
Quoted 9 lines · Olga Kornievskaia
fs/nfsd/nfs4proc.c +9
-0+static __be32 nfsd4_init_copy_res (struct nfsd4_copy *copy,bool sync) +{ +memcpy (©->cp_res.cb_stateid, ©->cp_dst_stateid, +sizeof (copy->cp_dst_stateid)); + copy->cp_res.wr_stable_how =NFS_UNSTABLE ; + copy->cp_synchronous = sync; +gen_boot_verifier (©->cp_res.wr_verifier, copy->cp_clp->net); + +return nfs_ok;
Just make this return void if you're not using the error return.
--b.
PATCH v9 6/9 NFSD create new stateid for async copy
In reply to Olga KornievskaiaGenerate a new stateid to be used for reply to the asynchronous COPY. Right now deciding to bind the lifetime to when the vfs copy is done. This way don't need to keep the nfsd_net structure for the callback. The drawback is that time copy state information is available for query by OFFLOAD_STATUS is slightly less.
--- fs/nfsd/netns.h | 8 ++++++++ fs/nfsd/nfs4proc.c | 14 ++++++++------ fs/nfsd/nfs4state.c | 32 ++++++++++++++++++++++++++++++++ fs/nfsd/nfsctl.c | 1 + fs/nfsd/state.h | 3 +++ fs/nfsd/xdr4.h | 2 ++ 6 files changed, 54 insertions(+), 6 deletions(-)
fs/nfsd/netns.h +8 -0
@@ -122,6 +122,14 @@ struct nfsd_net {wait_queue_head_t ntf_wq;atomic_t ntf_refcnt; + +/* +* clientid and stateid data for construction of net unique COPY +* stateids. +*/ +u32 s2s_cp_cl_id; +struct idr s2s_cp_stateids; +spinlock_t s2s_cp_lock; };/* Simple check to find out if a given net was properly initialized */
fs/nfsd/nfs4proc.c +8 -6
@@ -1120,8 +1120,6 @@ static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,static __be32 nfsd4_init_copy_res (struct nfsd4_copy *copy,bool sync) { -memcpy (©->cp_res.cb_stateid, ©->cp_dst_stateid, -sizeof (copy->cp_dst_stateid)); copy->cp_res.wr_stable_how =NFS_UNSTABLE ; copy->cp_synchronous = sync;gen_boot_verifier (©->cp_res.wr_verifier, copy->cp_clp->net);
@@ -1179,10 +1177,12 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) dst->cp_clp = src->cp_clp; dst->file_dst =get_file (src->file_dst); dst->file_src =get_file (src->file_src); +memcpy (&dst->cp_stateid, &src->cp_stateid,sizeof (src->cp_stateid)); }static void cleanup_async_copy (struct nfsd4_copy *copy) { +nfs4_free_cp_state (copy);fput (copy->file_dst);fput (copy->file_src);spin_lock (©->cp_clp->async_lock);
@@ -1229,16 +1229,18 @@ static int nfsd4_do_async_copy(void *data) copy->cp_clp = cstate->clp;memcpy (©->fh, &cstate->current_fh.fh_handle,sizeof (struct knfsd_fh )); -/* for now disable asynchronous copy feature */ - copy->cp_synchronous =1 ;if (!copy->cp_synchronous && async_copy_offload_enable) { +struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id); + status =nfserrno (-ENOMEM ); async_copy =kzalloc (sizeof (struct nfsd4_copy ),GFP_KERNEL );if (!async_copy) goto out; +if (!nfs4_init_cp_state (nn, copy)) + goto out; +memcpy (©->cp_res.cb_stateid, ©->cp_stateid, +sizeof (copy->cp_stateid));dup_copy_fields (copy, async_copy); -memcpy (©->cp_res.cb_stateid, ©->cp_dst_stateid, -sizeof (copy->cp_dst_stateid)); async_copy->copy_task =kthread_create (nfsd4_do_async_copy, async_copy,"%s" ,"copy thread" );if (IS_ERR (async_copy->copy_task))
fs/nfsd/nfs4state.c +32 -0
@@ -713,6 +713,36 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slareturn NULL ; } +/* +* Create a unique stateid_t to represent each COPY. +*/ +int nfs4_init_cp_state (struct nfsd_net *nn,struct nfsd4_copy *copy) +{ +int new_id; + +idr_preload (GFP_KERNEL ); +spin_lock (&nn->s2s_cp_lock); + new_id =idr_alloc_cyclic (&nn->s2s_cp_stateids, copy,0 ,0 ,GFP_NOWAIT ); +spin_unlock (&nn->s2s_cp_lock); +idr_preload_end (); +if (new_id <0 ) +return 0 ; + copy->cp_stateid.si_opaque.so_id = new_id; + copy->cp_stateid.si_opaque.so_clid.cl_boot = nn->boot_time; + copy->cp_stateid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; +return 1 ; +} + +void nfs4_free_cp_state (struct nfsd4_copy *copy) +{ +struct nfsd_net *nn; + + nn =net_generic (copy->cp_clp->net, nfsd_net_id); +spin_lock (&nn->s2s_cp_lock); +idr_remove (&nn->s2s_cp_stateids, copy->cp_stateid.si_opaque.so_id); +spin_unlock (&nn->s2s_cp_lock); +} +static struct nfs4_ol_stateid *nfs4_alloc_open_stateid (struct nfs4_client *clp) {struct nfs4_stid *stid;
@@ -7131,6 +7161,8 @@ static int nfs4_state_create_net(struct net *net)INIT_LIST_HEAD (&nn->close_lru);INIT_LIST_HEAD (&nn->del_recall_lru);spin_lock_init (&nn->client_lock); +spin_lock_init (&nn->s2s_cp_lock); +idr_init (&nn->s2s_cp_stateids);spin_lock_init (&nn->blocked_locks_lock);INIT_LIST_HEAD (&nn->blocked_locks_lru);
fs/nfsd/nfsctl.c +1 -0
@@ -1241,6 +1241,7 @@ static __net_init int nfsd_init_net(struct net *net) nn->nfsd4_grace =90 ; nn->clverifier_counter =prandom_u32 (); nn->clientid_counter =prandom_u32 (); + nn->s2s_cp_cl_id = nn->clientid_counter++;atomic_set (&nn->ntf_refcnt,0 );init_waitqueue_head (&nn->ntf_wq);
fs/nfsd/state.h +3 -0
@@ -602,6 +602,7 @@ struct nfsd4_blocked_lock {struct nfsd4_compound_state ;struct nfsd_net ; +struct nfsd4_copy ; extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
@@ -611,6 +612,8 @@ __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, struct nfs4_stid **s, struct nfsd_net *nn);struct nfs4_stid *nfs4_alloc_stid (struct nfs4_client *cl,struct kmem_cache *slab,void (*sc_free)(struct nfs4_stid *)); +int nfs4_init_cp_state (struct nfsd_net *nn,struct nfsd4_copy *copy); +void nfs4_free_cp_state (struct nfsd4_copy *copy);void nfs4_unhash_stid (struct nfs4_stid *s);void nfs4_put_stid (struct nfs4_stid *s);void nfs4_inc_and_copy_stateid (stateid_t *dst,struct nfs4_stid *stid);
fs/nfsd/xdr4.h +2 -0
@@ -538,6 +538,8 @@ struct nfsd4_copy {struct file *file_src;struct file *file_dst; +stateid_t cp_stateid; +struct list_head copies;struct task_struct *copy_task; };
Signature · 1 line
1.8.3.1
PATCH v9 7/9 NFSD handle OFFLOAD_CANCEL op
In reply to Olga KornievskaiaFrom: Olga Kornievskaia <[email protected]>
Upon receiving OFFLOAD_CANCEL search the list of copy stateids, if found then set the SIGPENDING signal so that do_splice stops copying and also send kthread_stop to the copy thread to stop and wait for it. Take a reference on the copy from the offload_cancel thread so that it won't go away while we are trying to process it.
--- fs/nfsd/nfs4proc.c | 40 +++++++++++++++++++++++++++++++++++++--- fs/nfsd/state.h | 1 + fs/nfsd/xdr4.h | 1 + 3 files changed, 39 insertions(+), 3 deletions(-)
fs/nfsd/nfs4proc.c +37 -3
@@ -1100,11 +1100,19 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) out:return status; } + +void nfs4_put_copy (struct nfsd4_copy *copy) +{ +if (!refcount_dec_and_test (©->refcount)) +return ; +kfree (copy); +} +static void nfsd4_cb_offload_release (struct nfsd4_callback *cb) { struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb); -kfree (copy); +nfs4_put_copy (copy); } static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
@@ -1135,6 +1143,8 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)u64 dst_pos = copy->cp_dst_pos; do { + if (signalled() || kthread_should_stop()) + break; bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos, copy->file_dst, dst_pos, bytes_total); if (bytes_copied <= 0)
@@ -1188,7 +1198,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)spin_lock (©->cp_clp->async_lock);list_del (©->copies);spin_unlock (©->cp_clp->async_lock); -kfree (copy); +nfs4_put_copy (copy); }static int nfsd4_do_async_copy (void *data)
@@ -1238,6 +1248,7 @@ static int nfsd4_do_async_copy(void *data) goto out;if (!nfs4_init_cp_state (nn, copy)) goto out; +refcount_set (&async_copy->refcount,1 );memcpy (©->cp_res.cb_stateid, ©->cp_stateid,sizeof (copy->cp_stateid));dup_copy_fields (copy, async_copy);
@@ -1267,7 +1278,30 @@ static int nfsd4_do_async_copy(void *data)struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { -return 0 ; + struct nfsd4_offload_status *os = &u->offload_status; +__be32 status =0 ; +struct nfsd4_copy *copy; +bool found = false; +struct nfs4_client *clp = cstate->clp; + +spin_lock (&clp->async_lock); +list_for_each_entry (copy, &clp->async_copies, copies) { +if (memcmp (©->cp_stateid, &os->stateid, +NFS4_STATEID_SIZE )) +continue ; + found = true; +refcount_inc (©->refcount); +break ; + } +spin_unlock (&clp->async_lock); +if (found) { +set_tsk_thread_flag (copy->copy_task,TIF_SIGPENDING ); +kthread_stop (copy->copy_task); +nfs4_put_copy (copy); + }else + status = nfserr_bad_stateid; + +return status; } static __be32
fs/nfsd/state.h +1 -0
@@ -641,6 +641,7 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,struct nfs4_file *find_file (struct knfsd_fh *fh);void put_nfs4_file (struct nfs4_file *fi); +extern void nfs4_put_copy (struct nfsd4_copy *copy);static inline void get_nfs4_file (struct nfs4_file *fi) {refcount_inc (&fi->fi_ref);
fs/nfsd/xdr4.h +1 -0
@@ -542,6 +542,7 @@ struct nfsd4_copy {struct list_head copies;struct task_struct *copy_task; +refcount_t refcount; };extern bool async_copy_offload_enable;
Signature · 1 line
1.8.3.1
PATCH v9 8/9 NFSD support OFFLOAD_STATUS
In reply to Olga KornievskaiaSearch the list for the asynchronous copy based on the stateid, then lookup the number of bytes copied so far.
--- fs/nfsd/nfs4proc.c | 45 ++++++++++++++++++++++++++++++++------------- fs/nfsd/state.h | 2 ++ 2 files changed, 34 insertions(+), 13 deletions(-)
fs/nfsd/nfs4proc.c +32 -13
@@ -1273,6 +1273,23 @@ static int nfsd4_do_async_copy(void *data) goto out; } +struct nfsd4_copy * +find_async_copy (struct nfs4_client *clp,stateid_t *stateid) +{ +struct nfsd4_copy *copy; + +spin_lock (&clp->async_lock); +list_for_each_entry (copy, &clp->async_copies, copies) { +if (memcmp (©->cp_stateid, stateid,NFS4_STATEID_SIZE )) +continue ; +refcount_inc (©->refcount); +spin_unlock (&clp->async_lock); +return copy; + } +spin_unlock (&clp->async_lock); +return NULL ; +} + static __be32 nfsd4_offload_cancel(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
@@ -1281,20 +1298,10 @@ static int nfsd4_do_async_copy(void *data)struct nfsd4_offload_status *os = &u->offload_status;__be32 status =0 ;struct nfsd4_copy *copy; -bool found = false;struct nfs4_client *clp = cstate->clp; -spin_lock (&clp->async_lock); -list_for_each_entry (copy, &clp->async_copies, copies) { -if (memcmp (©->cp_stateid, &os->stateid, -NFS4_STATEID_SIZE )) -continue ; - found = true; -refcount_inc (©->refcount); -break ; - } -spin_unlock (&clp->async_lock); -if (found) { + copy =find_async_copy (clp, &os->stateid); +if (copy) {set_tsk_thread_flag (copy->copy_task,TIF_SIGPENDING );kthread_stop (copy->copy_task);nfs4_put_copy (copy);
@@ -1331,7 +1338,19 @@ static int nfsd4_do_async_copy(void *data)struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { - return nfserr_notsupp; + struct nfsd4_offload_status *os = &u->offload_status; +__be32 status =0 ; +struct nfsd4_copy *copy; +struct nfs4_client *clp = cstate->clp; + + copy =find_async_copy (clp, &os->stateid); +if (copy) { + os->count = copy->cp_res.wr_bytes_written; +nfs4_put_copy (copy); + }else + status = nfserr_bad_stateid; + +return status; } static __be32
fs/nfsd/state.h +2 -0
@@ -642,6 +642,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,struct nfs4_file *find_file (struct knfsd_fh *fh);void put_nfs4_file (struct nfs4_file *fi);extern void nfs4_put_copy (struct nfsd4_copy *copy); +extern struct nfsd4_copy * +find_async_copy (struct nfs4_client *clp,stateid_t *staetid);static inline void get_nfs4_file (struct nfs4_file *fi) {refcount_inc (&fi->fi_ref);
Signature · 1 line
1.8.3.1
PATCH v9 9/9 NFSD stop ongoing async copies on client shutdown
In reply to Olga KornievskaiaFrom: Olga Kornievskaia <[email protected]>
If client received DESTROY_CLIENTID and there are (for some reason) on-going async copies, send CLIENT_BUSY error back (eg., client didn't send OFFLOAD_CANCEL).
If client's lease expired and client structure is being shutdown and there are on-going async copies, then shutdown the copies.
--- fs/nfsd/nfs4proc.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- fs/nfsd/nfs4state.c | 4 +++- fs/nfsd/state.h | 1 + fs/nfsd/xdr4.h | 1 + 4 files changed, 53 insertions(+), 6 deletions(-)
fs/nfsd/nfs4proc.c +48 -5
@@ -1108,6 +1108,51 @@ void nfs4_put_copy(struct nfsd4_copy *copy)kfree (copy); } +static bool +check_and_set_stop_copy (struct nfsd4_copy *copy) +{ +bool value; + +spin_lock (©->cp_clp->async_lock); + value = copy->stopped; +if (!copy->stopped) + copy->stopped = true; +spin_unlock (©->cp_clp->async_lock); +return value; +} + +static void nfsd4_stop_copy (struct nfsd4_copy *copy) +{ +/* only 1 thread should stop the copy */ +if (!check_and_set_stop_copy (copy)) { +set_tsk_thread_flag (copy->copy_task,TIF_SIGPENDING ); +kthread_stop (copy->copy_task); + } +nfs4_put_copy (copy); +} + +static struct nfsd4_copy *nfsd4_get_copy (struct nfs4_client *clp) +{ +struct nfsd4_copy *copy =NULL ; + +spin_lock (&clp->async_lock); +if (!list_empty (&clp->async_copies)) { + copy = list_first_entry(&clp->async_copies, struct nfsd4_copy, + copies); +refcount_inc (©->refcount); + } +spin_unlock (&clp->async_lock); +return copy; +} + +void nfsd4_shutdown_copy (struct nfs4_client *clp) +{ +struct nfsd4_copy *copy; + +while ((copy =nfsd4_get_copy (clp)) !=NULL ) +nfsd4_stop_copy (copy); +} +static void nfsd4_cb_offload_release (struct nfsd4_callback *cb) { struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
@@ -1301,11 +1346,9 @@ struct nfsd4_copy *struct nfs4_client *clp = cstate->clp; copy =find_async_copy (clp, &os->stateid); -if (copy) { -set_tsk_thread_flag (copy->copy_task,TIF_SIGPENDING ); -kthread_stop (copy->copy_task); -nfs4_put_copy (copy); - }else +if (copy) +nfsd4_stop_copy (copy); +else status = nfserr_bad_stateid;return status;
fs/nfsd/nfs4state.c +3 -1
@@ -1974,6 +1974,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp) } }nfsd4_return_all_client_layouts (clp); +nfsd4_shutdown_copy (clp);nfsd4_shutdown_callback (clp);if (clp->cl_cb_conn.cb_xprt)svc_xprt_put (clp->cl_cb_conn.cb_xprt);
@@ -2504,7 +2505,8 @@ static bool client_has_state(struct nfs4_client *clp) || !list_empty(&clp->cl_lo_states) #endif || !list_empty (&clp->cl_delegations) - || !list_empty(&clp->cl_sessions); + || !list_empty (&clp->cl_sessions) + || !list_empty(&clp->async_copies); } __be32
fs/nfsd/state.h +1 -0
@@ -634,6 +634,7 @@ extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,extern int nfsd4_create_callback_queue (void );extern void nfsd4_destroy_callback_queue (void );extern void nfsd4_shutdown_callback (struct nfs4_client *); +extern void nfsd4_shutdown_copy (struct nfs4_client *clp);extern void nfsd4_prepare_cb_recall (struct nfs4_delegation *dp);extern struct nfs4_client_reclaim *nfs4_client_to_reclaim (const char *name,struct nfsd_net *nn);
fs/nfsd/xdr4.h +1 -0
@@ -543,6 +543,7 @@ struct nfsd4_copy {struct list_head copies;struct task_struct *copy_task;refcount_t refcount; +bool stopped; };extern bool async_copy_offload_enable;
Signature · 1 line
1.8.3.1
Quoted 20 lines · Olga Kornievskaia
From: Olga Kornievskaia <[email protected]>
To do asynchronous copies, NFSD creates a new kthread to handle the request. Upon receiving the COPY, it generates a unique copy stateid (stored in a global list for keeping track of state for
OFFLOAD_STATUSto be queried by), starts the thread, and replies back to the client.nfsd4_copyarguments that are allocated on the stack are copies for the kthread.For the async copy handler, copy is done in the loop for the requested number of bytes. If an error is encountered and partial copy has happened, a successful partial copy is returned in the
CB_OFFLOAD.vfs_copy_file_rangeis called with 4MB chunks for both async and sync, allowing for 4MB granularity ofOFFLOAD_STATUSqueiry. Once copy is done, the results are queued for the callback workqueue and sent viaCB_OFFLOAD.When the server received an
OFFLOAD_CANCEL, it will find the kthread running the copy and will send a SIGPENDING andkthread_stop()and it will interrupt the ongoingdo_splice()and once vfs returns we are choosing not to send theCB_OFFLOADback to the client.
Quoted 7 lines
When the server receives an
OFFLOAD_STATUS, it will find the kthread running the copy and will locate within the copy state the current number of bytes copied so far.v9:
-- added module parameter (async_copy_offload_enable) to turns on async copy processing on the server
I think we got confused in the previous discussion of this.
The reason I wanted the module parameter was that server-to-server copy would allow a rogue client to direct the server to copy from any server it wishes, and I thought this was potentially risky, and want people to opt into it rather than having it the default.
That doesn't apply to asynchronous copy on its own.
So this module parameter could wait for the next patchset.
--b.
Quoted 29 lines
-- fixes some kbuild errors from the previous submission
Olga Kornievskaia (9):
NFSDCB_OFFLOADxdr
NFSDOFFLOAD_STATUSxdr
NFSDOFFLOAD_CANCELxdr
NFSD xdr callback stateid in async COPY reply NFSD introduce async copy feature
NFSD create new stateid for async copy NFSD handleOFFLOAD_CANCELop
NFSD supportOFFLOAD_STATUS
NFSD stop ongoing async copies on client shutdownfs/nfsd/netns.h | 8 ++ fs/nfsd/nfs4callback.c | 98 +++++++++++++++++ fs/nfsd/nfs4proc.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/nfsd/nfs4state.c | 38 ++++++- fs/nfsd/nfs4xdr.c | 50 +++++++-- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfssvc.c | 6 + fs/nfsd/state.h | 10 ++ fs/nfsd/xdr4.h | 29 +++++ fs/nfsd/xdr4cb.h | 10 ++ 10 files changed, 517 insertions(+), 24 deletions(-)Signature · 1 line
1.8.3.1
Quoted 31 lines · J. Bruce Fields
Quoted 20 lines · Olga Kornievskaia
From: Olga Kornievskaia <[email protected]>
To do asynchronous copies, NFSD creates a new kthread to handle the request. Upon receiving the COPY, it generates a unique copy stateid (stored in a global list for keeping track of state for
OFFLOAD_STATUSto be queried by), starts the thread, and replies back to the client.nfsd4_copyarguments that are allocated on the stack are copies for the kthread.For the async copy handler, copy is done in the loop for the requested number of bytes. If an error is encountered and partial copy has happened, a successful partial copy is returned in the
CB_OFFLOAD.vfs_copy_file_rangeis called with 4MB chunks for both async and sync, allowing for 4MB granularity ofOFFLOAD_STATUSqueiry. Once copy is done, the results are queued for the callback workqueue and sent viaCB_OFFLOAD.When the server received an
OFFLOAD_CANCEL, it will find the kthread running the copy and will send a SIGPENDING andkthread_stop()and it will interrupt the ongoingdo_splice()and once vfs returns we are choosing not to send theCB_OFFLOADback to the client.Quoted 7 lines
When the server receives an
OFFLOAD_STATUS, it will find the kthread running the copy and will locate within the copy state the current number of bytes copied so far.v9:
-- added module parameter (async_copy_offload_enable) to turns on async copy processing on the serverI think we got confused in the previous discussion of this.
Quoted 8 lines
The reason I wanted the module parameter was that server-to-server copy would allow a rogue client to direct the server to copy from any server it wishes, and I thought this was potentially risky, and want people to opt into it rather than having it the default.
That doesn't apply to asynchronous copy on its own.
So this module parameter could wait for the next patchset.
To clarify, you want "inter" copy offload to be configuration, but it already was (when it was first posted) under config option. Now instead of a compile option you prefer this to be a module parameter?
Do you have any other comments? I'd rather not re-post another version if you have more comments.
Quoted 36 lines
--b.
Quoted 26 lines
-- fixes some kbuild errors from the previous submission
Olga Kornievskaia (9):
NFSDCB_OFFLOADxdr
NFSDOFFLOAD_STATUSxdr
NFSDOFFLOAD_CANCELxdr
NFSD xdr callback stateid in async COPY reply NFSD introduce async copy feature
NFSD create new stateid for async copy NFSD handleOFFLOAD_CANCELop
NFSD supportOFFLOAD_STATUS
NFSD stop ongoing async copies on client shutdownfs/nfsd/netns.h | 8 ++ fs/nfsd/nfs4callback.c | 98 +++++++++++++++++ fs/nfsd/nfs4proc.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/nfsd/nfs4state.c | 38 ++++++- fs/nfsd/nfs4xdr.c | 50 +++++++-- fs/nfsd/nfsctl.c | 1 + fs/nfsd/nfssvc.c | 6 + fs/nfsd/state.h | 10 ++ fs/nfsd/xdr4.h | 29 +++++ fs/nfsd/xdr4cb.h | 10 ++ 10 files changed, 517 insertions(+), 24 deletions(-)Quoted 3 lines
--
1.8.3.1--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 8 lines · Olga Kornievskaia
Quoted 7 lines · J. Bruce Fields
I think we got confused in the previous discussion of this.
The reason I wanted the module parameter was that server-to-server copy would allow a rogue client to direct the server to copy from any server it wishes, and I thought this was potentially risky, and want people to opt into it rather than having it the default.
Quoted 7 lines
Quoted 3 lines
That doesn't apply to asynchronous copy on its own.
So this module parameter could wait for the next patchset.
To clarify, you want "inter" copy offload to be configuration, but it already was (when it was first posted) under config option. Now instead of a compile option you prefer this to be a module parameter?
That's right.
I'd like distributions to be able to include server-to-server-copy capable kernels, but I don't want it on by default because I think responsible administrators will want to do some firewalling first.
Quoted 2 lines
Do you have any other comments? I'd rather not re-post another version if you have more comments.
In that case I'd recommend holding off till next week.
--b.
Quoted 19 lines · J. Bruce Fields
Quoted 8 lines · Olga Kornievskaia
Quoted 7 lines · J. Bruce Fields
I think we got confused in the previous discussion of this.
The reason I wanted the module parameter was that server-to-server copy would allow a rogue client to direct the server to copy from any server it wishes, and I thought this was potentially risky, and want people to opt into it rather than having it the default.
Quoted 7 lines
Quoted 3 lines
That doesn't apply to asynchronous copy on its own.
So this module parameter could wait for the next patchset.
To clarify, you want "inter" copy offload to be configuration, but it already was (when it was first posted) under config option. Now instead of a compile option you prefer this to be a module parameter?
That's right.
Quoted 8 lines
I'd like distributions to be able to include server-to-server-copy capable kernels, but I don't want it on by default because I think responsible administrators will want to do some firewalling first.
Quoted 2 lines
Do you have any other comments? I'd rather not re-post another version if you have more comments.
In that case I'd recommend holding off till next week.
I read through the rest of the patches and don't see any show stoppers.
--b.