* [RFC v2 01/12] NFS CB_OFFLOAD xdr
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 02/12] NFS OFFLOAD_STATUS xdr Olga Kornievskaia
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/callback.h | 13 ++++++++
fs/nfs/callback_proc.c | 7 +++++
fs/nfs/callback_xdr.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index c701c30..e4ab65d 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -189,6 +189,19 @@ extern __be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args,
void *dummy,
struct cb_process_state *cps);
#endif /* CONFIG_NFS_V4_1 */
+#ifdef CONFIG_NFS_V4_2
+struct cb_offloadargs {
+ struct nfs_fh coa_fh;
+ nfs4_stateid coa_stateid;
+ uint32_t error;
+ uint64_t wr_count;
+ struct nfs_writeverf wr_writeverf;
+};
+
+extern __be32 nfs4_callback_offload(
+ struct cb_offloadargs *args,
+ void *dummy, struct cb_process_state *cps);
+#endif /* CONFIG_NFS_V4_2 */
extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
struct cb_getattrres *res,
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index f073a6d2c..b68b803 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -680,3 +680,10 @@ __be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args, void *dummy,
return htonl(NFS4_OK);
}
#endif /* CONFIG_NFS_V4_1 */
+#ifdef CONFIG_NFS_V4_2
+__be32 nfs4_callback_offload(struct cb_offloadargs *args, void *dummy,
+ struct cb_process_state *cps)
+{
+ return 0;
+}
+#endif /* CONFIG_NFS_V4_2 */
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index d051fc3..97f9d78 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -37,6 +37,9 @@
#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
#define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
#endif /* CONFIG_NFS_V4_1 */
+#ifdef CONFIG_NFS_V4_2
+#define CB_OP_OFFLOAD_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
+#endif /* CONFIG_NFS_V4_2 */
#define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -565,7 +568,72 @@ static __be32 decode_notify_lock_args(struct svc_rqst *rqstp, struct xdr_stream
}
#endif /* CONFIG_NFS_V4_1 */
+#ifdef CONFIG_NFS_V4_2
+static __be32 decode_write_response(struct xdr_stream *xdr,
+ struct cb_offloadargs *args)
+{
+ __be32 *p;
+ __be32 dummy;
+
+ /* skip the always zero field */
+ p = read_buf(xdr, 4);
+ if (unlikely(!p))
+ goto out;
+ dummy = ntohl(*p++);
+
+ /* decode count, stable_how, verifier */
+ p = xdr_inline_decode(xdr, 8 + 4);
+ if (unlikely(!p))
+ goto out;
+ p = xdr_decode_hyper(p, &args->wr_count);
+ args->wr_writeverf.committed = be32_to_cpup(p);
+ p = xdr_inline_decode(xdr, NFS4_VERIFIER_SIZE);
+ if (likely(p)) {
+ memcpy(&args->wr_writeverf.verifier.data[0], p,
+ NFS4_VERIFIER_SIZE);
+ return 0;
+ }
+out:
+ return htonl(NFS4ERR_RESOURCE);
+}
+static __be32 decode_offload_args(struct svc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct cb_offloadargs *args)
+{
+ __be32 *p;
+ __be32 status;
+
+ /* decode fh */
+ status = decode_fh(xdr, &args->coa_fh);
+ if (unlikely(status != 0))
+ return status;
+
+ /* decode stateid */
+ status = decode_stateid(xdr, &args->coa_stateid);
+ if (unlikely(status != 0))
+ return status;
+
+ /* decode status */
+ p = read_buf(xdr, 4);
+ if (unlikely(!p))
+ goto out;
+ args->error = ntohl(*p++);
+ if (!args->error) {
+ status = decode_write_response(xdr, args);
+ if (unlikely(status != 0))
+ return status;
+ } else {
+ p = xdr_inline_decode(xdr, 8);
+ if (unlikely(!p))
+ goto out;
+ p = xdr_decode_hyper(p, &args->wr_count);
+ }
+ return 0;
+out:
+ return htonl(NFS4ERR_RESOURCE);
+}
+#endif /* CONFIG_NFS_V4_2 */
static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0))
@@ -833,7 +901,10 @@ static void nfs4_cb_free_slot(struct cb_process_state *cps)
if (status != htonl(NFS4ERR_OP_ILLEGAL))
return status;
- if (op_nr == OP_CB_OFFLOAD)
+ if (op_nr == OP_CB_OFFLOAD) {
+ *op = &callback_ops[op_nr];
+ return htonl(NFS_OK);
+ } else
return htonl(NFS4ERR_NOTSUPP);
return htonl(NFS4ERR_OP_ILLEGAL);
}
@@ -1038,6 +1109,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
.res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ,
},
#endif /* CONFIG_NFS_V4_1 */
+#ifdef CONFIG_NFS_V4_2
+ [OP_CB_OFFLOAD] = {
+ .process_op = (callback_process_op_t)nfs4_callback_offload,
+ .decode_args = (callback_decode_arg_t)decode_offload_args,
+ .res_maxsize = CB_OP_OFFLOAD_RES_MAXSZ,
+ },
+#endif /* CONFIG_NFS_V4_2 */
};
/*
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 02/12] NFS OFFLOAD_STATUS xdr
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 01/12] NFS CB_OFFLOAD xdr Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 03/12] NFS OFFLOAD_STATUS op Olga Kornievskaia
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42xdr.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4proc.c | 1 +
fs/nfs/nfs4xdr.c | 1 +
include/linux/nfs4.h | 1 +
include/linux/nfs_fs_sb.h | 1 +
include/linux/nfs_xdr.h | 12 +++++++
6 files changed, 103 insertions(+)
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 6c72964..66f6193 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -25,6 +25,11 @@
NFS42_WRITE_RES_SIZE + \
1 /* cr_consecutive */ + \
1 /* cr_synchronous */)
+#define encode_offload_status_maxsz (op_encode_hdr_maxsz + \
+ XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_offload_status_maxsz (op_decode_hdr_maxsz + \
+ 2 /* osr_count */ + \
+ 1 + 1 /* osr_complete<1> */)
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
encode_fallocate_maxsz)
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
@@ -72,6 +77,12 @@
decode_savefh_maxsz + \
decode_putfh_maxsz + \
decode_copy_maxsz)
+#define NFS4_enc_offload_status_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_offload_status_maxsz)
+#define NFS4_dec_offload_status_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_offload_status_maxsz)
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_deallocate_maxsz + \
@@ -142,6 +153,14 @@ static void encode_copy(struct xdr_stream *xdr,
encode_uint32(xdr, 0); /* src server list */
}
+static void encode_offload_status(struct xdr_stream *xdr,
+ struct nfs42_offload_status_args *args,
+ struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_OFFLOAD_STATUS, decode_offload_status_maxsz, hdr);
+ encode_nfs4_stateid(xdr, &args->osa_stateid);
+}
+
static void encode_deallocate(struct xdr_stream *xdr,
struct nfs42_falloc_args *args,
struct compound_hdr *hdr)
@@ -243,6 +262,24 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
}
/*
+ * Encode OFFLOAD_STATUS request
+ */
+static void nfs4_xdr_enc_offload_status(struct rpc_rqst *req,
+ struct xdr_stream *xdr,
+ struct nfs42_offload_status_args *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->osa_seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->osa_seq_args, &hdr);
+ encode_putfh(xdr, args->osa_src_fh, &hdr);
+ encode_offload_status(xdr, args, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
* Encode DEALLOCATE request
*/
static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
@@ -391,6 +428,31 @@ static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
return decode_copy_requirements(xdr, res);
}
+static int decode_offload_status(struct xdr_stream *xdr,
+ struct nfs42_offload_status_res *res)
+{
+ __be32 *p;
+ uint32_t count;
+ int status;
+
+ status = decode_op_hdr(xdr, OP_OFFLOAD_STATUS);
+ if (status)
+ return status;
+ p = xdr_inline_decode(xdr, 8 + 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ p = xdr_decode_hyper(p, &res->osr_count);
+ count = be32_to_cpup(p++);
+ if (count) {
+ p = xdr_inline_decode(xdr, 4);
+ res->osr_status = be32_to_cpup(p);
+ }
+ return 0;
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
{
return decode_op_hdr(xdr, OP_DEALLOCATE);
@@ -486,6 +548,31 @@ static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
}
/*
+ * Decode OFFLOAD_STATUS response
+ */
+static int nfs4_xdr_dec_offload_status(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct nfs42_offload_status_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->osr_seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_offload_status(xdr, res);
+
+out:
+ return status;
+}
+
+/*
* Decode DEALLOCATE request
*/
static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1b18368..3caed60 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9245,6 +9245,7 @@ static bool nfs4_match_stateid(const nfs4_stateid *s1,
| NFS_CAP_ATOMIC_OPEN_V1
| NFS_CAP_ALLOCATE
| NFS_CAP_COPY
+ | NFS_CAP_OFFLOAD_STATUS
| NFS_CAP_DEALLOCATE
| NFS_CAP_SEEK
| NFS_CAP_LAYOUTSTATS
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index f0369e3..f7f695a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7573,6 +7573,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats),
PROC(CLONE, enc_clone, dec_clone),
PROC(COPY, enc_copy, dec_copy),
+ PROC(OFFLOAD_STATUS, enc_offload_status, dec_offload_status),
#endif /* CONFIG_NFS_V4_2 */
};
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1b1ca04..d67c350 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -523,6 +523,7 @@ enum {
NFSPROC4_CLNT_LAYOUTSTATS,
NFSPROC4_CLNT_CLONE,
NFSPROC4_CLNT_COPY,
+ NFSPROC4_CLNT_OFFLOAD_STATUS,
};
/* nfs41 types */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index b34097c..a53f9ca 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -250,5 +250,6 @@ struct nfs_server {
#define NFS_CAP_LAYOUTSTATS (1U << 22)
#define NFS_CAP_CLONE (1U << 23)
#define NFS_CAP_COPY (1U << 24)
+#define NFS_CAP_OFFLOAD_STATUS (1U << 25)
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 348f7c1..aafafde 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1385,6 +1385,18 @@ struct nfs42_copy_res {
bool synchronous;
};
+struct nfs42_offload_status_args {
+ struct nfs4_sequence_args osa_seq_args;
+ struct nfs_fh *osa_src_fh;
+ nfs4_stateid osa_stateid;
+};
+
+struct nfs42_offload_status_res {
+ struct nfs4_sequence_res osr_seq_res;
+ uint64_t osr_count;
+ int osr_status;
+};
+
struct nfs42_seek_args {
struct nfs4_sequence_args seq_args;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 03/12] NFS OFFLOAD_STATUS op
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 01/12] NFS CB_OFFLOAD xdr Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 02/12] NFS OFFLOAD_STATUS xdr Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 04/12] NFS OFFLOAD_CANCEL xdr Olga Kornievskaia
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42.h | 3 ++-
fs/nfs/nfs42proc.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index b6cd153..90ef9b4 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -19,5 +19,6 @@
int nfs42_proc_layoutstats_generic(struct nfs_server *,
struct nfs42_layoutstat_data *);
int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t);
-
+int nfs42_proc_offload_status(struct file *, nfs4_stateid *,
+ struct nfs42_offload_status_res *);
#endif /* __LINUX_FS_NFS_NFS4_2_H */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 1e486c7..d4e7f60 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -254,6 +254,48 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
return err;
}
+int _nfs42_proc_offload_status(struct file *dst, nfs4_stateid *stateid,
+ struct nfs42_offload_status_res *res)
+{
+ struct nfs42_offload_status_args args;
+ struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_STATUS],
+ .rpc_resp = res,
+ };
+ int status;
+
+ args.osa_src_fh = NFS_FH(file_inode(dst));
+ memcpy(&args.osa_stateid, stateid, sizeof(args.osa_stateid));
+ msg.rpc_argp = &args;
+ status = nfs4_call_sync(dst_server->client, dst_server, &msg,
+ &args.osa_seq_args, &res->osr_seq_res, 0);
+ if (status == -ENOTSUPP)
+ dst_server->caps &= ~NFS_CAP_OFFLOAD_STATUS;
+
+ return status;
+}
+
+int nfs42_proc_offload_status(struct file *dst, nfs4_stateid *stateid,
+ struct nfs42_offload_status_res *res)
+{
+ struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
+ struct nfs4_exception exception = { };
+ int status;
+
+ if (!(dst_server->caps & NFS_CAP_OFFLOAD_STATUS))
+ return -EOPNOTSUPP;
+
+ do {
+ status = _nfs42_proc_offload_status(dst, stateid, res);
+ if (status == -ENOTSUPP)
+ return -EOPNOTSUPP;
+ status = nfs4_handle_exception(dst_server, status, &exception);
+ } while (exception.retry);
+
+ return status;
+}
+
static loff_t _nfs42_proc_llseek(struct file *filep,
struct nfs_lock_context *lock, loff_t offset, int whence)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 04/12] NFS OFFLOAD_CANCEL xdr
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (2 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 03/12] NFS OFFLOAD_STATUS op Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 05/12] NFS COPY xdr handle async reply Olga Kornievskaia
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42xdr.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4proc.c | 1 +
fs/nfs/nfs4xdr.c | 1 +
include/linux/nfs4.h | 1 +
include/linux/nfs_fs_sb.h | 1 +
5 files changed, 70 insertions(+)
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 66f6193..7634a77 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -30,6 +30,9 @@
#define decode_offload_status_maxsz (op_decode_hdr_maxsz + \
2 /* osr_count */ + \
1 + 1 /* osr_complete<1> */)
+#define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \
+ XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_offload_cancel_maxsz (op_decode_hdr_maxsz)
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
encode_fallocate_maxsz)
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
@@ -83,6 +86,12 @@
#define NFS4_dec_offload_status_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_offload_status_maxsz)
+#define NFS4_enc_offload_cancel_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_offload_cancel_maxsz)
+#define NFS4_dec_offload_cancel_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_offload_cancel_maxsz)
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_deallocate_maxsz + \
@@ -161,6 +170,14 @@ static void encode_offload_status(struct xdr_stream *xdr,
encode_nfs4_stateid(xdr, &args->osa_stateid);
}
+static void encode_offload_cancel(struct xdr_stream *xdr,
+ struct nfs42_offload_status_args *args,
+ struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_OFFLOAD_CANCEL, decode_offload_cancel_maxsz, hdr);
+ encode_nfs4_stateid(xdr, &args->osa_stateid);
+}
+
static void encode_deallocate(struct xdr_stream *xdr,
struct nfs42_falloc_args *args,
struct compound_hdr *hdr)
@@ -280,6 +297,24 @@ static void nfs4_xdr_enc_offload_status(struct rpc_rqst *req,
}
/*
+ * Encode OFFLOAD_CANEL request
+ */
+static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
+ struct xdr_stream *xdr,
+ struct nfs42_offload_status_args *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->osa_seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->osa_seq_args, &hdr);
+ encode_putfh(xdr, args->osa_src_fh, &hdr);
+ encode_offload_cancel(xdr, args, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
* Encode DEALLOCATE request
*/
static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
@@ -453,6 +488,12 @@ static int decode_offload_status(struct xdr_stream *xdr,
return -EIO;
}
+static int decode_offload_cancel(struct xdr_stream *xdr,
+ struct nfs42_offload_status_res *res)
+{
+ return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
+}
+
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
{
return decode_op_hdr(xdr, OP_DEALLOCATE);
@@ -573,6 +614,31 @@ static int nfs4_xdr_dec_offload_status(struct rpc_rqst *rqstp,
}
/*
+ * Decode OFFLOAD_CANCEL response
+ */
+static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct nfs42_offload_status_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->osr_seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_offload_cancel(xdr, res);
+
+out:
+ return status;
+}
+
+/*
* Decode DEALLOCATE request
*/
static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3caed60..5450926 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9246,6 +9246,7 @@ static bool nfs4_match_stateid(const nfs4_stateid *s1,
| NFS_CAP_ALLOCATE
| NFS_CAP_COPY
| NFS_CAP_OFFLOAD_STATUS
+ | NFS_CAP_OFFLOAD_CANCEL
| NFS_CAP_DEALLOCATE
| NFS_CAP_SEEK
| NFS_CAP_LAYOUTSTATS
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index f7f695a..cf07efc 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7574,6 +7574,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(CLONE, enc_clone, dec_clone),
PROC(COPY, enc_copy, dec_copy),
PROC(OFFLOAD_STATUS, enc_offload_status, dec_offload_status),
+ PROC(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel),
#endif /* CONFIG_NFS_V4_2 */
};
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index d67c350..7262908 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -524,6 +524,7 @@ enum {
NFSPROC4_CLNT_CLONE,
NFSPROC4_CLNT_COPY,
NFSPROC4_CLNT_OFFLOAD_STATUS,
+ NFSPROC4_CLNT_OFFLOAD_CANCEL,
};
/* nfs41 types */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index a53f9ca..298ce5a 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -251,5 +251,6 @@ struct nfs_server {
#define NFS_CAP_CLONE (1U << 23)
#define NFS_CAP_COPY (1U << 24)
#define NFS_CAP_OFFLOAD_STATUS (1U << 25)
+#define NFS_CAP_OFFLOAD_CANCEL (1U << 26)
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 05/12] NFS COPY xdr handle async reply
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (3 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 04/12] NFS OFFLOAD_CANCEL xdr Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 06/12] NFS add support for asynchronous COPY Olga Kornievskaia
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
If server returns async reply, it must include a callback stateid,
wr_callback_id in the write_response4.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42xdr.c | 22 ++++++++++++----------
include/linux/nfs_xdr.h | 1 +
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 7634a77..83dce11 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -403,21 +403,23 @@ static int decode_write_response(struct xdr_stream *xdr,
struct nfs42_write_res *res)
{
__be32 *p;
+ int status, count;
- p = xdr_inline_decode(xdr, 4 + 8 + 4);
+ p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
-
- /*
- * We never use asynchronous mode, so warn if a server returns
- * a stateid.
- */
- if (unlikely(*p != 0)) {
- pr_err_once("%s: server has set unrequested "
- "asynchronous mode\n", __func__);
+ count = be32_to_cpup(p);
+ if (count > 1)
return -EREMOTEIO;
+ else if (count == 1) {
+ status = decode_opaque_fixed(xdr, &res->stateid,
+ NFS4_STATEID_SIZE);
+ if (unlikely(status))
+ goto out_overflow;
}
- p++;
+ p = xdr_inline_decode(xdr, 8 + 4);
+ if (unlikely(!p))
+ goto out_overflow;
p = xdr_decode_hyper(p, &res->count);
res->verifier.committed = be32_to_cpup(p);
return decode_verifier(xdr, &res->verifier.verifier);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index aafafde..6c6130f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1374,6 +1374,7 @@ struct nfs42_copy_args {
};
struct nfs42_write_res {
+ nfs4_stateid stateid;
u64 count;
struct nfs_writeverf verifier;
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 06/12] NFS add support for asynchronous COPY
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (4 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 05/12] NFS COPY xdr handle async reply Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 07/12] NFS handle COPY reply CB_OFFLOAD call race Olga Kornievskaia
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Change xdr to always send COPY asynchronously.
Keep the list copies send in a list under a server structure.
Once copy is sent, it waits on a completion structure that will
be signalled by the callback thread that receives CB_OFFLOAD.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/callback_proc.c | 34 ++++++++++++++++++++++++++++++++++
fs/nfs/client.c | 1 +
fs/nfs/nfs42proc.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
fs/nfs/nfs42xdr.c | 2 +-
include/linux/nfs_fs.h | 9 +++++++++
include/linux/nfs_fs_sb.h | 1 +
6 files changed, 88 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index b68b803..c1b081c 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -681,9 +681,43 @@ __be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args, void *dummy,
}
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
+static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
+ struct cb_offloadargs *args)
+{
+ cp_state->count = args->wr_count;
+ cp_state->error = args->error;
+ if (!args->error) {
+ cp_state->verf.committed = args->wr_writeverf.committed;
+ memcpy(&cp_state->verf.verifier.data[0],
+ &args->wr_writeverf.verifier.data[0],
+ NFS4_VERIFIER_SIZE);
+ }
+}
+
__be32 nfs4_callback_offload(struct cb_offloadargs *args, void *dummy,
struct cb_process_state *cps)
{
+ struct nfs_server *server;
+ struct nfs4_copy_state *copy;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
+ client_link) {
+ spin_lock(&server->nfs_client->cl_lock);
+ list_for_each_entry(copy, &server->ss_copies, copies) {
+ if (memcmp(args->coa_stateid.other,
+ copy->stateid.other,
+ sizeof(args->coa_stateid.other)))
+ continue;
+ nfs4_copy_cb_args(copy, args);
+ complete(©->completion);
+ spin_unlock(&server->nfs_client->cl_lock);
+ goto out;
+ }
+ spin_unlock(&server->nfs_client->cl_lock);
+ }
+out:
+ rcu_read_unlock();
return 0;
}
#endif /* CONFIG_NFS_V4_2 */
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 91a8d61..a72cd1d 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -885,6 +885,7 @@ struct nfs_server *nfs_alloc_server(void)
INIT_LIST_HEAD(&server->delegations);
INIT_LIST_HEAD(&server->layouts);
INIT_LIST_HEAD(&server->state_owners_lru);
+ INIT_LIST_HEAD(&server->ss_copies);
atomic_set(&server->active, 0);
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index d4e7f60..27a6eb8 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -129,6 +129,38 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
return err;
}
+static int handle_async_copy(struct nfs42_copy_res *res,
+ struct nfs_server *server,
+ struct file *src,
+ struct file *dst,
+ nfs4_stateid *src_stateid,
+ uint64_t *ret_count)
+{
+ struct nfs4_copy_state *copy;
+ int status;
+
+ copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
+ init_completion(©->completion);
+
+ spin_lock(&server->nfs_client->cl_lock);
+ list_add_tail(©->copies, &server->ss_copies);
+ spin_unlock(&server->nfs_client->cl_lock);
+
+ wait_for_completion_interruptible(©->completion);
+ spin_lock(&server->nfs_client->cl_lock);
+ list_del_init(©->copies);
+ spin_unlock(&server->nfs_client->cl_lock);
+ *ret_count = copy->count;
+ status = -copy->error;
+ if (copy->count && copy->verf.committed != NFS_FILE_SYNC)
+ status = nfs_commit_file(dst, ©->verf.verifier);
+ kfree(copy);
+ return status;
+}
+
static ssize_t _nfs42_proc_copy(struct file *src,
struct nfs_lock_context *src_lock,
struct file *dst,
@@ -147,6 +179,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
loff_t pos_dst = args->dst_pos;
size_t count = args->count;
int status;
+ uint64_t ret_count;
status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
src_lock, FMODE_READ);
@@ -174,16 +207,21 @@ static ssize_t _nfs42_proc_copy(struct file *src,
if (status)
return status;
- if (res->write_res.verifier.committed != NFS_FILE_SYNC) {
+ ret_count = res->write_res.count;
+ if (!res->synchronous) {
+ status = handle_async_copy(res, server, src, dst,
+ &args->src_stateid, &ret_count);
+ if (status)
+ return status;
+ } else if (res->write_res.verifier.committed != NFS_FILE_SYNC) {
status = nfs_commit_file(dst, &res->write_res.verifier.verifier);
if (status)
return status;
}
- truncate_pagecache_range(dst_inode, pos_dst,
- pos_dst + res->write_res.count);
+ truncate_pagecache_range(dst_inode, pos_dst, pos_dst + ret_count);
- return res->write_res.count;
+ return ret_count;
}
ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 83dce11..059d074 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -158,7 +158,7 @@ static void encode_copy(struct xdr_stream *xdr,
encode_uint64(xdr, args->count);
encode_uint32(xdr, 1); /* consecutive = true */
- encode_uint32(xdr, 1); /* synchronous = true */
+ encode_uint32(xdr, 0); /* synchronous = false */
encode_uint32(xdr, 0); /* src server list */
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 287f341..a862b7f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -182,6 +182,15 @@ struct nfs_inode {
struct inode vfs_inode;
};
+struct nfs4_copy_state {
+ struct list_head copies;
+ nfs4_stateid stateid;
+ struct completion completion;
+ uint64_t count;
+ struct nfs_writeverf verf;
+ int error;
+};
+
/*
* Cache validity bit flags
*/
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 298ce5a..9b252bb 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -206,6 +206,7 @@ struct nfs_server {
struct list_head state_owners_lru;
struct list_head layouts;
struct list_head delegations;
+ struct list_head ss_copies;
unsigned long mig_gen;
unsigned long mig_status;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 07/12] NFS handle COPY reply CB_OFFLOAD call race
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (5 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 06/12] NFS add support for asynchronous COPY Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 08/12] NFS send OFFLOAD_CANCEL when COPY killed Olga Kornievskaia
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
It's possible that server replies back with CB_OFFLOAD call and
COPY reply at the same time such that client will process
CB_OFFLOAD before reply to COPY. For that keep a list of pending
callback stateids received and them before waiting on completion
check the pending list.
Cleanup any pending copies on the client shutdown.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/callback_proc.c | 17 ++++++++++++++---
fs/nfs/nfs42proc.c | 24 +++++++++++++++++++++---
fs/nfs/nfs4client.c | 15 +++++++++++++++
include/linux/nfs_fs_sb.h | 1 +
4 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index c1b081c..01bcb4b 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -699,11 +699,12 @@ __be32 nfs4_callback_offload(struct cb_offloadargs *args, void *dummy,
{
struct nfs_server *server;
struct nfs4_copy_state *copy;
+ bool found = false;
+ spin_lock(&cps->clp->cl_lock);
rcu_read_lock();
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
client_link) {
- spin_lock(&server->nfs_client->cl_lock);
list_for_each_entry(copy, &server->ss_copies, copies) {
if (memcmp(args->coa_stateid.other,
copy->stateid.other,
@@ -711,13 +712,23 @@ __be32 nfs4_callback_offload(struct cb_offloadargs *args, void *dummy,
continue;
nfs4_copy_cb_args(copy, args);
complete(©->completion);
- spin_unlock(&server->nfs_client->cl_lock);
+ found = true;
goto out;
}
- spin_unlock(&server->nfs_client->cl_lock);
}
out:
rcu_read_unlock();
+ if (!found) {
+ copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
+ if (!copy) {
+ spin_unlock(&cps->clp->cl_lock);
+ return -ENOMEM;
+ }
+ memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
+ nfs4_copy_cb_args(copy, args);
+ list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
+ }
+ spin_unlock(&cps->clp->cl_lock);
return 0;
}
#endif /* CONFIG_NFS_V4_2 */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 27a6eb8..8ee9fb8 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -137,15 +137,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
uint64_t *ret_count)
{
struct nfs4_copy_state *copy;
- int status;
+ int status = NFS4_OK;
+ bool found_pending = false;
+
+ spin_lock(&server->nfs_client->cl_lock);
+ list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
+ copies) {
+ if (memcmp(&res->write_res.stateid, ©->stateid,
+ NFS4_STATEID_SIZE))
+ continue;
+ found_pending = true;
+ list_del(©->copies);
+ break;
+ }
+ if (found_pending) {
+ spin_unlock(&server->nfs_client->cl_lock);
+ goto out;
+ }
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
- if (!copy)
+ if (!copy) {
+ spin_unlock(&server->nfs_client->cl_lock);
return -ENOMEM;
+ }
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
init_completion(©->completion);
- spin_lock(&server->nfs_client->cl_lock);
list_add_tail(©->copies, &server->ss_copies);
spin_unlock(&server->nfs_client->cl_lock);
@@ -153,6 +170,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
spin_lock(&server->nfs_client->cl_lock);
list_del_init(©->copies);
spin_unlock(&server->nfs_client->cl_lock);
+out:
*ret_count = copy->count;
status = -copy->error;
if (copy->count && copy->verf.committed != NFS_FILE_SYNC)
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 5ae9d64..bebb97e1 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -156,9 +156,23 @@ struct rpc_clnt *
}
}
+static void
+nfs4_cleanup_callback(struct nfs_client *clp)
+{
+ struct nfs4_copy_state *cp_state;
+
+ while (!list_empty(&clp->pending_cb_stateids)) {
+ cp_state = list_entry(clp->pending_cb_stateids.next,
+ struct nfs4_copy_state, copies);
+ list_del(&cp_state->copies);
+ kfree(cp_state);
+ }
+}
+
void nfs41_shutdown_client(struct nfs_client *clp)
{
if (nfs4_has_session(clp)) {
+ nfs4_cleanup_callback(clp);
nfs4_shutdown_ds_clients(clp);
nfs4_destroy_session(clp->cl_session);
nfs4_destroy_clientid(clp);
@@ -202,6 +216,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
#if IS_ENABLED(CONFIG_NFS_V4_1)
init_waitqueue_head(&clp->cl_lock_waitq);
#endif
+ INIT_LIST_HEAD(&clp->pending_cb_stateids);
return clp;
error:
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 9b252bb..04f6cb4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -118,6 +118,7 @@ struct nfs_client {
#endif
struct net *cl_net;
+ struct list_head pending_cb_stateids;
};
/*
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 08/12] NFS send OFFLOAD_CANCEL when COPY killed
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (6 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 07/12] NFS handle COPY reply CB_OFFLOAD call race Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 09/12] NFS make COPY synchronous xdr configurable Olga Kornievskaia
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
When COPY is killed send OFFLOAD_CANCEL to both destination and
source servers.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42proc.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 8ee9fb8..2ffd96d 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -16,6 +16,7 @@
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
+static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
struct nfs_lock_context *lock, loff_t offset, loff_t len)
@@ -166,10 +167,15 @@ static int handle_async_copy(struct nfs42_copy_res *res,
list_add_tail(©->copies, &server->ss_copies);
spin_unlock(&server->nfs_client->cl_lock);
- wait_for_completion_interruptible(©->completion);
+ status = wait_for_completion_interruptible(©->completion);
spin_lock(&server->nfs_client->cl_lock);
list_del_init(©->copies);
spin_unlock(&server->nfs_client->cl_lock);
+ if (status == -ERESTARTSYS) {
+ nfs42_do_offload_cancel_async(dst, ©->stateid);
+ kfree(copy);
+ return status;
+ }
out:
*ret_count = copy->count;
status = -copy->error;
@@ -220,8 +226,13 @@ static ssize_t _nfs42_proc_copy(struct file *src,
status = nfs4_call_sync(server->client, server, &msg,
&args->seq_args, &res->seq_res, 0);
- if (status == -ENOTSUPP)
+ switch (status) {
+ case -ENOTSUPP:
server->caps &= ~NFS_CAP_COPY;
+ break;
+ case -ERESTARTSYS:
+ nfs42_do_offload_cancel_async(src, &args->src_stateid);
+ }
if (status)
return status;
@@ -310,6 +321,84 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
return err;
}
+struct nfs42_offloadcancel_data {
+ struct nfs_server *seq_server;
+ struct nfs42_offload_status_args args;
+ struct nfs42_offload_status_res res;
+};
+
+static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata)
+{
+ struct nfs42_offloadcancel_data *data = calldata;
+
+ nfs4_setup_sequence(data->seq_server->nfs_client,
+ &data->args.osa_seq_args,
+ &data->res.osr_seq_res, task);
+}
+
+static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata)
+{
+ struct nfs42_offloadcancel_data *data = calldata;
+
+ nfs41_sequence_done(task, &data->res.osr_seq_res);
+ kfree(data);
+}
+
+static void nfs42_free_offloadcancel_data(void *data)
+{
+ kfree(data);
+}
+
+static const struct rpc_call_ops nfs42_offload_cancel_ops = {
+ .rpc_call_prepare = nfs42_offload_cancel_prepare,
+ .rpc_call_done = nfs42_offload_cancel_done,
+ .rpc_release = nfs42_free_offloadcancel_data,
+};
+
+static int nfs42_do_offload_cancel_async(struct file *dst,
+ nfs4_stateid *stateid)
+{
+ struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
+ struct nfs42_offloadcancel_data *data = NULL;
+ struct nfs_open_context *ctx = nfs_file_open_context(dst);
+ struct rpc_task *task;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL],
+ .rpc_cred = ctx->cred,
+ };
+ struct rpc_task_setup task_setup_data = {
+ .rpc_client = dst_server->client,
+ .rpc_message = &msg,
+ .callback_ops = &nfs42_offload_cancel_ops,
+ .workqueue = nfsiod_workqueue,
+ .flags = RPC_TASK_ASYNC,
+ };
+ int status;
+
+ if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
+ return -EOPNOTSUPP;
+
+ data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS);
+ if (data == NULL)
+ return -ENOMEM;
+ data->seq_server = dst_server;
+ data->args.osa_src_fh = NFS_FH(file_inode(dst));
+ memcpy(&data->args.osa_stateid, stateid,
+ sizeof(data->args.osa_stateid));
+ msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ task_setup_data.callback_data = data;
+ nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res, 1);
+ task = rpc_run_task(&task_setup_data);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ status = rpc_wait_for_completion_task(task);
+ if (status == -ENOTSUPP)
+ dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL;
+ rpc_put_task(task);
+ return status;
+}
+
int _nfs42_proc_offload_status(struct file *dst, nfs4_stateid *stateid,
struct nfs42_offload_status_res *res)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 09/12] NFS make COPY synchronous xdr configurable
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (7 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 08/12] NFS send OFFLOAD_CANCEL when COPY killed Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 10/12] NFS handle COPY ERR_OFFLOAD_NO_REQS Olga Kornievskaia
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Instead of hardcoding always sending async copy, make it
configurable. In case, we get ERR_OFFLOAD_NO_REQS and we need to
resend the operation as synchronous.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42proc.c | 2 ++
fs/nfs/nfs42xdr.c | 2 +-
include/linux/nfs_xdr.h | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 2ffd96d..32b08ea 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -204,6 +204,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
size_t count = args->count;
int status;
uint64_t ret_count;
+ bool sync = false;
status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
src_lock, FMODE_READ);
@@ -224,6 +225,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
if (status)
return status;
+ args->sync = sync;
status = nfs4_call_sync(server->client, server, &msg,
&args->seq_args, &res->seq_res, 0);
switch (status) {
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 059d074..1f12574 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -158,7 +158,7 @@ static void encode_copy(struct xdr_stream *xdr,
encode_uint64(xdr, args->count);
encode_uint32(xdr, 1); /* consecutive = true */
- encode_uint32(xdr, 0); /* synchronous = false */
+ encode_uint32(xdr, args->sync);
encode_uint32(xdr, 0); /* src server list */
}
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 6c6130f..a04862c 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1371,6 +1371,7 @@ struct nfs42_copy_args {
u64 dst_pos;
u64 count;
+ bool sync;
};
struct nfs42_write_res {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 10/12] NFS handle COPY ERR_OFFLOAD_NO_REQS
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (8 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 09/12] NFS make COPY synchronous xdr configurable Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 11/12] NFS if we got partial copy ignore errors Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 12/12] NFS recover from destination server reboot for copies Olga Kornievskaia
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
If client sent async COPY and server replied with
ERR_OFFLOAD_NO_REQS, client should retry with a synchronous copy.
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42proc.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 32b08ea..850fa10 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -225,10 +225,17 @@ static ssize_t _nfs42_proc_copy(struct file *src,
if (status)
return status;
+retry:
args->sync = sync;
status = nfs4_call_sync(server->client, server, &msg,
&args->seq_args, &res->seq_res, 0);
switch (status) {
+ case -NFS4ERR_OFFLOAD_NO_REQS:
+ if (!sync) {
+ sync = true;
+ goto retry;
+ }
+ break;
case -ENOTSUPP:
server->caps &= ~NFS_CAP_COPY;
break;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 11/12] NFS if we got partial copy ignore errors
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (9 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 10/12] NFS handle COPY ERR_OFFLOAD_NO_REQS Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
2017-03-17 21:03 ` [RFC v2 12/12] NFS recover from destination server reboot for copies Olga Kornievskaia
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Don't ignore ENOSPC. Otherwise, try next copy chunk
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42proc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 850fa10..acd884d 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -178,7 +178,8 @@ static int handle_async_copy(struct nfs42_copy_res *res,
}
out:
*ret_count = copy->count;
- status = -copy->error;
+ if (copy->count < 0 || copy->error == ENOSPC)
+ status = -copy->error;
if (copy->count && copy->verf.committed != NFS_FILE_SYNC)
status = nfs_commit_file(dst, ©->verf.verifier);
kfree(copy);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC v2 12/12] NFS recover from destination server reboot for copies
2017-03-17 21:03 [RFC v2 00/12] NFS (just) async support for COPY Olga Kornievskaia
` (10 preceding siblings ...)
2017-03-17 21:03 ` [RFC v2 11/12] NFS if we got partial copy ignore errors Olga Kornievskaia
@ 2017-03-17 21:03 ` Olga Kornievskaia
11 siblings, 0 replies; 13+ messages in thread
From: Olga Kornievskaia @ 2017-03-17 21:03 UTC (permalink / raw)
To: Trond.Myklebust; +Cc: linux-nfs
Mark the destination state to indicate a server-side copy is
happening. On detecting a reboot and recovering open state check
if any state is engaged in a server-side copy, if so, find the
copy and mark it and then signal the waiting thread. Upon wakeup,
if copy was marked then propage EAGAIN to the nfsd_copy_file_range
and restart the copy from scratch (no partial state is being
queried at this point).
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
fs/nfs/nfs42proc.c | 20 ++++++++++++++++----
fs/nfs/nfs4_fs.h | 4 ++++
fs/nfs/nfs4file.c | 9 +++++++--
fs/nfs/nfs4state.c | 15 +++++++++++++++
include/linux/nfs_fs.h | 2 ++
5 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index acd884d..bab21ba5 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -140,6 +140,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
struct nfs4_copy_state *copy;
int status = NFS4_OK;
bool found_pending = false;
+ struct nfs_open_context *ctx = nfs_file_open_context(dst);
spin_lock(&server->nfs_client->cl_lock);
list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
@@ -163,6 +164,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
}
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
init_completion(©->completion);
+ copy->parent_state = ctx->state;
list_add_tail(©->copies, &server->ss_copies);
spin_unlock(&server->nfs_client->cl_lock);
@@ -172,9 +174,10 @@ static int handle_async_copy(struct nfs42_copy_res *res,
list_del_init(©->copies);
spin_unlock(&server->nfs_client->cl_lock);
if (status == -ERESTARTSYS) {
- nfs42_do_offload_cancel_async(dst, ©->stateid);
- kfree(copy);
- return status;
+ goto out_cancel;
+ } else if (copy->flags) {
+ status = -EAGAIN;
+ goto out_cancel;
}
out:
*ret_count = copy->count;
@@ -184,6 +187,10 @@ static int handle_async_copy(struct nfs42_copy_res *res,
status = nfs_commit_file(dst, ©->verf.verifier);
kfree(copy);
return status;
+out_cancel:
+ nfs42_do_offload_cancel_async(dst, ©->stateid);
+ kfree(copy);
+ return status;
}
static ssize_t _nfs42_proc_copy(struct file *src,
@@ -226,6 +233,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
if (status)
return status;
+ set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
+ &dst_lock->open_context->state->flags);
retry:
args->sync = sync;
status = nfs4_call_sync(server->client, server, &msg,
@@ -314,9 +323,12 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
if (err >= 0)
break;
- if (err == -ENOTSUPP) {
+ switch (err) {
+ case -ENOTSUPP:
err = -EOPNOTSUPP;
break;
+ case -EAGAIN:
+ break;
}
err2 = nfs4_handle_exception(server, err, &src_exception);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index af285cc..681c389 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -161,6 +161,10 @@ enum {
NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */
NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */
+#ifdef CONFIG_NFS_V4_2
+ NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
+#endif /* CONFIG_NFS_V4_2 */
+
};
struct nfs4_state {
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 0efba77..881b819 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -133,10 +133,15 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
size_t count, unsigned int flags)
{
+ ssize_t ret;
+
if (file_inode(file_in) == file_inode(file_out))
return -EINVAL;
-
- return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+retry:
+ ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+ if (ret == -EAGAIN)
+ goto retry;
+ return ret;
}
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 8156bad..12dbaf0 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1540,6 +1540,21 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
&state->flags);
nfs4_put_open_state(state);
spin_lock(&sp->so_lock);
+#ifdef CONFIG_NFS_V4_2
+ if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) {
+ struct nfs4_copy_state *copy;
+
+ spin_lock(&sp->so_server->nfs_client->cl_lock);
+ list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
+ if (memcmp(&state->stateid.other, ©->parent_state->stateid.other, NFS4_STATEID_SIZE))
+ continue;
+ copy->flags = 1;
+ complete(©->completion);
+ break;
+ }
+ spin_unlock(&sp->so_server->nfs_client->cl_lock);
+ }
+#endif /* CONFIG_NFS_V4_2 */
goto restart;
}
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index a862b7f..d8164b6 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -189,6 +189,8 @@ struct nfs4_copy_state {
uint64_t count;
struct nfs_writeverf verf;
int error;
+ int flags;
+ struct nfs4_state *parent_state;
};
/*
--
1.8.3.1
^ permalink raw reply related [flat|nested] 13+ messages in thread