Linux-NFS Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v7 00/19] client and server support for "inter" SSC copy
@ 2019-09-16 21:13 Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 01/19] NFS NFSD: defining nl4_servers structure needed by both Olga Kornievskaia
                   ` (19 more replies)
  0 siblings, 20 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

v7:
--- rebased patches ontop of Bruce's nfsd-next

Olga Kornievskaia (19):
  NFS NFSD: defining nl4_servers structure needed by both
  NFS: add COPY_NOTIFY operation
  NFS: add ca_source_server<> to COPY
  NFS: also send OFFLOAD_CANCEL to source server
  NFS: inter ssc open
  NFS: skip recovery of copy open on dest server
  NFS: for "inter" copy treat ESTALE as ENOTSUPP
  NFS: COPY handle ERR_OFFLOAD_DENIED
  NFS: handle source server reboot
  NFS: replace cross device check in copy_file_range
  NFSD fill-in netloc4 structure
  NFSD add ca_source_server<> to COPY
  NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  NFSD COPY_NOTIFY xdr
  NFSD add COPY_NOTIFY operation
  NFSD check stateids against copy stateids
  NFSD generalize nfsd4_compound_state flag names
  NFSD: allow inter server COPY to have a STALE source server fh
  NFSD add nfs4 inter ssc to nfsd4_copy

 fs/nfs/nfs42.h            |  15 +-
 fs/nfs/nfs42proc.c        | 193 ++++++++++++++++----
 fs/nfs/nfs42xdr.c         | 190 +++++++++++++++++++-
 fs/nfs/nfs4_fs.h          |  11 ++
 fs/nfs/nfs4client.c       |   2 +-
 fs/nfs/nfs4file.c         | 125 ++++++++++++-
 fs/nfs/nfs4proc.c         |   6 +-
 fs/nfs/nfs4state.c        |  29 ++-
 fs/nfs/nfs4xdr.c          |   1 +
 fs/nfsd/Kconfig           |  10 ++
 fs/nfsd/nfs4proc.c        | 436 +++++++++++++++++++++++++++++++++++++++++-----
 fs/nfsd/nfs4state.c       | 215 ++++++++++++++++++++---
 fs/nfsd/nfs4xdr.c         | 155 +++++++++++++++-
 fs/nfsd/nfsd.h            |  32 ++++
 fs/nfsd/nfsfh.h           |   5 +-
 fs/nfsd/nfssvc.c          |   6 +
 fs/nfsd/state.h           |  34 +++-
 fs/nfsd/xdr4.h            |  39 ++++-
 include/linux/nfs4.h      |  25 +++
 include/linux/nfs_fs.h    |   3 +-
 include/linux/nfs_fs_sb.h |   1 +
 include/linux/nfs_xdr.h   |  17 ++
 22 files changed, 1429 insertions(+), 121 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 01/19] NFS NFSD: defining nl4_servers structure needed by both
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 02/19] NFS: add COPY_NOTIFY operation Olga Kornievskaia
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

These structures are needed by COPY_NOTIFY on the client and needed
by the nfsd as well

Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 include/linux/nfs4.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index fd59904..5810e24 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/uidgid.h>
 #include <uapi/linux/nfs4.h>
+#include <linux/sunrpc/msg_prot.h>
 
 enum nfs4_acl_whotype {
 	NFS4_ACL_WHO_NAMED = 0,
@@ -674,4 +675,27 @@ struct nfs4_op_map {
 	} u;
 };
 
+struct nfs42_netaddr {
+	char		netid[RPCBIND_MAXNETIDLEN];
+	char		addr[RPCBIND_MAXUADDRLEN + 1];
+	u32		netid_len;
+	u32		addr_len;
+};
+
+enum netloc_type4 {
+	NL4_NAME		= 1,
+	NL4_URL			= 2,
+	NL4_NETADDR		= 3,
+};
+
+struct nl4_server {
+	enum netloc_type4	nl4_type;
+	union {
+		struct { /* NL4_NAME, NL4_URL */
+			int	nl4_str_sz;
+			char	nl4_str[NFS4_OPAQUE_LIMIT + 1];
+		};
+		struct nfs42_netaddr	nl4_addr; /* NL4_NETADDR */
+	} u;
+};
 #endif
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 02/19] NFS: add COPY_NOTIFY operation
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 01/19] NFS NFSD: defining nl4_servers structure needed by both Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 03/19] NFS: add ca_source_server<> to COPY Olga Kornievskaia
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

Try using the delegation stateid, then the open stateid.

Only NL4_NETATTR, No support for NL4_NAME and NL4_URL.
Allow only one source server address to be returned for now.

To distinguish between same server copy offload ("intra") and
a copy between different server ("inter"), do a check of server
owner identity and also make sure server is capable of doing
a copy offload.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs42.h            |  12 ++++
 fs/nfs/nfs42proc.c        |  91 ++++++++++++++++++++++++
 fs/nfs/nfs42xdr.c         | 178 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs4_fs.h          |   2 +
 fs/nfs/nfs4client.c       |   2 +-
 fs/nfs/nfs4file.c         |  20 +++++-
 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   |  16 +++++
 11 files changed, 323 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index 901cca7..4995731 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -13,6 +13,7 @@
 #define PNFS_LAYOUTSTATS_MAXDEV (4)
 
 /* nfs4.2proc.c */
+#ifdef CONFIG_NFS_V4_2
 int nfs42_proc_allocate(struct file *, loff_t, loff_t);
 ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t);
 int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
@@ -23,5 +24,16 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *,
 int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
 			   const struct nfs42_layout_error *errors,
 			   size_t n);
+int nfs42_proc_copy_notify(struct file *, struct file *,
+			   struct nfs42_copy_notify_res *);
+static inline bool nfs42_files_from_same_server(struct file *in,
+						struct file *out)
+{
+	struct nfs_client *c_in = (NFS_SERVER(file_inode(in)))->nfs_client;
+	struct nfs_client *c_out = (NFS_SERVER(file_inode(out)))->nfs_client;
 
+	return nfs4_check_serverowner_major_id(c_in->cl_serverowner,
+					       c_out->cl_serverowner);
+}
+#endif /* CONFIG_NFS_V4_2 */
 #endif /* __LINUX_FS_NFS_NFS4_2_H */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 5196bfa..6317dd8 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
  */
 #include <linux/fs.h>
+#include <linux/sunrpc/addr.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
@@ -15,10 +16,30 @@
 #include "pnfs.h"
 #include "nfs4session.h"
 #include "internal.h"
+#include "delegation.h"
 
 #define NFSDBG_FACILITY NFSDBG_PROC
 static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
 
+static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
+{
+	struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client;
+	unsigned short port = 2049;
+
+	rcu_read_lock();
+	naddr->netid_len = scnprintf(naddr->netid,
+					sizeof(naddr->netid), "%s",
+					rpc_peeraddr2str(clp->cl_rpcclient,
+					RPC_DISPLAY_NETID));
+	naddr->addr_len = scnprintf(naddr->addr,
+					sizeof(naddr->addr),
+					"%s.%u.%u",
+					rpc_peeraddr2str(clp->cl_rpcclient,
+					RPC_DISPLAY_ADDR),
+					port >> 8, port & 255);
+	rcu_read_unlock();
+}
+
 static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 		struct nfs_lock_context *lock, loff_t offset, loff_t len)
 {
@@ -459,6 +480,76 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
 	return status;
 }
 
+int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
+			    struct nfs42_copy_notify_args *args,
+			    struct nfs42_copy_notify_res *res)
+{
+	struct nfs_server *src_server = NFS_SERVER(file_inode(src));
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
+		.rpc_argp = args,
+		.rpc_resp = res,
+	};
+	int status;
+	struct nfs_open_context *ctx;
+	struct nfs_lock_context *l_ctx;
+
+	ctx = get_nfs_open_context(nfs_file_open_context(src));
+	l_ctx = nfs_get_lock_context(ctx);
+	if (IS_ERR(l_ctx))
+		return PTR_ERR(l_ctx);
+
+	status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
+				     FMODE_READ);
+	nfs_put_lock_context(l_ctx);
+	if (status)
+		return status;
+
+	status = nfs4_call_sync(src_server->client, src_server, &msg,
+				&args->cna_seq_args, &res->cnr_seq_res, 0);
+	if (status == -ENOTSUPP)
+		src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
+
+	put_nfs_open_context(nfs_file_open_context(src));
+	return status;
+}
+
+int nfs42_proc_copy_notify(struct file *src, struct file *dst,
+				struct nfs42_copy_notify_res *res)
+{
+	struct nfs_server *src_server = NFS_SERVER(file_inode(src));
+	struct nfs42_copy_notify_args *args;
+	struct nfs4_exception exception = {
+		.inode = file_inode(src),
+	};
+	int status;
+
+	if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
+		return -EOPNOTSUPP;
+
+	args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
+	if (args == NULL)
+		return -ENOMEM;
+
+	args->cna_src_fh  = NFS_FH(file_inode(src)),
+	args->cna_dst.nl4_type = NL4_NETADDR;
+	nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr);
+	exception.stateid = &args->cna_src_stateid;
+
+	do {
+		status = _nfs42_proc_copy_notify(src, dst, args, res);
+		if (status == -ENOTSUPP) {
+			status = -EOPNOTSUPP;
+			goto out;
+		}
+		status = nfs4_handle_exception(src_server, status, &exception);
+	} while (exception.retry);
+
+out:
+	kfree(args);
+	return status;
+}
+
 static loff_t _nfs42_proc_llseek(struct file *filep,
 		struct nfs_lock_context *lock, loff_t offset, int whence)
 {
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index aed865a..ccabc0c 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -29,6 +29,16 @@
 #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_copy_notify_maxsz	(op_encode_hdr_maxsz + \
+					 XDR_QUADLEN(NFS4_STATEID_SIZE) + \
+					 1 + /* nl4_type */ \
+					 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
+#define decode_copy_notify_maxsz	(op_decode_hdr_maxsz + \
+					 3 + /* cnr_lease_time */\
+					 XDR_QUADLEN(NFS4_STATEID_SIZE) + \
+					 1 + /* Support 1 cnr_source_server */\
+					 1 + /* nl4_type */ \
+					 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
 #define encode_deallocate_maxsz		(op_encode_hdr_maxsz + \
 					 encode_fallocate_maxsz)
 #define decode_deallocate_maxsz		(op_decode_hdr_maxsz)
@@ -99,6 +109,12 @@
 					 decode_sequence_maxsz + \
 					 decode_putfh_maxsz + \
 					 decode_offload_cancel_maxsz)
+#define NFS4_enc_copy_notify_sz		(compound_encode_hdr_maxsz + \
+					 encode_putfh_maxsz + \
+					 encode_copy_notify_maxsz)
+#define NFS4_dec_copy_notify_sz		(compound_decode_hdr_maxsz + \
+					 decode_putfh_maxsz + \
+					 decode_copy_notify_maxsz)
 #define NFS4_enc_deallocate_sz		(compound_encode_hdr_maxsz + \
 					 encode_sequence_maxsz + \
 					 encode_putfh_maxsz + \
@@ -166,6 +182,26 @@ static void encode_allocate(struct xdr_stream *xdr,
 	encode_fallocate(xdr, args);
 }
 
+static void encode_nl4_server(struct xdr_stream *xdr,
+			      const struct nl4_server *ns)
+{
+	encode_uint32(xdr, ns->nl4_type);
+	switch (ns->nl4_type) {
+	case NL4_NAME:
+	case NL4_URL:
+		encode_string(xdr, ns->u.nl4_str_sz, ns->u.nl4_str);
+		break;
+	case NL4_NETADDR:
+		encode_string(xdr, ns->u.nl4_addr.netid_len,
+			      ns->u.nl4_addr.netid);
+		encode_string(xdr, ns->u.nl4_addr.addr_len,
+			      ns->u.nl4_addr.addr);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+	}
+}
+
 static void encode_copy(struct xdr_stream *xdr,
 			const struct nfs42_copy_args *args,
 			struct compound_hdr *hdr)
@@ -191,6 +227,15 @@ static void encode_offload_cancel(struct xdr_stream *xdr,
 	encode_nfs4_stateid(xdr, &args->osa_stateid);
 }
 
+static void encode_copy_notify(struct xdr_stream *xdr,
+			       const struct nfs42_copy_notify_args *args,
+			       struct compound_hdr *hdr)
+{
+	encode_op_hdr(xdr, OP_COPY_NOTIFY, decode_copy_notify_maxsz, hdr);
+	encode_nfs4_stateid(xdr, &args->cna_src_stateid);
+	encode_nl4_server(xdr, &args->cna_dst);
+}
+
 static void encode_deallocate(struct xdr_stream *xdr,
 			      const struct nfs42_falloc_args *args,
 			      struct compound_hdr *hdr)
@@ -355,6 +400,25 @@ static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
 }
 
 /*
+ * Encode COPY_NOTIFY request
+ */
+static void nfs4_xdr_enc_copy_notify(struct rpc_rqst *req,
+				     struct xdr_stream *xdr,
+				     const void *data)
+{
+	const struct nfs42_copy_notify_args *args = data;
+	struct compound_hdr hdr = {
+		.minorversion = nfs4_xdr_minorversion(&args->cna_seq_args),
+	};
+
+	encode_compound_hdr(xdr, req, &hdr);
+	encode_sequence(xdr, &args->cna_seq_args, &hdr);
+	encode_putfh(xdr, args->cna_src_fh, &hdr);
+	encode_copy_notify(xdr, args, &hdr);
+	encode_nops(&hdr);
+}
+
+/*
  * Encode DEALLOCATE request
  */
 static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
@@ -490,6 +554,58 @@ static int decode_write_response(struct xdr_stream *xdr,
 	return decode_verifier(xdr, &res->verifier.verifier);
 }
 
+static int decode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns)
+{
+	struct nfs42_netaddr *naddr;
+	uint32_t dummy;
+	char *dummy_str;
+	__be32 *p;
+	int status;
+
+	/* nl_type */
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(!p))
+		return -EIO;
+	ns->nl4_type = be32_to_cpup(p);
+	switch (ns->nl4_type) {
+	case NL4_NAME:
+	case NL4_URL:
+		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+		if (unlikely(status))
+			return status;
+		if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+			return -EIO;
+		memcpy(&ns->u.nl4_str, dummy_str, dummy);
+		ns->u.nl4_str_sz = dummy;
+		break;
+	case NL4_NETADDR:
+		naddr = &ns->u.nl4_addr;
+
+		/* netid string */
+		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+		if (unlikely(status))
+			return status;
+		if (unlikely(dummy > RPCBIND_MAXNETIDLEN))
+			return -EIO;
+		naddr->netid_len = dummy;
+		memcpy(naddr->netid, dummy_str, naddr->netid_len);
+
+		/* uaddr string */
+		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+		if (unlikely(status))
+			return status;
+		if (unlikely(dummy > RPCBIND_MAXUADDRLEN))
+			return -EIO;
+		naddr->addr_len = dummy;
+		memcpy(naddr->addr, dummy_str, naddr->addr_len);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return -EIO;
+	}
+	return 0;
+}
+
 static int decode_copy_requirements(struct xdr_stream *xdr,
 				    struct nfs42_copy_res *res) {
 	__be32 *p;
@@ -529,6 +645,42 @@ static int decode_offload_cancel(struct xdr_stream *xdr,
 	return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
 }
 
+static int decode_copy_notify(struct xdr_stream *xdr,
+			      struct nfs42_copy_notify_res *res)
+{
+	__be32 *p;
+	int status, count;
+
+	status = decode_op_hdr(xdr, OP_COPY_NOTIFY);
+	if (status)
+		return status;
+	/* cnr_lease_time */
+	p = xdr_inline_decode(xdr, 12);
+	if (unlikely(!p))
+		return -EIO;
+	p = xdr_decode_hyper(p, &res->cnr_lease_time.seconds);
+	res->cnr_lease_time.nseconds = be32_to_cpup(p);
+
+	status = decode_opaque_fixed(xdr, &res->cnr_stateid, NFS4_STATEID_SIZE);
+	if (unlikely(status))
+		return -EIO;
+
+	/* number of source addresses */
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(!p))
+		return -EIO;
+
+	count = be32_to_cpup(p);
+	if (count > 1)
+		pr_warn("NFS: %s: nsvr %d > Supported. Use first servers\n",
+			 __func__, count);
+
+	status = decode_nl4_server(xdr, &res->cnr_src);
+	if (unlikely(status))
+		return -EIO;
+	return 0;
+}
+
 static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
 {
 	return decode_op_hdr(xdr, OP_DEALLOCATE);
@@ -657,6 +809,32 @@ static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp,
 }
 
 /*
+ * Decode COPY_NOTIFY response
+ */
+static int nfs4_xdr_dec_copy_notify(struct rpc_rqst *rqstp,
+				    struct xdr_stream *xdr,
+				    void *data)
+{
+	struct nfs42_copy_notify_res *res = data;
+	struct compound_hdr hdr;
+	int status;
+
+	status = decode_compound_hdr(xdr, &hdr);
+	if (status)
+		goto out;
+	status = decode_sequence(xdr, &res->cnr_seq_res, rqstp);
+	if (status)
+		goto out;
+	status = decode_putfh(xdr);
+	if (status)
+		goto out;
+	status = decode_copy_notify(xdr, res);
+
+out:
+	return status;
+}
+
+/*
  * Decode DEALLOCATE request
  */
 static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index d778dad..bd37fff 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -457,6 +457,8 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
 			struct nfs_client **, const struct cred *);
 extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
 extern void nfs41_notify_server(struct nfs_client *);
+bool nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
+			struct nfs41_server_owner *o2);
 #else
 static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 {
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 616393a..6741ad4 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -629,7 +629,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
 /*
  * Returns true if the server major ids match
  */
-static bool
+bool
 nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
 				struct nfs41_server_owner *o2)
 {
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 96db471..8d845ef 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -133,6 +133,9 @@ 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)
 {
+	struct nfs42_copy_notify_res *cn_resp = NULL;
+	ssize_t ret;
+
 	/* Only offload copy if superblock is the same */
 	if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb)
 		return -EXDEV;
@@ -140,7 +143,22 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 		return -EOPNOTSUPP;
 	if (file_inode(file_in) == file_inode(file_out))
 		return -EOPNOTSUPP;
-	return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+	if (!nfs42_files_from_same_server(file_in, file_out)) {
+		cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
+				GFP_NOFS);
+		if (unlikely(cn_resp == NULL))
+			return -ENOMEM;
+
+		ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
+		if (ret) {
+			ret = -EOPNOTSUPP;
+			goto out;
+		}
+	}
+	ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+out:
+	kfree(cn_resp);
+	return ret;
 }
 
 static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 39896af..1012cbe 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9799,6 +9799,7 @@ static bool nfs4_match_stateid(const nfs4_stateid *s1,
 		| NFS_CAP_ALLOCATE
 		| NFS_CAP_COPY
 		| NFS_CAP_OFFLOAD_CANCEL
+		| NFS_CAP_COPY_NOTIFY
 		| NFS_CAP_DEALLOCATE
 		| NFS_CAP_SEEK
 		| NFS_CAP_LAYOUTSTATS
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 46a8d63..d76c772 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7581,6 +7581,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 	PROC42(CLONE,		enc_clone,		dec_clone),
 	PROC42(COPY,		enc_copy,		dec_copy),
 	PROC42(OFFLOAD_CANCEL,	enc_offload_cancel,	dec_offload_cancel),
+	PROC42(COPY_NOTIFY,	enc_copy_notify,	dec_copy_notify),
 	PROC(LOOKUPP,		enc_lookupp,		dec_lookupp),
 	PROC42(LAYOUTERROR,	enc_layouterror,	dec_layouterror),
 };
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 5810e24..5e7a526 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -537,6 +537,7 @@ enum {
 	NFSPROC4_CLNT_CLONE,
 	NFSPROC4_CLNT_COPY,
 	NFSPROC4_CLNT_OFFLOAD_CANCEL,
+	NFSPROC4_CLNT_COPY_NOTIFY,
 
 	NFSPROC4_CLNT_LOOKUPP,
 	NFSPROC4_CLNT_LAYOUTERROR,
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index a87fe85..e1c8748 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -276,5 +276,6 @@ struct nfs_server {
 #define NFS_CAP_COPY		(1U << 24)
 #define NFS_CAP_OFFLOAD_CANCEL	(1U << 25)
 #define NFS_CAP_LAYOUTERROR	(1U << 26)
+#define NFS_CAP_COPY_NOTIFY	(1U << 27)
 
 #endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 9b8324e..0a7af40 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1463,6 +1463,22 @@ struct nfs42_offload_status_res {
 	int				osr_status;
 };
 
+struct nfs42_copy_notify_args {
+	struct nfs4_sequence_args	cna_seq_args;
+
+	struct nfs_fh		*cna_src_fh;
+	nfs4_stateid		cna_src_stateid;
+	struct nl4_server	cna_dst;
+};
+
+struct nfs42_copy_notify_res {
+	struct nfs4_sequence_res	cnr_seq_res;
+
+	struct nfstime4		cnr_lease_time;
+	nfs4_stateid		cnr_stateid;
+	struct nl4_server	cnr_src;
+};
+
 struct nfs42_seek_args {
 	struct nfs4_sequence_args	seq_args;
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 03/19] NFS: add ca_source_server<> to COPY
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 01/19] NFS NFSD: defining nl4_servers structure needed by both Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 02/19] NFS: add COPY_NOTIFY operation Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 04/19] NFS: also send OFFLOAD_CANCEL to source server Olga Kornievskaia
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

Support only one source server address: the same address that
the client and source server use.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs42.h          |  3 ++-
 fs/nfs/nfs42proc.c      | 26 +++++++++++++++++---------
 fs/nfs/nfs42xdr.c       | 12 ++++++++++--
 fs/nfs/nfs4file.c       |  7 ++++++-
 include/linux/nfs_xdr.h |  1 +
 5 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index 4995731..02e3810 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -15,7 +15,8 @@
 /* nfs4.2proc.c */
 #ifdef CONFIG_NFS_V4_2
 int nfs42_proc_allocate(struct file *, loff_t, loff_t);
-ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t);
+ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t,
+			struct nl4_server *, nfs4_stateid *);
 int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
 loff_t nfs42_proc_llseek(struct file *, loff_t, int);
 int nfs42_proc_layoutstats_generic(struct nfs_server *,
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 6317dd8..e34ade8 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -243,7 +243,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 				struct file *dst,
 				struct nfs_lock_context *dst_lock,
 				struct nfs42_copy_args *args,
-				struct nfs42_copy_res *res)
+				struct nfs42_copy_res *res,
+				struct nl4_server *nss,
+				nfs4_stateid *cnr_stateid)
 {
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
@@ -257,11 +259,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 	size_t count = args->count;
 	ssize_t status;
 
-	status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
-				     src_lock, FMODE_READ);
-	if (status)
-		return status;
-
+	if (nss) {
+		args->cp_src = nss;
+		nfs4_stateid_copy(&args->src_stateid, cnr_stateid);
+	} else {
+		status = nfs4_set_rw_stateid(&args->src_stateid,
+				src_lock->open_context, src_lock, FMODE_READ);
+		if (status)
+			return status;
+	}
 	status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
 			pos_src, pos_src + (loff_t)count - 1);
 	if (status)
@@ -325,8 +331,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 }
 
 ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
-			struct file *dst, loff_t pos_dst,
-			size_t count)
+			struct file *dst, loff_t pos_dst, size_t count,
+			struct nl4_server *nss,
+			nfs4_stateid *cnr_stateid)
 {
 	struct nfs_server *server = NFS_SERVER(file_inode(dst));
 	struct nfs_lock_context *src_lock;
@@ -368,7 +375,8 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 		inode_lock(file_inode(dst));
 		err = _nfs42_proc_copy(src, src_lock,
 				dst, dst_lock,
-				&args, &res);
+				&args, &res,
+				nss, cnr_stateid);
 		inode_unlock(file_inode(dst));
 
 		if (err >= 0)
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index ccabc0c..c03f324 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -21,7 +21,10 @@
 #define encode_copy_maxsz		(op_encode_hdr_maxsz +          \
 					 XDR_QUADLEN(NFS4_STATEID_SIZE) + \
 					 XDR_QUADLEN(NFS4_STATEID_SIZE) + \
-					 2 + 2 + 2 + 1 + 1 + 1)
+					 2 + 2 + 2 + 1 + 1 + 1 +\
+					 1 + /* One cnr_source_server */\
+					 1 + /* nl4_type */ \
+					 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
 #define decode_copy_maxsz		(op_decode_hdr_maxsz + \
 					 NFS42_WRITE_RES_SIZE + \
 					 1 /* cr_consecutive */ + \
@@ -216,7 +219,12 @@ static void encode_copy(struct xdr_stream *xdr,
 
 	encode_uint32(xdr, 1); /* consecutive = true */
 	encode_uint32(xdr, args->sync);
-	encode_uint32(xdr, 0); /* src server list */
+	if (args->cp_src == NULL) { /* intra-ssc */
+		encode_uint32(xdr, 0); /* no src server list */
+		return;
+	}
+	encode_uint32(xdr, 1); /* supporting 1 server */
+	encode_nl4_server(xdr, args->cp_src);
 }
 
 static void encode_offload_cancel(struct xdr_stream *xdr,
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 8d845ef..1bec960 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -134,6 +134,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 				      size_t count, unsigned int flags)
 {
 	struct nfs42_copy_notify_res *cn_resp = NULL;
+	struct nl4_server *nss = NULL;
+	nfs4_stateid *cnrs = NULL;
 	ssize_t ret;
 
 	/* Only offload copy if superblock is the same */
@@ -154,8 +156,11 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 			ret = -EOPNOTSUPP;
 			goto out;
 		}
+		nss = &cn_resp->cnr_src;
+		cnrs = &cn_resp->cnr_stateid;
 	}
-	ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+	ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
+				nss, cnrs);
 out:
 	kfree(cn_resp);
 	return ret;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 0a7af40..008faca 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1435,6 +1435,7 @@ struct nfs42_copy_args {
 
 	u64				count;
 	bool				sync;
+	struct nl4_server		*cp_src;
 };
 
 struct nfs42_write_res {
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 04/19] NFS: also send OFFLOAD_CANCEL to source server
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (2 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 03/19] NFS: add ca_source_server<> to COPY Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 05/19] NFS: inter ssc open Olga Kornievskaia
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

In case of copy is cancelled, also send OFFLOAD_CANCEL to the source
server.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs42proc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index e34ade8..bbf7c1e 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -206,12 +206,14 @@ static int handle_async_copy(struct nfs42_copy_res *res,
 	memcpy(&res->write_res.verifier, &copy->verf, sizeof(copy->verf));
 	status = -copy->error;
 
+out_free:
 	kfree(copy);
 	return status;
 out_cancel:
 	nfs42_do_offload_cancel_async(dst, &copy->stateid);
-	kfree(copy);
-	return status;
+	if (!nfs42_files_from_same_server(src, dst))
+		nfs42_do_offload_cancel_async(src, src_stateid);
+	goto out_free;
 }
 
 static int process_copy_commit(struct file *dst, loff_t pos_dst,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 05/19] NFS: inter ssc open
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (3 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 04/19] NFS: also send OFFLOAD_CANCEL to source server Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 06/19] NFS: skip recovery of copy open on dest server Olga Kornievskaia
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

NFSv4.2 inter server to server copy requires the destination server to
READ the data from the source server using the provided stateid and
file handle.

Given an NFSv4 stateid and filehandle from the COPY operaion, provide the
destination server with an NFS client function to create a struct file
suitable for the destiniation server to READ the data to be copied.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Andy Adamson <andros@netapp.com>
---
 fs/nfs/nfs4_fs.h  |  7 +++++
 fs/nfs/nfs4file.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/nfs4proc.c |  5 ++-
 3 files changed, 103 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index bd37fff..8b9f039 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -311,6 +311,13 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
 		const struct nfs_open_context *ctx,
 		const struct nfs_lock_context *l_ctx,
 		fmode_t fmode);
+extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+			     struct nfs_fattr *fattr, struct nfs4_label *label,
+			     struct inode *inode);
+extern int update_open_stateid(struct nfs4_state *state,
+				const nfs4_stateid *open_stateid,
+				const nfs4_stateid *deleg_stateid,
+				fmode_t fmode);
 
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
 		struct nfs_fsinfo *fsinfo);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 1bec960..d9ca8af 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -8,6 +8,7 @@
 #include <linux/file.h>
 #include <linux/falloc.h>
 #include <linux/nfs_fs.h>
+#include <linux/file.h>
 #include "delegation.h"
 #include "internal.h"
 #include "iostat.h"
@@ -286,6 +287,99 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
 out:
 	return ret < 0 ? ret : count;
 }
+
+static int read_name_gen = 1;
+#define SSC_READ_NAME_BODY "ssc_read_%d"
+
+struct file *
+nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
+		nfs4_stateid *stateid)
+{
+	struct nfs_fattr fattr;
+	struct file *filep, *res;
+	struct nfs_server *server;
+	struct inode *r_ino = NULL;
+	struct nfs_open_context *ctx;
+	struct nfs4_state_owner *sp;
+	char *read_name;
+	int len, status = 0;
+
+	server = NFS_SERVER(ss_mnt->mnt_root->d_inode);
+
+	nfs_fattr_init(&fattr);
+
+	status = nfs4_proc_getattr(server, src_fh, &fattr, NULL, NULL);
+	if (status < 0) {
+		res = ERR_PTR(status);
+		goto out;
+	}
+
+	res = ERR_PTR(-ENOMEM);
+	len = strlen(SSC_READ_NAME_BODY) + 16;
+	read_name = kzalloc(len, GFP_NOFS);
+	if (read_name == NULL)
+		goto out;
+	snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
+
+	r_ino = nfs_fhget(ss_mnt->mnt_root->d_inode->i_sb, src_fh, &fattr,
+			NULL);
+	if (IS_ERR(r_ino)) {
+		res = ERR_CAST(r_ino);
+		goto out;
+	}
+
+	filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, FMODE_READ,
+				     r_ino->i_fop);
+	if (IS_ERR(filep)) {
+		res = ERR_CAST(filep);
+		goto out;
+	}
+	filep->f_mode |= FMODE_READ;
+
+	ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode,
+					filep);
+	if (IS_ERR(ctx)) {
+		res = ERR_CAST(ctx);
+		goto out_filep;
+	}
+
+	res = ERR_PTR(-EINVAL);
+	sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL);
+	if (sp == NULL)
+		goto out_ctx;
+
+	ctx->state = nfs4_get_open_state(r_ino, sp);
+	if (ctx->state == NULL)
+		goto out_stateowner;
+
+	set_bit(NFS_OPEN_STATE, &ctx->state->flags);
+	memcpy(&ctx->state->open_stateid.other, &stateid->other,
+	       NFS4_STATEID_OTHER_SIZE);
+	update_open_stateid(ctx->state, stateid, NULL, filep->f_mode);
+
+	nfs_file_set_open_context(filep, ctx);
+	put_nfs_open_context(ctx);
+
+	file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping);
+	res = filep;
+out:
+	return res;
+out_stateowner:
+	nfs4_put_state_owner(sp);
+out_ctx:
+	put_nfs_open_context(ctx);
+out_filep:
+	fput(filep);
+	goto out;
+}
+EXPORT_SYMBOL_GPL(nfs42_ssc_open);
+void nfs42_ssc_close(struct file *filep)
+{
+	struct nfs_open_context *ctx = nfs_file_open_context(filep);
+
+	ctx->state->flags = 0;
+}
+EXPORT_SYMBOL_GPL(nfs42_ssc_close);
 #endif /* CONFIG_NFS_V4_2 */
 
 const struct file_operations nfs4_file_operations = {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1012cbe..b783699 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -91,7 +91,6 @@
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label, struct inode *inode);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label, struct inode *inode);
 static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
 			    struct nfs_fattr *fattr, struct iattr *sattr,
@@ -1705,7 +1704,7 @@ static void nfs_state_clear_delegation(struct nfs4_state *state)
 	write_sequnlock(&state->seqlock);
 }
 
-static int update_open_stateid(struct nfs4_state *state,
+int update_open_stateid(struct nfs4_state *state,
 		const nfs4_stateid *open_stateid,
 		const nfs4_stateid *delegation,
 		fmode_t fmode)
@@ -3997,7 +3996,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 				struct nfs_fattr *fattr, struct nfs4_label *label,
 				struct inode *inode)
 {
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 06/19] NFS: skip recovery of copy open on dest server
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (4 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 05/19] NFS: inter ssc open Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 07/19] NFS: for "inter" copy treat ESTALE as ENOTSUPP Olga Kornievskaia
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Mark the open created for the source file on the destination
server. Then if this open is going thru a recovery, then fail
the recovery as we don't need to be recoving a "fake" open.
We need to fail the ongoing READs and vfs_copy_file_range().

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs4_fs.h   |  1 +
 fs/nfs/nfs4file.c  |  1 +
 fs/nfs/nfs4state.c | 14 ++++++++++++++
 3 files changed, 16 insertions(+)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 8b9f039..f1a7f40 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -168,6 +168,7 @@ enum {
 	NFS_STATE_CHANGE_WAIT,		/* A state changing operation is outstanding */
 #ifdef CONFIG_NFS_V4_2
 	NFS_CLNT_DST_SSC_COPY_STATE,    /* dst server open state on client*/
+	NFS_SRV_SSC_COPY_STATE,		/* ssc state on the dst server */
 #endif /* CONFIG_NFS_V4_2 */
 };
 
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index d9ca8af..b0dbb59 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -352,6 +352,7 @@ struct file *
 	if (ctx->state == NULL)
 		goto out_stateowner;
 
+	set_bit(NFS_SRV_SSC_COPY_STATE, &ctx->state->flags);
 	set_bit(NFS_OPEN_STATE, &ctx->state->flags);
 	memcpy(&ctx->state->open_stateid.other, &stateid->other,
 	       NFS4_STATEID_OTHER_SIZE);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 9afd051..e06a63f 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1606,6 +1606,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
 {
 	struct nfs4_state *state;
 	int status = 0;
+#ifdef CONFIG_NFS_V4_2
+	bool found_ssc_copy_state = false;
+#endif /* CONFIG_NFS_V4_2 */
 
 	/* Note: we rely on the sp->so_states list being ordered 
 	 * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
@@ -1625,6 +1628,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
 			continue;
 		if (state->state == 0)
 			continue;
+#ifdef CONFIG_NFS_V4_2
+		if (test_bit(NFS_SRV_SSC_COPY_STATE, &state->flags)) {
+			nfs4_state_mark_recovery_failed(state, -EIO);
+			found_ssc_copy_state = true;
+			continue;
+		}
+#endif /* CONFIG_NFS_V4_2 */
 		refcount_inc(&state->count);
 		spin_unlock(&sp->so_lock);
 		status = __nfs4_reclaim_open_state(sp, state, ops);
@@ -1671,6 +1681,10 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
 	}
 	raw_write_seqcount_end(&sp->so_reclaim_seqcount);
 	spin_unlock(&sp->so_lock);
+#ifdef CONFIG_NFS_V4_2
+	if (found_ssc_copy_state)
+		return -EIO;
+#endif /* CONFIG_NFS_V4_2 */
 	return 0;
 out_err:
 	nfs4_put_open_state(state);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 07/19] NFS: for "inter" copy treat ESTALE as ENOTSUPP
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (5 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 06/19] NFS: skip recovery of copy open on dest server Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 08/19] NFS: COPY handle ERR_OFFLOAD_DENIED Olga Kornievskaia
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

If the client sends an "inter" copy to the destination server but
it only supports "intra" copy, it can return ESTALE (since it
doesn't know anything about the file handle from the other server
and does not recognize the special case of "inter" copy). Translate
this error as ENOTSUPP and also send OFFLOAD_CANCEL to the source
server so that it can clean up state.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs42proc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index bbf7c1e..f8ebd77 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -393,6 +393,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 			args.sync = true;
 			dst_exception.retry = 1;
 			continue;
+		} else if (err == -ESTALE &&
+				!nfs42_files_from_same_server(src, dst)) {
+			nfs42_do_offload_cancel_async(src, &args.src_stateid);
+			err = -EOPNOTSUPP;
+			break;
 		}
 
 		err2 = nfs4_handle_exception(server, err, &src_exception);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 08/19] NFS: COPY handle ERR_OFFLOAD_DENIED
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (6 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 07/19] NFS: for "inter" copy treat ESTALE as ENOTSUPP Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 09/19] NFS: handle source server reboot Olga Kornievskaia
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

If server sends ERR_OFFLOAD_DENIED error, the client must fall
back on doing copy the normal way. Return ENOTSUPP to the vfs and
fallback to regular copy.

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 f8ebd77..705fe69 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -393,7 +393,8 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 			args.sync = true;
 			dst_exception.retry = 1;
 			continue;
-		} else if (err == -ESTALE &&
+		} else if ((err == -ESTALE ||
+				err == -NFS4ERR_OFFLOAD_DENIED) &&
 				!nfs42_files_from_same_server(src, dst)) {
 			nfs42_do_offload_cancel_async(src, &args.src_stateid);
 			err = -EOPNOTSUPP;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 09/19] NFS: handle source server reboot
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (7 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 08/19] NFS: COPY handle ERR_OFFLOAD_DENIED Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 10/19] NFS: replace cross device check in copy_file_range Olga Kornievskaia
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

When the source server reboots after a server-to-server copy was
issued, we need to retry the copy from COPY_NOTIFY. We need to
detect that the source server rebooted and there is a copy waiting
on a destination server and wake it up.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs42proc.c     | 68 ++++++++++++++++++++++++++++++++++----------------
 fs/nfs/nfs4_fs.h       |  1 +
 fs/nfs/nfs4file.c      |  3 +++
 fs/nfs/nfs4state.c     | 15 ++++++++---
 include/linux/nfs_fs.h |  3 ++-
 5 files changed, 64 insertions(+), 26 deletions(-)

diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 705fe69..918dd78 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -153,22 +153,26 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
 }
 
 static int handle_async_copy(struct nfs42_copy_res *res,
-			     struct nfs_server *server,
+			     struct nfs_server *dst_server,
+			     struct nfs_server *src_server,
 			     struct file *src,
 			     struct file *dst,
-			     nfs4_stateid *src_stateid)
+			     nfs4_stateid *src_stateid,
+			     bool *restart)
 {
 	struct nfs4_copy_state *copy, *tmp_copy;
 	int status = NFS4_OK;
 	bool found_pending = false;
-	struct nfs_open_context *ctx = nfs_file_open_context(dst);
+	struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
+	struct nfs_open_context *src_ctx = nfs_file_open_context(src);
 
 	copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
 	if (!copy)
 		return -ENOMEM;
 
-	spin_lock(&server->nfs_client->cl_lock);
-	list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
+	spin_lock(&dst_server->nfs_client->cl_lock);
+	list_for_each_entry(tmp_copy,
+				&dst_server->nfs_client->pending_cb_stateids,
 				copies) {
 		if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
 				NFS4_STATEID_SIZE))
@@ -178,7 +182,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
 		break;
 	}
 	if (found_pending) {
-		spin_unlock(&server->nfs_client->cl_lock);
+		spin_unlock(&dst_server->nfs_client->cl_lock);
 		kfree(copy);
 		copy = tmp_copy;
 		goto out;
@@ -186,19 +190,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
 
 	memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
 	init_completion(&copy->completion);
-	copy->parent_state = ctx->state;
+	copy->parent_dst_state = dst_ctx->state;
+	copy->parent_src_state = src_ctx->state;
+
+	list_add_tail(&copy->copies, &dst_server->ss_copies);
+	spin_unlock(&dst_server->nfs_client->cl_lock);
 
-	list_add_tail(&copy->copies, &server->ss_copies);
-	spin_unlock(&server->nfs_client->cl_lock);
+	if (dst_server != src_server) {
+		spin_lock(&src_server->nfs_client->cl_lock);
+		list_add_tail(&copy->copies, &src_server->ss_copies);
+		spin_unlock(&src_server->nfs_client->cl_lock);
+	}
 
 	status = wait_for_completion_interruptible(&copy->completion);
-	spin_lock(&server->nfs_client->cl_lock);
+	spin_lock(&dst_server->nfs_client->cl_lock);
 	list_del_init(&copy->copies);
-	spin_unlock(&server->nfs_client->cl_lock);
+	spin_unlock(&dst_server->nfs_client->cl_lock);
+	if (dst_server != src_server) {
+		spin_lock(&src_server->nfs_client->cl_lock);
+		list_del_init(&copy->copies);
+		spin_unlock(&src_server->nfs_client->cl_lock);
+	}
 	if (status == -ERESTARTSYS) {
 		goto out_cancel;
-	} else if (copy->flags) {
+	} else if (copy->flags && copy->error) {
 		status = -EAGAIN;
+		*restart = true;
 		goto out_cancel;
 	}
 out:
@@ -247,7 +264,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 				struct nfs42_copy_args *args,
 				struct nfs42_copy_res *res,
 				struct nl4_server *nss,
-				nfs4_stateid *cnr_stateid)
+				nfs4_stateid *cnr_stateid,
+				bool *restart)
 {
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
@@ -255,7 +273,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 		.rpc_resp = res,
 	};
 	struct inode *dst_inode = file_inode(dst);
-	struct nfs_server *server = NFS_SERVER(dst_inode);
+	struct inode *src_inode = file_inode(src);
+	struct nfs_server *dst_server = NFS_SERVER(dst_inode);
+	struct nfs_server *src_server = NFS_SERVER(src_inode);
 	loff_t pos_src = args->src_pos;
 	loff_t pos_dst = args->dst_pos;
 	size_t count = args->count;
@@ -291,13 +311,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 		if (!res->commit_res.verf)
 			return -ENOMEM;
 	}
+	set_bit(NFS_CLNT_SRC_SSC_COPY_STATE,
+		&src_lock->open_context->state->flags);
 	set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
 		&dst_lock->open_context->state->flags);
 
-	status = nfs4_call_sync(server->client, server, &msg,
+	status = nfs4_call_sync(dst_server->client, dst_server, &msg,
 				&args->seq_args, &res->seq_res, 0);
 	if (status == -ENOTSUPP)
-		server->caps &= ~NFS_CAP_COPY;
+		dst_server->caps &= ~NFS_CAP_COPY;
 	if (status)
 		goto out;
 
@@ -309,8 +331,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
 	}
 
 	if (!res->synchronous) {
-		status = handle_async_copy(res, server, src, dst,
-				&args->src_stateid);
+		status = handle_async_copy(res, dst_server, src_server, src,
+				dst, &args->src_stateid, restart);
 		if (status)
 			return status;
 	}
@@ -358,6 +380,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 		.stateid	= &args.dst_stateid,
 	};
 	ssize_t err, err2;
+	bool restart = false;
 
 	src_lock = nfs_get_lock_context(nfs_file_open_context(src));
 	if (IS_ERR(src_lock))
@@ -378,7 +401,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 		err = _nfs42_proc_copy(src, src_lock,
 				dst, dst_lock,
 				&args, &res,
-				nss, cnr_stateid);
+				nss, cnr_stateid, &restart);
 		inode_unlock(file_inode(dst));
 
 		if (err >= 0)
@@ -387,8 +410,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 			err = -EOPNOTSUPP;
 			break;
 		} else if (err == -EAGAIN) {
-			dst_exception.retry = 1;
-			continue;
+			if (!restart) {
+				dst_exception.retry = 1;
+				continue;
+			}
+			break;
 		} else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
 			args.sync = true;
 			dst_exception.retry = 1;
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index f1a7f40..fec976e 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -168,6 +168,7 @@ enum {
 	NFS_STATE_CHANGE_WAIT,		/* A state changing operation is outstanding */
 #ifdef CONFIG_NFS_V4_2
 	NFS_CLNT_DST_SSC_COPY_STATE,    /* dst server open state on client*/
+	NFS_CLNT_SRC_SSC_COPY_STATE,    /* src server open state on client*/
 	NFS_SRV_SSC_COPY_STATE,		/* ssc state on the dst server */
 #endif /* CONFIG_NFS_V4_2 */
 };
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index b0dbb59..d02b25d 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -146,6 +146,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 		return -EOPNOTSUPP;
 	if (file_inode(file_in) == file_inode(file_out))
 		return -EOPNOTSUPP;
+retry:
 	if (!nfs42_files_from_same_server(file_in, file_out)) {
 		cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
 				GFP_NOFS);
@@ -164,6 +165,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 				nss, cnrs);
 out:
 	kfree(cn_resp);
+	if (ret == -EAGAIN)
+		goto retry;
 	return ret;
 }
 
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e06a63f..881ce7b 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1554,15 +1554,22 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state
 {
 	struct nfs4_copy_state *copy;
 
-	if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags))
+	if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
+		!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
 		return;
 
 	spin_lock(&sp->so_server->nfs_client->cl_lock);
 	list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
-		if (!nfs4_stateid_match_other(&state->stateid, &copy->parent_state->stateid))
-			continue;
+		if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
+				!nfs4_stateid_match_other(&state->stateid,
+				&copy->parent_src_state->stateid)) ||
+		    (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
+				!nfs4_stateid_match_other(&state->stateid,
+				&copy->parent_dst_state->stateid)))
+				continue;
 		copy->flags = 1;
-		complete(&copy->completion);
+		if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags))
+			complete(&copy->completion);
 		break;
 	}
 	spin_unlock(&sp->so_server->nfs_client->cl_lock);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 0a11712..6ff1ec7 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -195,7 +195,8 @@ struct nfs4_copy_state {
 	struct nfs_writeverf	verf;
 	int			error;
 	int			flags;
-	struct nfs4_state	*parent_state;
+	struct nfs4_state	*parent_src_state;
+	struct nfs4_state	*parent_dst_state;
 };
 
 /*
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 10/19] NFS: replace cross device check in copy_file_range
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (8 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 09/19] NFS: handle source server reboot Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 11/19] NFSD fill-in netloc4 structure Olga Kornievskaia
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

Add a check to disallow cross file systems copy offload, both
files are expected to be of NFS4.2+ type.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfs/nfs4file.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index d02b25d..bf70dee 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -140,7 +140,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
 	ssize_t ret;
 
 	/* Only offload copy if superblock is the same */
-	if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb)
+	if (file_in->f_op != &nfs4_file_operations)
 		return -EXDEV;
 	if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY))
 		return -EOPNOTSUPP;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 11/19] NFSD fill-in netloc4 structure
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (9 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 10/19] NFS: replace cross device check in copy_file_range Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 12/19] NFSD add ca_source_server<> to COPY Olga Kornievskaia
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

nfs.4 defines nfs42_netaddr structure that represents netloc4.

Populate needed fields from the sockaddr structure.

This will be used by flexfiles and 4.2 inter copy

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfsd.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index af29475..687f8e1 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -19,6 +19,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/sunrpc/msg_prot.h>
+#include <linux/sunrpc/addr.h>
 
 #include <uapi/linux/nfsd/debug.h>
 
@@ -386,6 +387,37 @@ static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
 
 extern const u32 nfsd_suppattrs[3][3];
 
+static inline u32 nfsd4_set_netaddr(struct sockaddr *addr,
+				    struct nfs42_netaddr *netaddr)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+	unsigned int port;
+	size_t ret_addr, ret_port;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		port = ntohs(sin->sin_port);
+		sprintf(netaddr->netid, "tcp");
+		netaddr->netid_len = 3;
+		break;
+	case AF_INET6:
+		port = ntohs(sin6->sin6_port);
+		sprintf(netaddr->netid, "tcp6");
+		netaddr->netid_len = 4;
+		break;
+	default:
+		return nfserr_inval;
+	}
+	ret_addr = rpc_ntop(addr, netaddr->addr, sizeof(netaddr->addr));
+	ret_port = snprintf(netaddr->addr + ret_addr,
+			    RPCBIND_MAXUADDRLEN + 1 - ret_addr,
+			    ".%u.%u", port >> 8, port & 0xff);
+	WARN_ON(ret_port >= RPCBIND_MAXUADDRLEN + 1 - ret_addr);
+	netaddr->addr_len = ret_addr + ret_port;
+	return 0;
+}
+
 static inline bool bmval_is_subset(const u32 *bm1, const u32 *bm2)
 {
 	return !((bm1[0] & ~bm2[0]) ||
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 12/19] NFSD add ca_source_server<> to COPY
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (10 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 11/19] NFSD fill-in netloc4 structure Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op Olga Kornievskaia
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Decode the ca_source_server list that's sent but only use the
first one. Presence of non-zero list indicates an "inter" copy.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4xdr.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/nfsd/xdr4.h    | 12 +++++-----
 2 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c1fc264..3eccc81 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -40,6 +40,7 @@
 #include <linux/utsname.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/svcauth_gss.h>
+#include <linux/sunrpc/addr.h>
 
 #include "idmap.h"
 #include "acl.h"
@@ -1744,10 +1745,47 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str
 	DECODE_TAIL;
 }
 
+static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
+				      struct nl4_server *ns)
+{
+	DECODE_HEAD;
+	struct nfs42_netaddr *naddr;
+
+	READ_BUF(4);
+	ns->nl4_type = be32_to_cpup(p++);
+
+	/* currently support for 1 inter-server source server */
+	switch (ns->nl4_type) {
+	case NL4_NETADDR:
+		naddr = &ns->u.nl4_addr;
+
+		READ_BUF(4);
+		naddr->netid_len = be32_to_cpup(p++);
+		if (naddr->netid_len > RPCBIND_MAXNETIDLEN)
+			goto xdr_error;
+
+		READ_BUF(naddr->netid_len + 4); /* 4 for uaddr len */
+		COPYMEM(naddr->netid, naddr->netid_len);
+
+		naddr->addr_len = be32_to_cpup(p++);
+		if (naddr->addr_len > RPCBIND_MAXUADDRLEN)
+			goto xdr_error;
+
+		READ_BUF(naddr->addr_len);
+		COPYMEM(naddr->addr, naddr->addr_len);
+		break;
+	default:
+		goto xdr_error;
+	}
+	DECODE_TAIL;
+}
+
 static __be32
 nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
 {
 	DECODE_HEAD;
+	struct nl4_server *ns_dummy;
+	int i, count;
 
 	status = nfsd4_decode_stateid(argp, &copy->cp_src_stateid);
 	if (status)
@@ -1762,7 +1800,32 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str
 	p = xdr_decode_hyper(p, &copy->cp_count);
 	p++; /* ca_consecutive: we always do consecutive copies */
 	copy->cp_synchronous = be32_to_cpup(p++);
-	/* tmp = be32_to_cpup(p); Source server list not supported */
+
+	count = be32_to_cpup(p++);
+
+	copy->cp_intra = false;
+	if (count == 0) { /* intra-server copy */
+		copy->cp_intra = true;
+		goto intra;
+	}
+
+	/* decode all the supplied server addresses but use first */
+	status = nfsd4_decode_nl4_server(argp, &copy->cp_src);
+	if (status)
+		return status;
+
+	ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
+	if (ns_dummy == NULL)
+		return nfserrno(-ENOMEM);
+	for (i = 0; i < count - 1; i++) {
+		status = nfsd4_decode_nl4_server(argp, ns_dummy);
+		if (status) {
+			kfree(ns_dummy);
+			return status;
+		}
+	}
+	kfree(ns_dummy);
+intra:
 
 	DECODE_TAIL;
 }
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index f4737d6..e815a9c 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -518,11 +518,13 @@ struct nfsd42_write_res {
 
 struct nfsd4_copy {
 	/* request */
-	stateid_t	cp_src_stateid;
-	stateid_t	cp_dst_stateid;
-	u64		cp_src_pos;
-	u64		cp_dst_pos;
-	u64		cp_count;
+	stateid_t		cp_src_stateid;
+	stateid_t		cp_dst_stateid;
+	u64			cp_src_pos;
+	u64			cp_dst_pos;
+	u64			cp_count;
+	struct nl4_server	cp_src;
+	bool			cp_intra;
 
 	/* both */
 	bool		cp_synchronous;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (11 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 12/19] NFSD add ca_source_server<> to COPY Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-10-02 15:52   ` bfields
  2019-09-16 21:13 ` [PATCH v7 14/19] NFSD COPY_NOTIFY xdr Olga Kornievskaia
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Needed for copy to add nfs4_cp_state to the nfs4_stid.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4proc.c  | 21 +++++++++++----------
 fs/nfsd/nfs4state.c | 11 ++++++++---
 fs/nfsd/state.h     |  3 ++-
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4e3e77b..6c0d216 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -776,7 +776,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 	/* check stateid */
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
 					&read->rd_stateid, RD_STATE,
-					&read->rd_nf);
+					&read->rd_nf, NULL);
 	if (status) {
 		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
 		goto out;
@@ -948,7 +948,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
 		status = nfs4_preprocess_stateid_op(rqstp, cstate,
 				&cstate->current_fh, &setattr->sa_stateid,
-				WR_STATE, NULL);
+				WR_STATE, NULL, NULL);
 		if (status) {
 			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
 			return status;
@@ -999,7 +999,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 	trace_nfsd_write_start(rqstp, &cstate->current_fh,
 			       write->wr_offset, cnt);
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
-						stateid, WR_STATE, &nf);
+						stateid, WR_STATE, &nf, NULL);
 	if (status) {
 		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
 		return status;
@@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 static __be32
 nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		  stateid_t *src_stateid, struct nfsd_file **src,
-		  stateid_t *dst_stateid, struct nfsd_file **dst)
+		  stateid_t *dst_stateid, struct nfsd_file **dst,
+		  struct nfs4_stid **stid)
 {
 	__be32 status;
 
@@ -1034,14 +1035,14 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 		return nfserr_nofilehandle;
 
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
-					    src_stateid, RD_STATE, src);
+					    src_stateid, RD_STATE, src, NULL);
 	if (status) {
 		dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
 		goto out;
 	}
 
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
-					    dst_stateid, WR_STATE, dst);
+					    dst_stateid, WR_STATE, dst, stid);
 	if (status) {
 		dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
 		goto out_put_src;
@@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 	__be32 status;
 
 	status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
-				   &clone->cl_dst_stateid, &dst);
+				   &clone->cl_dst_stateid, &dst, NULL);
 	if (status)
 		goto out;
 
@@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
 
 	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
 				   &copy->nf_src, &copy->cp_dst_stateid,
-				   &copy->nf_dst);
+				   &copy->nf_dst, NULL);
 	if (status)
 		goto out;
 
@@ -1346,7 +1347,7 @@ struct nfsd4_copy *
 
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
 					    &fallocate->falloc_stateid,
-					    WR_STATE, &nf);
+					    WR_STATE, &nf, NULL);
 	if (status != nfs_ok) {
 		dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
 		return status;
@@ -1405,7 +1406,7 @@ struct nfsd4_copy *
 
 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
 					    &seek->seek_stateid,
-					    RD_STATE, &nf);
+					    RD_STATE, &nf, NULL);
 	if (status) {
 		dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
 		return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index da1093d..78e03af 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5584,7 +5584,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 __be32
 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
-		stateid_t *stateid, int flags, struct nfsd_file **nfp)
+		stateid_t *stateid, int flags, struct nfsd_file **nfp,
+		struct nfs4_stid **cstid)
 {
 	struct inode *ino = d_inode(fhp->fh_dentry);
 	struct net *net = SVC_NET(rqstp);
@@ -5633,8 +5634,12 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 	if (status == nfs_ok && nfp)
 		status = nfs4_check_file(rqstp, fhp, s, nfp, flags);
 out:
-	if (s)
-		nfs4_put_stid(s);
+	if (s) {
+		if (!status && cstid)
+			*cstid = s;
+		else
+			nfs4_put_stid(s);
+	}
 	return status;
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 46f56af..d9e7cbd 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -617,7 +617,8 @@ struct nfsd4_blocked_lock {
 
 extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
-		stateid_t *stateid, int flags, struct nfsd_file **filp);
+		stateid_t *stateid, int flags, struct nfsd_file **filp,
+		struct nfs4_stid **cstid);
 __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 		     stateid_t *stateid, unsigned char typemask,
 		     struct nfs4_stid **s, struct nfsd_net *nn);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 14/19] NFSD COPY_NOTIFY xdr
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (12 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 15/19] NFSD add COPY_NOTIFY operation Olga Kornievskaia
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4proc.c | 28 +++++++++++++++++
 fs/nfsd/nfs4xdr.c  | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/nfsd/xdr4.h     | 13 ++++++++
 3 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6c0d216..05519a2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1339,6 +1339,13 @@ struct nfsd4_copy *
 }
 
 static __be32
+nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+		  union nfsd4_op_u *u)
+{
+	return nfserr_notsupp;
+}
+
+static __be32
 nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		struct nfsd4_fallocate *fallocate, int flags)
 {
@@ -2291,6 +2298,21 @@ static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp,
 		1 /* osr_complete<1> optional 0 for now */) * sizeof(__be32);
 }
 
+static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp,
+					struct nfsd4_op *op)
+{
+	return (op_encode_hdr_size +
+		3 /* cnr_lease_time */ +
+		1 /* We support one cnr_source_server */ +
+		1 /* cnr_stateid seq */ +
+		op_encode_stateid_maxsz /* cnr_stateid */ +
+		1 /* num cnr_source_server*/ +
+		1 /* nl4_type */ +
+		1 /* nl4 size */ +
+		XDR_QUADLEN(NFS4_OPAQUE_LIMIT) /*nl4_loc + nl4_loc_sz */)
+		* sizeof(__be32);
+}
+
 #ifdef CONFIG_NFSD_PNFS
 static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
@@ -2715,6 +2737,12 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 		.op_name = "OP_OFFLOAD_CANCEL",
 		.op_rsize_bop = nfsd4_only_status_rsize,
 	},
+	[OP_COPY_NOTIFY] = {
+		.op_func = nfsd4_copy_notify,
+		.op_flags = OP_MODIFIES_SOMETHING,
+		.op_name = "OP_COPY_NOTIFY",
+		.op_rsize_bop = nfsd4_copy_notify_rsize,
+	},
 };
 
 /**
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 3eccc81..ab6ca65 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1838,6 +1838,18 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
 }
 
 static __be32
+nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
+			 struct nfsd4_copy_notify *cn)
+{
+	int status;
+
+	status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid);
+	if (status)
+		return status;
+	return nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
+}
+
+static __be32
 nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
 {
 	DECODE_HEAD;
@@ -1938,7 +1950,7 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
 	/* new operations for NFSv4.2 */
 	[OP_ALLOCATE]		= (nfsd4_dec)nfsd4_decode_fallocate,
 	[OP_COPY]		= (nfsd4_dec)nfsd4_decode_copy,
-	[OP_COPY_NOTIFY]	= (nfsd4_dec)nfsd4_decode_notsupp,
+	[OP_COPY_NOTIFY]	= (nfsd4_dec)nfsd4_decode_copy_notify,
 	[OP_DEALLOCATE]		= (nfsd4_dec)nfsd4_decode_fallocate,
 	[OP_IO_ADVISE]		= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_LAYOUTERROR]	= (nfsd4_dec)nfsd4_decode_notsupp,
@@ -4323,6 +4335,46 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 }
 
 static __be32
+nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
+{
+	struct xdr_stream *xdr = &resp->xdr;
+	struct nfs42_netaddr *addr;
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, 4);
+	*p++ = cpu_to_be32(ns->nl4_type);
+
+	switch (ns->nl4_type) {
+	case NL4_NETADDR:
+		addr = &ns->u.nl4_addr;
+
+		/* netid_len, netid, uaddr_len, uaddr (port included
+		 * in RPCBIND_MAXUADDRLEN)
+		 */
+		p = xdr_reserve_space(xdr,
+			4 /* netid len */ +
+			(XDR_QUADLEN(addr->netid_len) * 4) +
+			4 /* uaddr len */ +
+			(XDR_QUADLEN(addr->addr_len) * 4));
+		if (!p)
+			return nfserr_resource;
+
+		*p++ = cpu_to_be32(addr->netid_len);
+		p = xdr_encode_opaque_fixed(p, addr->netid,
+					    addr->netid_len);
+		*p++ = cpu_to_be32(addr->addr_len);
+		p = xdr_encode_opaque_fixed(p, addr->addr,
+					addr->addr_len);
+		break;
+	default:
+		WARN_ON_ONCE(ns->nl4_type != NL4_NETADDR);
+		return nfserr_inval;
+	}
+
+	return 0;
+}
+
+static __be32
 nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
 		  struct nfsd4_copy *copy)
 {
@@ -4356,6 +4408,40 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 }
 
 static __be32
+nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
+			 struct nfsd4_copy_notify *cn)
+{
+	struct xdr_stream *xdr = &resp->xdr;
+	__be32 *p;
+
+	if (nfserr)
+		return nfserr;
+
+	/* 8 sec, 4 nsec */
+	p = xdr_reserve_space(xdr, 12);
+	if (!p)
+		return nfserr_resource;
+
+	/* cnr_lease_time */
+	p = xdr_encode_hyper(p, cn->cpn_sec);
+	*p++ = cpu_to_be32(cn->cpn_nsec);
+
+	/* cnr_stateid */
+	nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_cnr_stateid);
+	if (nfserr)
+		return nfserr;
+
+	/* cnr_src.nl_nsvr */
+	p = xdr_reserve_space(xdr, 4);
+	if (!p)
+		return nfserr_resource;
+
+	*p++ = cpu_to_be32(1);
+
+	return nfsd42_encode_nl4_server(resp, &cn->cpn_src);
+}
+
+static __be32
 nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
 		  struct nfsd4_seek *seek)
 {
@@ -4452,7 +4538,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 	/* NFSv4.2 operations */
 	[OP_ALLOCATE]		= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_COPY]		= (nfsd4_enc)nfsd4_encode_copy,
-	[OP_COPY_NOTIFY]	= (nfsd4_enc)nfsd4_encode_noop,
+	[OP_COPY_NOTIFY]	= (nfsd4_enc)nfsd4_encode_copy_notify,
 	[OP_DEALLOCATE]		= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_IO_ADVISE]		= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_LAYOUTERROR]	= (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index e815a9c..8231fe0 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -570,6 +570,18 @@ struct nfsd4_offload_status {
 	u32		status;
 };
 
+struct nfsd4_copy_notify {
+	/* request */
+	stateid_t		cpn_src_stateid;
+	struct nl4_server	cpn_dst;
+
+	/* response */
+	stateid_t		cpn_cnr_stateid;
+	u64			cpn_sec;
+	u32			cpn_nsec;
+	struct nl4_server	cpn_src;
+};
+
 struct nfsd4_op {
 	int					opnum;
 	const struct nfsd4_operation *		opdesc;
@@ -629,6 +641,7 @@ struct nfsd4_op {
 		struct nfsd4_clone		clone;
 		struct nfsd4_copy		copy;
 		struct nfsd4_offload_status	offload_status;
+		struct nfsd4_copy_notify	copy_notify;
 		struct nfsd4_seek		seek;
 	} u;
 	struct nfs4_replay *			replay;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 15/19] NFSD add COPY_NOTIFY operation
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (13 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 14/19] NFSD COPY_NOTIFY xdr Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-10-01 20:59   ` bfields
  2019-09-16 21:13 ` [PATCH v7 16/19] NFSD check stateids against copy stateids Olga Kornievskaia
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Introducing the COPY_NOTIFY operation.

Create a new unique stateid that will keep track of the copy
state and the upcoming READs that will use that stateid.
Each associated parent stateid has a list of copy
notify stateids. A copy notify structure makes a copy of
the parent stateid and a clientid and will use it to look
up the parent stateid during the READ request (suggested
by Trond Myklebust <trond.myklebust@hammerspace.com>).

At nfs4_put_stid() time, we walk the list of the associated
copy notify stateids and delete them.

Laundromat thread will traverse globally stored copy notify
stateid in idr and notice if any haven't been referenced in the
lease period, if so, it'll remove them.

Return single netaddr to advertise to the copy.

Suggested-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Andy Adamson <andros@netapp.com>
---
 fs/nfsd/nfs4proc.c  |  44 ++++++++++++++++++--
 fs/nfsd/nfs4state.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/state.h     |  28 ++++++++++++-
 fs/nfsd/xdr4.h      |   2 +-
 4 files changed, 178 insertions(+), 14 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 05519a2..75ecdbd 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -37,6 +37,7 @@
 #include <linux/falloc.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/sunrpc/addr.h>
 
 #include "idmap.h"
 #include "cache.h"
@@ -1221,7 +1222,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
 
 static void cleanup_async_copy(struct nfsd4_copy *copy)
 {
-	nfs4_free_cp_state(copy);
+	nfs4_free_copy_state(copy);
 	nfsd_file_put(copy->nf_dst);
 	nfsd_file_put(copy->nf_src);
 	spin_lock(&copy->cp_clp->async_lock);
@@ -1275,7 +1276,7 @@ static int nfsd4_do_async_copy(void *data)
 		async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
 		if (!async_copy)
 			goto out;
-		if (!nfs4_init_cp_state(nn, copy)) {
+		if (!nfs4_init_copy_state(nn, copy)) {
 			kfree(async_copy);
 			goto out;
 		}
@@ -1342,7 +1343,44 @@ struct nfsd4_copy *
 nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		  union nfsd4_op_u *u)
 {
-	return nfserr_notsupp;
+	struct nfsd4_copy_notify *cn = &u->copy_notify;
+	__be32 status;
+	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+	struct nfs4_stid *stid;
+	struct nfs4_cpntf_state *cps;
+	struct nfs4_client *clp = cstate->clp;
+
+	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+					&cn->cpn_src_stateid, RD_STATE, NULL,
+					&stid);
+	if (status)
+		return status;
+
+	cn->cpn_sec = nn->nfsd4_lease;
+	cn->cpn_nsec = 0;
+
+	status = nfserrno(-ENOMEM);
+	cps = nfs4_alloc_init_cpntf_state(nn, stid);
+	if (!cps)
+		goto out;
+	memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.stid, sizeof(stateid_t));
+	memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t));
+	memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t));
+
+	/* For now, only return one server address in cpn_src, the
+	 * address used by the client to connect to this server.
+	 */
+	cn->cpn_src.nl4_type = NL4_NETADDR;
+	status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
+				 &cn->cpn_src.u.nl4_addr);
+	WARN_ON_ONCE(status);
+	if (status) {
+		nfs4_put_cpntf_state(nn, cps);
+		goto out;
+	}
+out:
+	nfs4_put_stid(stid);
+	return status;
 }
 
 static __be32
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 78e03af..857133f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -80,6 +80,7 @@
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
 static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
 void nfsd4_end_grace(struct nfsd_net *nn);
+static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
 
 /* Locking: */
 
@@ -722,6 +723,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
 	/* Will be incremented before return to client: */
 	refcount_set(&stid->sc_count, 1);
 	spin_lock_init(&stid->sc_lock);
+	INIT_LIST_HEAD(&stid->sc_cp_list);
 
 	/*
 	 * It shouldn't be a problem to reuse an opaque stateid value.
@@ -741,30 +743,76 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
 /*
  * Create a unique stateid_t to represent each COPY.
  */
-int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
+static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid,
+			      unsigned char sc_type)
 {
 	int new_id;
 
+	stid->stid.si_opaque.so_clid.cl_boot = nn->boot_time;
+	stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id;
+	stid->sc_type = sc_type;
+
 	idr_preload(GFP_KERNEL);
 	spin_lock(&nn->s2s_cp_lock);
-	new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, copy, 0, 0, GFP_NOWAIT);
+	new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT);
+	stid->stid.si_opaque.so_id = new_id;
 	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)
+int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
+{
+	return nfs4_init_cp_state(nn, &copy->cp_stateid, NFS4_COPY_STID);
+}
+
+struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
+						     struct nfs4_stid *p_stid)
+{
+	struct nfs4_cpntf_state *cps;
+
+	cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL);
+	if (!cps)
+		return NULL;
+	cps->cpntf_time = get_seconds();
+	refcount_set(&cps->cp_stateid.sc_count, 1);
+	if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID))
+		goto out_free;
+	spin_lock(&nn->s2s_cp_lock);
+	list_add(&cps->cp_list, &p_stid->sc_cp_list);
+	spin_unlock(&nn->s2s_cp_lock);
+	return cps;
+out_free:
+	kfree(cps);
+	return NULL;
+}
+
+void nfs4_free_copy_state(struct nfsd4_copy *copy)
 {
 	struct nfsd_net *nn;
 
+	WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID);
 	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);
+	idr_remove(&nn->s2s_cp_stateids,
+		   copy->cp_stateid.stid.si_opaque.so_id);
+	spin_unlock(&nn->s2s_cp_lock);
+}
+
+static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid)
+{
+	struct nfs4_cpntf_state *cps;
+	struct nfsd_net *nn;
+
+	nn = net_generic(net, nfsd_net_id);
+	spin_lock(&nn->s2s_cp_lock);
+	while (!list_empty(&stid->sc_cp_list)) {
+		cps = list_first_entry(&stid->sc_cp_list,
+				       struct nfs4_cpntf_state, cp_list);
+		_free_cpntf_state_locked(nn, cps);
+	}
 	spin_unlock(&nn->s2s_cp_lock);
 }
 
@@ -915,6 +963,7 @@ static void block_delegations(struct knfsd_fh *fh)
 		return;
 	}
 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
+	nfs4_free_cpntf_statelist(clp->net, s);
 	spin_unlock(&clp->cl_lock);
 	s->sc_free(s);
 	if (fp)
@@ -2906,6 +2955,26 @@ static bool client_has_openowners(struct nfs4_client *clp)
 	return false;
 }
 
+static bool client_has_copy_notifies(struct nfs4_client *clp)
+{
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+	copy_stateid_t *cps_t;
+	struct nfs4_cpntf_state *cps;
+	int i;
+
+	spin_lock(&nn->s2s_cp_lock);
+	idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
+		cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
+		if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
+				same_clid(&cps->cp_p_clid, &clp->cl_clientid)) {
+			spin_unlock(&nn->s2s_cp_lock);
+			return true;
+		}
+	}
+	spin_unlock(&nn->s2s_cp_lock);
+	return false;
+}
+
 static bool client_has_state(struct nfs4_client *clp)
 {
 	return client_has_openowners(clp)
@@ -2914,7 +2983,8 @@ static bool client_has_state(struct nfs4_client *clp)
 #endif
 		|| !list_empty(&clp->cl_delegations)
 		|| !list_empty(&clp->cl_sessions)
-		|| !list_empty(&clp->async_copies);
+		|| !list_empty(&clp->async_copies)
+		|| client_has_copy_notifies(clp);
 }
 
 static __be32 copy_impl_id(struct nfs4_client *clp,
@@ -5192,6 +5262,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
 	struct list_head *pos, *next, reaplist;
 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
 	time_t t, new_timeo = nn->nfsd4_lease;
+	struct nfs4_cpntf_state *cps;
+	copy_stateid_t *cps_t;
+	int i;
 
 	dprintk("NFSD: laundromat service - starting\n");
 
@@ -5202,6 +5275,17 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
 	dprintk("NFSD: end of grace period\n");
 	nfsd4_end_grace(nn);
 	INIT_LIST_HEAD(&reaplist);
+
+	spin_lock(&nn->s2s_cp_lock);
+	idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
+		cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
+		if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
+				!time_after((unsigned long)cps->cpntf_time,
+				(unsigned long)cutoff))
+			_free_cpntf_state_locked(nn, cps);
+	}
+	spin_unlock(&nn->s2s_cp_lock);
+
 	spin_lock(&nn->client_lock);
 	list_for_each_safe(pos, next, &nn->client_lru) {
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
@@ -5577,6 +5661,24 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 out:
 	return status;
 }
+static void
+_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
+{
+	WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
+	if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
+		return;
+	list_del(&cps->cp_list);
+	idr_remove(&nn->s2s_cp_stateids,
+		   cps->cp_stateid.stid.si_opaque.so_id);
+	kfree(cps);
+}
+
+void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
+{
+	spin_lock(&nn->s2s_cp_lock);
+	_free_cpntf_state_locked(nn, cps);
+	spin_unlock(&nn->s2s_cp_lock);
+}
 
 /*
  * Checks for stateid operations
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index d9e7cbd..967b937 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -56,6 +56,14 @@
 	stateid_opaque_t        si_opaque;
 } stateid_t;
 
+typedef struct {
+	stateid_t		stid;
+#define NFS4_COPY_STID 1
+#define NFS4_COPYNOTIFY_STID 2
+	unsigned char		sc_type;
+	refcount_t		sc_count;
+} copy_stateid_t;
+
 #define STATEID_FMT	"(%08x/%08x/%08x/%08x)"
 #define STATEID_VAL(s) \
 	(s)->si_opaque.so_clid.cl_boot, \
@@ -96,6 +104,7 @@ struct nfs4_stid {
 #define NFS4_REVOKED_DELEG_STID 16
 #define NFS4_CLOSED_DELEG_STID 32
 #define NFS4_LAYOUT_STID 64
+	struct list_head	sc_cp_list;
 	unsigned char		sc_type;
 	stateid_t		sc_stateid;
 	spinlock_t		sc_lock;
@@ -104,6 +113,17 @@ struct nfs4_stid {
 	void			(*sc_free)(struct nfs4_stid *);
 };
 
+/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
+ * parent OPEN/LOCK/DELEG stateid.
+ */
+struct nfs4_cpntf_state {
+	copy_stateid_t		cp_stateid;
+	struct list_head	cp_list;	/* per parent nfs4_stid */
+	stateid_t		cp_p_stateid;	/* copy of parent's stateid */
+	clientid_t		cp_p_clid;	/* copy of parent's clid */
+	time_t			cpntf_time;	/* last time stateid used */
+};
+
 /*
  * Represents a delegation stateid. The nfs4_client holds references to these
  * and they are put when it is being destroyed or when the delegation is
@@ -624,8 +644,10 @@ __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);
+int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
+void nfs4_free_copy_state(struct nfsd4_copy *copy);
+struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
+			struct nfs4_stid *p_stid);
 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);
@@ -655,6 +677,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
 extern void nfs4_put_copy(struct nfsd4_copy *copy);
 extern struct nfsd4_copy *
 find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
+extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
+				 struct nfs4_cpntf_state *cps);
 static inline void get_nfs4_file(struct nfs4_file *fi)
 {
 	refcount_inc(&fi->fi_ref);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 8231fe0..2937e06 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -542,7 +542,7 @@ struct nfsd4_copy {
 	struct nfsd_file        *nf_src;
 	struct nfsd_file        *nf_dst;
 
-	stateid_t		cp_stateid;
+	copy_stateid_t		cp_stateid;
 
 	struct list_head	copies;
 	struct task_struct	*copy_task;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 16/19] NFSD check stateids against copy stateids
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (14 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 15/19] NFSD add COPY_NOTIFY operation Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 17/19] NFSD generalize nfsd4_compound_state flag names Olga Kornievskaia
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Incoming stateid (used by a READ) could be a saved copy stateid.
Using the provided stateid, look it up in the list of copy_notify
stateids. If found, use the parent's stateid and parent's clid
to look up the parent's stid to do the appropriate checks.

Update the copy notify timestamp (cpntf_time) with current time
this making it 'active' so that laundromat thread will not delete
copy notify state.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4state.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 66 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 857133f..062c0c4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4537,7 +4537,8 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4
 
 static __be32 lookup_clientid(clientid_t *clid,
 		struct nfsd4_compound_state *cstate,
-		struct nfsd_net *nn)
+		struct nfsd_net *nn,
+		bool sessions)
 {
 	struct nfs4_client *found;
 
@@ -4558,7 +4559,7 @@ static __be32 lookup_clientid(clientid_t *clid,
 	 */
 	WARN_ON_ONCE(cstate->session);
 	spin_lock(&nn->client_lock);
-	found = find_confirmed_client(clid, false, nn);
+	found = find_confirmed_client(clid, sessions, nn);
 	if (!found) {
 		spin_unlock(&nn->client_lock);
 		return nfserr_expired;
@@ -4591,7 +4592,7 @@ static __be32 lookup_clientid(clientid_t *clid,
 	if (open->op_file == NULL)
 		return nfserr_jukebox;
 
-	status = lookup_clientid(clientid, cstate, nn);
+	status = lookup_clientid(clientid, cstate, nn, false);
 	if (status)
 		return status;
 	clp = cstate->clp;
@@ -5180,7 +5181,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
 
 	dprintk("process_renew(%08x/%08x): starting\n", 
 			clid->cl_boot, clid->cl_id);
-	status = lookup_clientid(clid, cstate, nn);
+	status = lookup_clientid(clid, cstate, nn, false);
 	if (status)
 		goto out;
 	clp = cstate->clp;
@@ -5582,7 +5583,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
 		CLOSE_STATEID(stateid))
 		return nfserr_bad_stateid;
-	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
+	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn,
+				 false);
 	if (status == nfserr_stale_clientid) {
 		if (cstate->session)
 			return nfserr_bad_stateid;
@@ -5672,6 +5674,59 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 		   cps->cp_stateid.stid.si_opaque.so_id);
 	kfree(cps);
 }
+/*
+ * A READ from an inter server to server COPY will have a
+ * copy stateid. Look up the copy notify stateid from the
+ * idr structure and take a reference on it.
+ */
+static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+		     struct nfs4_cpntf_state **cps)
+{
+	copy_stateid_t *cps_t;
+	struct nfs4_cpntf_state *state = NULL;
+
+	if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id)
+		return nfserr_bad_stateid;
+	spin_lock(&nn->s2s_cp_lock);
+	cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id);
+	if (cps_t) {
+		state = container_of(cps_t, struct nfs4_cpntf_state,
+				     cp_stateid);
+		if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID)
+			return nfserr_bad_stateid;
+		refcount_inc(&state->cp_stateid.sc_count);
+	}
+	spin_unlock(&nn->s2s_cp_lock);
+	if (!state)
+		return nfserr_bad_stateid;
+	*cps = state;
+	return 0;
+}
+
+static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+			       struct nfs4_stid **stid)
+{
+	__be32 status;
+	struct nfs4_cpntf_state *cps = NULL;
+	struct nfsd4_compound_state cstate;
+
+	status = _find_cpntf_state(nn, st, &cps);
+	if (status)
+		return status;
+
+	cps->cpntf_time = get_seconds();
+	memset(&cstate, 0, sizeof(cstate));
+	status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true);
+	if (status)
+		goto out;
+	status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid,
+				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
+				stid, nn);
+	put_client_renew(cstate.clp);
+out:
+	nfs4_put_cpntf_state(nn, cps);
+	return status;
+}
 
 void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
 {
@@ -5709,6 +5764,8 @@ void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
 	status = nfsd4_lookup_stateid(cstate, stateid,
 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
 				&s, nn);
+	if (status == nfserr_bad_stateid)
+		status = find_cpntf_state(nn, stateid, &s);
 	if (status)
 		return status;
 	status = nfsd4_stid_check_stateid_generation(stateid, s,
@@ -6741,7 +6798,8 @@ static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct
 		 return nfserr_inval;
 
 	if (!nfsd4_has_session(cstate)) {
-		status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
+		status = lookup_clientid(&lockt->lt_clientid, cstate, nn,
+					 false);
 		if (status)
 			goto out;
 	}
@@ -6925,7 +6983,7 @@ static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct
 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
 		clid->cl_boot, clid->cl_id);
 
-	status = lookup_clientid(clid, cstate, nn);
+	status = lookup_clientid(clid, cstate, nn, false);
 	if (status)
 		return status;
 
@@ -7072,7 +7130,7 @@ struct nfs4_client_reclaim *
 	__be32 status;
 
 	/* find clientid in conf_id_hashtbl */
-	status = lookup_clientid(clid, cstate, nn);
+	status = lookup_clientid(clid, cstate, nn, false);
 	if (status)
 		return nfserr_reclaim_bad;
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 17/19] NFSD generalize nfsd4_compound_state flag names
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (15 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 16/19] NFSD check stateids against copy stateids Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-16 21:13 ` [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh Olga Kornievskaia
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

From: Olga Kornievskaia <kolga@netapp.com>

Allow for sid_flag field non-stateid use.

Signed-off-by: Andy Adamson <andros@netapp.com>
---
 fs/nfsd/nfs4proc.c  | 8 ++++----
 fs/nfsd/nfs4state.c | 7 ++++---
 fs/nfsd/xdr4.h      | 6 +++---
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 75ecdbd..90d0b67 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -531,9 +531,9 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat
 		return nfserr_restorefh;
 
 	fh_dup2(&cstate->current_fh, &cstate->save_fh);
-	if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) {
+	if (HAS_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG)) {
 		memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
-		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+		SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
 	}
 	return nfs_ok;
 }
@@ -543,9 +543,9 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat
 	     union nfsd4_op_u *u)
 {
 	fh_dup2(&cstate->save_fh, &cstate->current_fh);
-	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
+	if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG)) {
 		memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
-		SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG);
+		SET_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG);
 	}
 	return nfs_ok;
 }
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 062c0c4..81c52282 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -7928,7 +7928,8 @@ static int nfs4_state_create_net(struct net *net)
 static void
 get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
 {
-	if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
+	if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) &&
+	    CURRENT_STATEID(stateid))
 		memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
 }
 
@@ -7937,14 +7938,14 @@ static int nfs4_state_create_net(struct net *net)
 {
 	if (cstate->minorversion) {
 		memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
-		SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+		SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
 	}
 }
 
 void
 clear_current_stateid(struct nfsd4_compound_state *cstate)
 {
-	CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+	CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
 }
 
 /*
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 2937e06..0b4fe07 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -46,9 +46,9 @@
 #define CURRENT_STATE_ID_FLAG (1<<0)
 #define SAVED_STATE_ID_FLAG (1<<1)
 
-#define SET_STATE_ID(c, f) ((c)->sid_flags |= (f))
-#define HAS_STATE_ID(c, f) ((c)->sid_flags & (f))
-#define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f))
+#define SET_CSTATE_FLAG(c, f) ((c)->sid_flags |= (f))
+#define HAS_CSTATE_FLAG(c, f) ((c)->sid_flags & (f))
+#define CLEAR_CSTATE_FLAG(c, f) ((c)->sid_flags &= ~(f))
 
 struct nfsd4_compound_state {
 	struct svc_fh		current_fh;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (16 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 17/19] NFSD generalize nfsd4_compound_state flag names Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-10-02 19:55   ` bfields
  2019-09-16 21:13 ` [PATCH v7 19/19] NFSD add nfs4 inter ssc to nfsd4_copy Olga Kornievskaia
  2019-09-30 19:06 ` [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
  19 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

The inter server to server COPY source server filehandle
is a foreign filehandle as the COPY is sent to the destination
server.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/Kconfig    | 10 +++++++++
 fs/nfsd/nfs4proc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/nfsfh.h    |  5 ++++-
 fs/nfsd/xdr4.h     |  1 +
 4 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 10cefb0..b7172a8 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -133,6 +133,16 @@ config NFSD_FLEXFILELAYOUT
 
 	  If unsure, say N.
 
+config NFSD_V4_2_INTER_SSC
+	bool "NFSv4.2 inter server to server COPY"
+	depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2
+	help
+	  This option enables support for NFSv4.2 inter server to
+	  server copy where the destination server calls the NFSv4.2
+	  client to read the data to copy from the source server.
+
+	  If unsure, say N.
+
 config NFSD_V4_SECURITY_LABEL
 	bool "Provide Security Label support for NFSv4 server"
 	depends on NFSD_V4 && SECURITY
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 90d0b67..7574ba7 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -504,12 +504,20 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat
 	    union nfsd4_op_u *u)
 {
 	struct nfsd4_putfh *putfh = &u->putfh;
+	__be32 ret;
 
 	fh_put(&cstate->current_fh);
 	cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
 	memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
 	       putfh->pf_fhlen);
-	return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
+	ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
+#ifdef CONFIG_NFSD_V4_2_INTER_SSC
+	if (ret == nfserr_stale && putfh->no_verify) {
+		SET_FH_FLAG(&cstate->current_fh, NFSD4_FH_FOREIGN);
+		ret = 0;
+	}
+#endif
+	return ret;
 }
 
 static __be32
@@ -1956,6 +1964,45 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
 		- rqstp->rq_auth_slack;
 }
 
+#ifdef CONFIG_NFSD_V4_2_INTER_SSC
+static __be32
+check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
+{
+	struct nfsd4_op	*op, *current_op, *saved_op;
+	struct nfsd4_copy *copy;
+	struct nfsd4_putfh *putfh;
+	int i;
+
+	/* traverse all operation and if it's a COPY compound, mark the
+	 * source filehandle to skip verification
+	 */
+	for (i = 0; i < args->opcnt; i++) {
+		op = &args->ops[i];
+		if (op->opnum == OP_PUTFH)
+			current_op = op;
+		else if (op->opnum == OP_SAVEFH)
+			saved_op = current_op;
+		else if (op->opnum == OP_RESTOREFH)
+			current_op = saved_op;
+		else if (op->opnum == OP_COPY) {
+			copy = (struct nfsd4_copy *)&op->u;
+			if (!saved_op)
+				return nfserr_nofilehandle;
+			putfh = (struct nfsd4_putfh *)&saved_op->u;
+			if (!copy->cp_intra)
+				putfh->no_verify = true;
+		}
+	}
+	return nfs_ok;
+}
+#else
+static __be32
+check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
+{
+	return nfs_ok;
+}
+#endif
+
 /*
  * COMPOUND call.
  */
@@ -2004,6 +2051,9 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
 		resp->opcnt = 1;
 		goto encode_op;
 	}
+	status = check_if_stalefh_allowed(args);
+	if (status)
+		goto out;
 
 	trace_nfsd_compound(rqstp, args->opcnt);
 	while (!status && resp->opcnt < args->opcnt) {
@@ -2019,13 +2069,14 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
 				op->status = nfsd4_open_omfg(rqstp, cstate, op);
 			goto encode_op;
 		}
-
-		if (!current_fh->fh_dentry) {
+		if (!current_fh->fh_dentry &&
+				!HAS_FH_FLAG(current_fh, NFSD4_FH_FOREIGN)) {
 			if (!(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
 				op->status = nfserr_nofilehandle;
 				goto encode_op;
 			}
-		} else if (current_fh->fh_export->ex_fslocs.migrated &&
+		} else if (current_fh->fh_export &&
+			   current_fh->fh_export->ex_fslocs.migrated &&
 			  !(op->opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
 			op->status = nfserr_moved;
 			goto encode_op;
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 755e256..b9c7568 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -35,7 +35,7 @@ static inline ino_t u32_to_ino_t(__u32 uino)
 
 	bool			fh_locked;	/* inode locked by us */
 	bool			fh_want_write;	/* remount protection taken */
-
+	int			fh_flags;	/* FH flags */
 #ifdef CONFIG_NFSD_V3
 	bool			fh_post_saved;	/* post-op attrs saved */
 	bool			fh_pre_saved;	/* pre-op attrs saved */
@@ -56,6 +56,9 @@ static inline ino_t u32_to_ino_t(__u32 uino)
 #endif /* CONFIG_NFSD_V3 */
 
 } svc_fh;
+#define NFSD4_FH_FOREIGN (1<<0)
+#define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f))
+#define HAS_FH_FLAG(c, f) ((c)->fh_flags & (f))
 
 enum nfsd_fsid {
 	FSID_DEV = 0,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 0b4fe07..b16f602 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -221,6 +221,7 @@ struct nfsd4_lookup {
 struct nfsd4_putfh {
 	u32		pf_fhlen;           /* request */
 	char		*pf_fhval;          /* request */
+	bool		no_verify;	    /* represents foreigh fh */
 };
 
 struct nfsd4_open {
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 19/19] NFSD add nfs4 inter ssc to nfsd4_copy
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (17 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh Olga Kornievskaia
@ 2019-09-16 21:13 ` Olga Kornievskaia
  2019-09-19 19:55   ` [PATCH 1/1] " Olga Kornievskaia
  2019-09-30 19:06 ` [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
  19 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-16 21:13 UTC (permalink / raw)
  To: trond.myklebust, anna.schumaker, bfields; +Cc: linux-nfs

Given a universal address, mount the source server from the destination
server.  Use an internal mount. Call the NFS client nfs42_ssc_open to
obtain the NFS struct file suitable for nfsd_copy_range.

Ability to do "inter" server-to-server depends on the an nfsd kernel
parameter "inter_copy_offload_enable".

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4proc.c  | 284 ++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/nfs4state.c |  15 ++-
 fs/nfsd/nfssvc.c    |   6 ++
 fs/nfsd/state.h     |   3 +
 fs/nfsd/xdr4.h      |   5 +
 5 files changed, 286 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7574ba7..006d502 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1144,6 +1144,208 @@ void nfsd4_shutdown_copy(struct nfs4_client *clp)
 	while ((copy = nfsd4_get_copy(clp)) != NULL)
 		nfsd4_stop_copy(copy);
 }
+#ifdef CONFIG_NFSD_V4_2_INTER_SSC
+
+extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
+				   struct nfs_fh *src_fh,
+				   nfs4_stateid *stateid);
+extern void nfs42_ssc_close(struct file *filep);
+
+extern void nfs_sb_deactive(struct super_block *sb);
+
+#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
+
+/**
+ * Support one copy source server for now.
+ */
+static __be32
+nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
+		       struct vfsmount **mount)
+{
+	struct file_system_type *type;
+	struct vfsmount *ss_mnt;
+	struct nfs42_netaddr *naddr;
+	struct sockaddr_storage tmp_addr;
+	size_t tmp_addrlen, match_netid_len = 3;
+	char *startsep = "", *endsep = "", *match_netid = "tcp";
+	char *ipaddr, *dev_name, *raw_data;
+	int len, raw_len, status = -EINVAL;
+
+	naddr = &nss->u.nl4_addr;
+	tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
+					 naddr->addr_len,
+					 (struct sockaddr *)&tmp_addr,
+					 sizeof(tmp_addr));
+	if (tmp_addrlen == 0)
+		goto out_err;
+
+	if (tmp_addr.ss_family == AF_INET6) {
+		startsep = "[";
+		endsep = "]";
+		match_netid = "tcp6";
+		match_netid_len = 4;
+	}
+
+	if (naddr->netid_len != match_netid_len ||
+		strncmp(naddr->netid, match_netid, naddr->netid_len))
+		goto out_err;
+
+	/* Construct the raw data for the vfs_kern_mount call */
+	len = RPC_MAX_ADDRBUFLEN + 1;
+	ipaddr = kzalloc(len, GFP_KERNEL);
+	if (!ipaddr)
+		goto out_err;
+
+	rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
+
+	/* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
+
+	raw_len = strlen(NFSD42_INTERSSC_MOUNTOPS) + strlen(ipaddr);
+	raw_data = kzalloc(raw_len, GFP_KERNEL);
+	if (!raw_data)
+		goto out_free_ipaddr;
+
+	snprintf(raw_data, raw_len, NFSD42_INTERSSC_MOUNTOPS, ipaddr);
+
+	status = -ENODEV;
+	type = get_fs_type("nfs");
+	if (!type)
+		goto out_free_rawdata;
+
+	/* Set the server:<export> for the vfs_kern_mount call */
+	dev_name = kzalloc(len + 5, GFP_KERNEL);
+	if (!dev_name)
+		goto out_free_rawdata;
+	snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
+
+	/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
+	ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
+	module_put(type->owner);
+	if (IS_ERR(ss_mnt))
+		goto out_free_devname;
+
+	status = 0;
+	*mount = ss_mnt;
+
+out_free_devname:
+	kfree(dev_name);
+out_free_rawdata:
+	kfree(raw_data);
+out_free_ipaddr:
+	kfree(ipaddr);
+out_err:
+	return status;
+}
+
+static void
+nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
+{
+	nfs_sb_deactive(ss_mnt->mnt_sb);
+	mntput(ss_mnt);
+}
+
+/**
+ * nfsd4_setup_inter_ssc
+ *
+ * Verify COPY destination stateid.
+ * Connect to the source server with NFSv4.1.
+ * Create the source struct file for nfsd_copy_range.
+ * Called with COPY cstate:
+ *    SAVED_FH: source filehandle
+ *    CURRENT_FH: destination filehandle
+ *
+ * Returns errno (not nfserrxxx)
+ */
+static __be32
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy, struct vfsmount **mount)
+{
+	struct svc_fh *s_fh = NULL;
+	stateid_t *s_stid = &copy->cp_src_stateid;
+	__be32 status = -EINVAL;
+
+	/* Verify the destination stateid and set dst struct file*/
+	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+					    &copy->cp_dst_stateid,
+					    WR_STATE, &copy->nf_dst, NULL);
+	if (status)
+		goto out;
+
+	status = nfsd4_interssc_connect(&copy->cp_src, rqstp, mount);
+	if (status)
+		goto out;
+
+	s_fh = &cstate->save_fh;
+
+	copy->c_fh.size = s_fh->fh_handle.fh_size;
+	memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size);
+	copy->stateid.seqid = s_stid->si_generation;
+	memcpy(copy->stateid.other, (void *)&s_stid->si_opaque,
+	       sizeof(stateid_opaque_t));
+
+	status = 0;
+out:
+	return status;
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+			struct nfsd_file *dst)
+{
+	nfs42_ssc_close(src->nf_file);
+	nfsd_file_put(src);
+	nfsd_file_put(dst);
+	mntput(ss_mnt);
+}
+
+#else /* CONFIG_NFSD_V4_2_INTER_SSC */
+
+static __be32
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy,
+		      struct vfsmount **mount)
+{
+	*mount = NULL;
+	return -EINVAL;
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *src,
+			struct file *dst)
+{
+}
+
+static void
+nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
+{
+}
+
+static struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
+				   struct nfs_fh *src_fh,
+				   nfs4_stateid *stateid)
+{
+	return NULL;
+}
+#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
+
+static __be32
+nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy)
+{
+	return nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
+				 &copy->nf_src, &copy->cp_dst_stateid,
+				 &copy->nf_dst, NULL);
+}
+
+static void
+nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
+{
+	nfsd_file_put(src);
+	nfsd_file_put(dst);
+}
 
 static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
 {
@@ -1209,12 +1411,16 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
 		status = nfs_ok;
 	}
 
-	nfsd_file_put(copy->nf_src);
-	nfsd_file_put(copy->nf_dst);
+	if (!copy->cp_intra) /* Inter server SSC */
+		nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
+					copy->nf_dst);
+	else
+		nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
+
 	return status;
 }
 
-static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
+static int 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;
@@ -1224,8 +1430,17 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
 	memcpy(&dst->fh, &src->fh, sizeof(src->fh));
 	dst->cp_clp = src->cp_clp;
 	dst->nf_dst = nfsd_file_get(src->nf_dst);
-	dst->nf_src = nfsd_file_get(src->nf_src);
+	dst->cp_intra = src->cp_intra;
+	if (src->cp_intra) /* for inter, file_src doesn't exist yet */
+		dst->nf_src = nfsd_file_get(src->nf_src);
+
 	memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
+	memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
+	memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
+	memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
+	dst->ss_mnt = src->ss_mnt;
+
+	return 0;
 }
 
 static void cleanup_async_copy(struct nfsd4_copy *copy)
@@ -1244,7 +1459,18 @@ static int nfsd4_do_async_copy(void *data)
 	struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
 	struct nfsd4_copy *cb_copy;
 
+	if (!copy->cp_intra) { /* Inter server SSC */
+		copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
+					      &copy->stateid);
+		if (IS_ERR(copy->nf_src)) {
+			copy->nfserr = nfserr_offload_denied;
+			nfsd4_interssc_disconnect(copy->ss_mnt);
+			goto do_callback;
+		}
+	}
+
 	copy->nfserr = nfsd4_do_copy(copy, 0);
+do_callback:
 	cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
 	if (!cb_copy)
 		goto out;
@@ -1268,11 +1494,20 @@ static int nfsd4_do_async_copy(void *data)
 	__be32 status;
 	struct nfsd4_copy *async_copy = NULL;
 
-	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
-				   &copy->nf_src, &copy->cp_dst_stateid,
-				   &copy->nf_dst, NULL);
-	if (status)
-		goto out;
+	if (!copy->cp_intra) { /* Inter server SSC */
+		if (!inter_copy_offload_enable || copy->cp_synchronous) {
+			status = nfserr_notsupp;
+			goto out;
+		}
+		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
+					&copy->ss_mnt);
+		if (status)
+			return nfserr_offload_denied;
+	} else {
+		status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
+		if (status)
+			return status;
+	}
 
 	copy->cp_clp = cstate->clp;
 	memcpy(&copy->fh, &cstate->current_fh.fh_handle,
@@ -1283,15 +1518,15 @@ static int nfsd4_do_async_copy(void *data)
 		status = nfserrno(-ENOMEM);
 		async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
 		if (!async_copy)
-			goto out;
-		if (!nfs4_init_copy_state(nn, copy)) {
-			kfree(async_copy);
-			goto out;
-		}
+			goto out_err;
+		if (!nfs4_init_copy_state(nn, copy))
+			goto out_err;
 		refcount_set(&async_copy->refcount, 1);
 		memcpy(&copy->cp_res.cb_stateid, &copy->cp_stateid,
 			sizeof(copy->cp_stateid));
-		dup_copy_fields(copy, async_copy);
+		status = dup_copy_fields(copy, async_copy);
+		if (status)
+			goto out_err;
 		async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
 				async_copy, "%s", "copy thread");
 		if (IS_ERR(async_copy->copy_task))
@@ -1302,12 +1537,16 @@ static int nfsd4_do_async_copy(void *data)
 		spin_unlock(&async_copy->cp_clp->async_lock);
 		wake_up_process(async_copy->copy_task);
 		status = nfs_ok;
-	} else
+	} else {
 		status = nfsd4_do_copy(copy, 1);
+	}
 out:
 	return status;
 out_err:
 	cleanup_async_copy(async_copy);
+	status = nfserrno(-ENOMEM);
+	if (!copy->cp_intra)
+		nfsd4_interssc_disconnect(copy->ss_mnt);
 	goto out;
 }
 
@@ -1318,7 +1557,7 @@ struct nfsd4_copy *
 
 	spin_lock(&clp->async_lock);
 	list_for_each_entry(copy, &clp->async_copies, copies) {
-		if (memcmp(&copy->cp_stateid, stateid, NFS4_STATEID_SIZE))
+		if (memcmp(&copy->cp_stateid.stid, stateid, NFS4_STATEID_SIZE))
 			continue;
 		refcount_inc(&copy->refcount);
 		spin_unlock(&clp->async_lock);
@@ -1334,17 +1573,18 @@ struct nfsd4_copy *
 		     union nfsd4_op_u *u)
 {
 	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)
+	if (!copy) {
+		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
+		return manage_cpntf_state(nn, &os->stateid, clp, NULL);
+	} else
 		nfsd4_stop_copy(copy);
-	else
-		status = nfserr_bad_stateid;
 
-	return status;
+	return nfs_ok;
 }
 
 static __be32
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 81c52282..0a70a82 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5679,8 +5679,9 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
  * copy stateid. Look up the copy notify stateid from the
  * idr structure and take a reference on it.
  */
-static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
-		     struct nfs4_cpntf_state **cps)
+__be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+			  struct nfs4_client *clp,
+			  struct nfs4_cpntf_state **cps)
 {
 	copy_stateid_t *cps_t;
 	struct nfs4_cpntf_state *state = NULL;
@@ -5694,12 +5695,16 @@ static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
 				     cp_stateid);
 		if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID)
 			return nfserr_bad_stateid;
-		refcount_inc(&state->cp_stateid.sc_count);
+		if (!clp)
+			refcount_inc(&state->cp_stateid.sc_count);
+		else
+			_free_cpntf_state_locked(nn, state);
 	}
 	spin_unlock(&nn->s2s_cp_lock);
 	if (!state)
 		return nfserr_bad_stateid;
-	*cps = state;
+	if (!clp && state)
+		*cps = state;
 	return 0;
 }
 
@@ -5710,7 +5715,7 @@ static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
 	struct nfs4_cpntf_state *cps = NULL;
 	struct nfsd4_compound_state cstate;
 
-	status = _find_cpntf_state(nn, st, &cps);
+	status = manage_cpntf_state(nn, st, NULL, &cps);
 	if (status)
 		return status;
 
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 3caaf56..e093c81 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -31,6 +31,12 @@
 
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
 
+bool inter_copy_offload_enable;
+EXPORT_SYMBOL_GPL(inter_copy_offload_enable);
+module_param(inter_copy_offload_enable, bool, 0644);
+MODULE_PARM_DESC(inter_copy_offload_enable,
+		 "Enable inter server to server copy offload. Default: false");
+
 extern struct svc_program	nfsd_program;
 static int			nfsd(void *vrqstp);
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 967b937..3f57680 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -679,6 +679,9 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
 find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
 extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
 				 struct nfs4_cpntf_state *cps);
+extern __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+				 struct nfs4_client *clp,
+				 struct nfs4_cpntf_state **cps);
 static inline void get_nfs4_file(struct nfs4_file *fi)
 {
 	refcount_inc(&fi->fi_ref);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index b16f602..db63d39 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -549,7 +549,12 @@ struct nfsd4_copy {
 	struct task_struct	*copy_task;
 	refcount_t		refcount;
 	bool			stopped;
+
+	struct vfsmount		*ss_mnt;
+	struct nfs_fh		c_fh;
+	nfs4_stateid		stateid;
 };
+extern bool inter_copy_offload_enable;
 
 struct nfsd4_seek {
 	/* request */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/1] NFSD add nfs4 inter ssc to nfsd4_copy
  2019-09-16 21:13 ` [PATCH v7 19/19] NFSD add nfs4 inter ssc to nfsd4_copy Olga Kornievskaia
@ 2019-09-19 19:55   ` " Olga Kornievskaia
  0 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-19 19:55 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Given a universal address, mount the source server from the destination
server.  Use an internal mount. Call the NFS client nfs42_ssc_open to
obtain the NFS struct file suitable for nfsd_copy_range.

Ability to do "inter" server-to-server depends on the an nfsd kernel
parameter "inter_copy_offload_enable".

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
---
 fs/nfsd/nfs4proc.c  | 284 ++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/nfs4state.c |  15 ++-
 fs/nfsd/nfssvc.c    |   6 ++
 fs/nfsd/state.h     |   3 +
 fs/nfsd/xdr4.h      |   5 +
 5 files changed, 286 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7574ba7..a431d4f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1144,6 +1144,208 @@ void nfsd4_shutdown_copy(struct nfs4_client *clp)
 	while ((copy = nfsd4_get_copy(clp)) != NULL)
 		nfsd4_stop_copy(copy);
 }
+#ifdef CONFIG_NFSD_V4_2_INTER_SSC
+
+extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
+				   struct nfs_fh *src_fh,
+				   nfs4_stateid *stateid);
+extern void nfs42_ssc_close(struct file *filep);
+
+extern void nfs_sb_deactive(struct super_block *sb);
+
+#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
+
+/**
+ * Support one copy source server for now.
+ */
+static __be32
+nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
+		       struct vfsmount **mount)
+{
+	struct file_system_type *type;
+	struct vfsmount *ss_mnt;
+	struct nfs42_netaddr *naddr;
+	struct sockaddr_storage tmp_addr;
+	size_t tmp_addrlen, match_netid_len = 3;
+	char *startsep = "", *endsep = "", *match_netid = "tcp";
+	char *ipaddr, *dev_name, *raw_data;
+	int len, raw_len, status = -EINVAL;
+
+	naddr = &nss->u.nl4_addr;
+	tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
+					 naddr->addr_len,
+					 (struct sockaddr *)&tmp_addr,
+					 sizeof(tmp_addr));
+	if (tmp_addrlen == 0)
+		goto out_err;
+
+	if (tmp_addr.ss_family == AF_INET6) {
+		startsep = "[";
+		endsep = "]";
+		match_netid = "tcp6";
+		match_netid_len = 4;
+	}
+
+	if (naddr->netid_len != match_netid_len ||
+		strncmp(naddr->netid, match_netid, naddr->netid_len))
+		goto out_err;
+
+	/* Construct the raw data for the vfs_kern_mount call */
+	len = RPC_MAX_ADDRBUFLEN + 1;
+	ipaddr = kzalloc(len, GFP_KERNEL);
+	if (!ipaddr)
+		goto out_err;
+
+	rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
+
+	/* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
+
+	raw_len = strlen(NFSD42_INTERSSC_MOUNTOPS) + strlen(ipaddr);
+	raw_data = kzalloc(raw_len, GFP_KERNEL);
+	if (!raw_data)
+		goto out_free_ipaddr;
+
+	snprintf(raw_data, raw_len, NFSD42_INTERSSC_MOUNTOPS, ipaddr);
+
+	status = -ENODEV;
+	type = get_fs_type("nfs");
+	if (!type)
+		goto out_free_rawdata;
+
+	/* Set the server:<export> for the vfs_kern_mount call */
+	dev_name = kzalloc(len + 5, GFP_KERNEL);
+	if (!dev_name)
+		goto out_free_rawdata;
+	snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
+
+	/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
+	ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
+	module_put(type->owner);
+	if (IS_ERR(ss_mnt))
+		goto out_free_devname;
+
+	status = 0;
+	*mount = ss_mnt;
+
+out_free_devname:
+	kfree(dev_name);
+out_free_rawdata:
+	kfree(raw_data);
+out_free_ipaddr:
+	kfree(ipaddr);
+out_err:
+	return status;
+}
+
+static void
+nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
+{
+	nfs_sb_deactive(ss_mnt->mnt_sb);
+	mntput(ss_mnt);
+}
+
+/**
+ * nfsd4_setup_inter_ssc
+ *
+ * Verify COPY destination stateid.
+ * Connect to the source server with NFSv4.1.
+ * Create the source struct file for nfsd_copy_range.
+ * Called with COPY cstate:
+ *    SAVED_FH: source filehandle
+ *    CURRENT_FH: destination filehandle
+ *
+ * Returns errno (not nfserrxxx)
+ */
+static __be32
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy, struct vfsmount **mount)
+{
+	struct svc_fh *s_fh = NULL;
+	stateid_t *s_stid = &copy->cp_src_stateid;
+	__be32 status = -EINVAL;
+
+	/* Verify the destination stateid and set dst struct file*/
+	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+					    &copy->cp_dst_stateid,
+					    WR_STATE, &copy->nf_dst, NULL);
+	if (status)
+		goto out;
+
+	status = nfsd4_interssc_connect(&copy->cp_src, rqstp, mount);
+	if (status)
+		goto out;
+
+	s_fh = &cstate->save_fh;
+
+	copy->c_fh.size = s_fh->fh_handle.fh_size;
+	memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size);
+	copy->stateid.seqid = s_stid->si_generation;
+	memcpy(copy->stateid.other, (void *)&s_stid->si_opaque,
+	       sizeof(stateid_opaque_t));
+
+	status = 0;
+out:
+	return status;
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+			struct nfsd_file *dst)
+{
+	nfs42_ssc_close(src->nf_file);
+	nfsd_file_put(src);
+	nfsd_file_put(dst);
+	mntput(ss_mnt);
+}
+
+#else /* CONFIG_NFSD_V4_2_INTER_SSC */
+
+static __be32
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy,
+		      struct vfsmount **mount)
+{
+	*mount = NULL;
+	return -EINVAL;
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
+			struct nfsd_file *dst)
+{
+}
+
+static void
+nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
+{
+}
+
+static struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
+				   struct nfs_fh *src_fh,
+				   nfs4_stateid *stateid)
+{
+	return NULL;
+}
+#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
+
+static __be32
+nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
+		      struct nfsd4_compound_state *cstate,
+		      struct nfsd4_copy *copy)
+{
+	return nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
+				 &copy->nf_src, &copy->cp_dst_stateid,
+				 &copy->nf_dst, NULL);
+}
+
+static void
+nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
+{
+	nfsd_file_put(src);
+	nfsd_file_put(dst);
+}
 
 static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
 {
@@ -1209,12 +1411,16 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
 		status = nfs_ok;
 	}
 
-	nfsd_file_put(copy->nf_src);
-	nfsd_file_put(copy->nf_dst);
+	if (!copy->cp_intra) /* Inter server SSC */
+		nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
+					copy->nf_dst);
+	else
+		nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
+
 	return status;
 }
 
-static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
+static int 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;
@@ -1224,8 +1430,17 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
 	memcpy(&dst->fh, &src->fh, sizeof(src->fh));
 	dst->cp_clp = src->cp_clp;
 	dst->nf_dst = nfsd_file_get(src->nf_dst);
-	dst->nf_src = nfsd_file_get(src->nf_src);
+	dst->cp_intra = src->cp_intra;
+	if (src->cp_intra) /* for inter, file_src doesn't exist yet */
+		dst->nf_src = nfsd_file_get(src->nf_src);
+
 	memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
+	memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
+	memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
+	memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
+	dst->ss_mnt = src->ss_mnt;
+
+	return 0;
 }
 
 static void cleanup_async_copy(struct nfsd4_copy *copy)
@@ -1244,7 +1459,18 @@ static int nfsd4_do_async_copy(void *data)
 	struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
 	struct nfsd4_copy *cb_copy;
 
+	if (!copy->cp_intra) { /* Inter server SSC */
+		copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
+					      &copy->stateid);
+		if (IS_ERR(copy->nf_src)) {
+			copy->nfserr = nfserr_offload_denied;
+			nfsd4_interssc_disconnect(copy->ss_mnt);
+			goto do_callback;
+		}
+	}
+
 	copy->nfserr = nfsd4_do_copy(copy, 0);
+do_callback:
 	cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
 	if (!cb_copy)
 		goto out;
@@ -1268,11 +1494,20 @@ static int nfsd4_do_async_copy(void *data)
 	__be32 status;
 	struct nfsd4_copy *async_copy = NULL;
 
-	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
-				   &copy->nf_src, &copy->cp_dst_stateid,
-				   &copy->nf_dst, NULL);
-	if (status)
-		goto out;
+	if (!copy->cp_intra) { /* Inter server SSC */
+		if (!inter_copy_offload_enable || copy->cp_synchronous) {
+			status = nfserr_notsupp;
+			goto out;
+		}
+		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
+					&copy->ss_mnt);
+		if (status)
+			return nfserr_offload_denied;
+	} else {
+		status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
+		if (status)
+			return status;
+	}
 
 	copy->cp_clp = cstate->clp;
 	memcpy(&copy->fh, &cstate->current_fh.fh_handle,
@@ -1283,15 +1518,15 @@ static int nfsd4_do_async_copy(void *data)
 		status = nfserrno(-ENOMEM);
 		async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
 		if (!async_copy)
-			goto out;
-		if (!nfs4_init_copy_state(nn, copy)) {
-			kfree(async_copy);
-			goto out;
-		}
+			goto out_err;
+		if (!nfs4_init_copy_state(nn, copy))
+			goto out_err;
 		refcount_set(&async_copy->refcount, 1);
 		memcpy(&copy->cp_res.cb_stateid, &copy->cp_stateid,
 			sizeof(copy->cp_stateid));
-		dup_copy_fields(copy, async_copy);
+		status = dup_copy_fields(copy, async_copy);
+		if (status)
+			goto out_err;
 		async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
 				async_copy, "%s", "copy thread");
 		if (IS_ERR(async_copy->copy_task))
@@ -1302,12 +1537,16 @@ static int nfsd4_do_async_copy(void *data)
 		spin_unlock(&async_copy->cp_clp->async_lock);
 		wake_up_process(async_copy->copy_task);
 		status = nfs_ok;
-	} else
+	} else {
 		status = nfsd4_do_copy(copy, 1);
+	}
 out:
 	return status;
 out_err:
 	cleanup_async_copy(async_copy);
+	status = nfserrno(-ENOMEM);
+	if (!copy->cp_intra)
+		nfsd4_interssc_disconnect(copy->ss_mnt);
 	goto out;
 }
 
@@ -1318,7 +1557,7 @@ struct nfsd4_copy *
 
 	spin_lock(&clp->async_lock);
 	list_for_each_entry(copy, &clp->async_copies, copies) {
-		if (memcmp(&copy->cp_stateid, stateid, NFS4_STATEID_SIZE))
+		if (memcmp(&copy->cp_stateid.stid, stateid, NFS4_STATEID_SIZE))
 			continue;
 		refcount_inc(&copy->refcount);
 		spin_unlock(&clp->async_lock);
@@ -1334,17 +1573,18 @@ struct nfsd4_copy *
 		     union nfsd4_op_u *u)
 {
 	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)
+	if (!copy) {
+		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
+		return manage_cpntf_state(nn, &os->stateid, clp, NULL);
+	} else
 		nfsd4_stop_copy(copy);
-	else
-		status = nfserr_bad_stateid;
 
-	return status;
+	return nfs_ok;
 }
 
 static __be32
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 81c52282..0a70a82 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5679,8 +5679,9 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
  * copy stateid. Look up the copy notify stateid from the
  * idr structure and take a reference on it.
  */
-static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
-		     struct nfs4_cpntf_state **cps)
+__be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+			  struct nfs4_client *clp,
+			  struct nfs4_cpntf_state **cps)
 {
 	copy_stateid_t *cps_t;
 	struct nfs4_cpntf_state *state = NULL;
@@ -5694,12 +5695,16 @@ static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
 				     cp_stateid);
 		if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID)
 			return nfserr_bad_stateid;
-		refcount_inc(&state->cp_stateid.sc_count);
+		if (!clp)
+			refcount_inc(&state->cp_stateid.sc_count);
+		else
+			_free_cpntf_state_locked(nn, state);
 	}
 	spin_unlock(&nn->s2s_cp_lock);
 	if (!state)
 		return nfserr_bad_stateid;
-	*cps = state;
+	if (!clp && state)
+		*cps = state;
 	return 0;
 }
 
@@ -5710,7 +5715,7 @@ static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
 	struct nfs4_cpntf_state *cps = NULL;
 	struct nfsd4_compound_state cstate;
 
-	status = _find_cpntf_state(nn, st, &cps);
+	status = manage_cpntf_state(nn, st, NULL, &cps);
 	if (status)
 		return status;
 
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 3caaf56..e093c81 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -31,6 +31,12 @@
 
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
 
+bool inter_copy_offload_enable;
+EXPORT_SYMBOL_GPL(inter_copy_offload_enable);
+module_param(inter_copy_offload_enable, bool, 0644);
+MODULE_PARM_DESC(inter_copy_offload_enable,
+		 "Enable inter server to server copy offload. Default: false");
+
 extern struct svc_program	nfsd_program;
 static int			nfsd(void *vrqstp);
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 967b937..3f57680 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -679,6 +679,9 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
 find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
 extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
 				 struct nfs4_cpntf_state *cps);
+extern __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st,
+				 struct nfs4_client *clp,
+				 struct nfs4_cpntf_state **cps);
 static inline void get_nfs4_file(struct nfs4_file *fi)
 {
 	refcount_inc(&fi->fi_ref);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index b16f602..db63d39 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -549,7 +549,12 @@ struct nfsd4_copy {
 	struct task_struct	*copy_task;
 	refcount_t		refcount;
 	bool			stopped;
+
+	struct vfsmount		*ss_mnt;
+	struct nfs_fh		c_fh;
+	nfs4_stateid		stateid;
 };
+extern bool inter_copy_offload_enable;
 
 struct nfsd4_seek {
 	/* request */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 00/19] client and server support for "inter" SSC copy
  2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
                   ` (18 preceding siblings ...)
  2019-09-16 21:13 ` [PATCH v7 19/19] NFSD add nfs4 inter ssc to nfsd4_copy Olga Kornievskaia
@ 2019-09-30 19:06 ` Olga Kornievskaia
  2019-10-01 17:13   ` bfields
  19 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-09-30 19:06 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

Hi Bruce,

Have you had a chance to take a look at the new patch series and have
any more comments?

On Mon, Sep 16, 2019 at 5:13 PM Olga Kornievskaia
<olga.kornievskaia@gmail.com> wrote:
>
> v7:
> --- rebased patches ontop of Bruce's nfsd-next
>
> Olga Kornievskaia (19):
>   NFS NFSD: defining nl4_servers structure needed by both
>   NFS: add COPY_NOTIFY operation
>   NFS: add ca_source_server<> to COPY
>   NFS: also send OFFLOAD_CANCEL to source server
>   NFS: inter ssc open
>   NFS: skip recovery of copy open on dest server
>   NFS: for "inter" copy treat ESTALE as ENOTSUPP
>   NFS: COPY handle ERR_OFFLOAD_DENIED
>   NFS: handle source server reboot
>   NFS: replace cross device check in copy_file_range
>   NFSD fill-in netloc4 structure
>   NFSD add ca_source_server<> to COPY
>   NFSD return nfs4_stid in nfs4_preprocess_stateid_op
>   NFSD COPY_NOTIFY xdr
>   NFSD add COPY_NOTIFY operation
>   NFSD check stateids against copy stateids
>   NFSD generalize nfsd4_compound_state flag names
>   NFSD: allow inter server COPY to have a STALE source server fh
>   NFSD add nfs4 inter ssc to nfsd4_copy
>
>  fs/nfs/nfs42.h            |  15 +-
>  fs/nfs/nfs42proc.c        | 193 ++++++++++++++++----
>  fs/nfs/nfs42xdr.c         | 190 +++++++++++++++++++-
>  fs/nfs/nfs4_fs.h          |  11 ++
>  fs/nfs/nfs4client.c       |   2 +-
>  fs/nfs/nfs4file.c         | 125 ++++++++++++-
>  fs/nfs/nfs4proc.c         |   6 +-
>  fs/nfs/nfs4state.c        |  29 ++-
>  fs/nfs/nfs4xdr.c          |   1 +
>  fs/nfsd/Kconfig           |  10 ++
>  fs/nfsd/nfs4proc.c        | 436 +++++++++++++++++++++++++++++++++++++++++-----
>  fs/nfsd/nfs4state.c       | 215 ++++++++++++++++++++---
>  fs/nfsd/nfs4xdr.c         | 155 +++++++++++++++-
>  fs/nfsd/nfsd.h            |  32 ++++
>  fs/nfsd/nfsfh.h           |   5 +-
>  fs/nfsd/nfssvc.c          |   6 +
>  fs/nfsd/state.h           |  34 +++-
>  fs/nfsd/xdr4.h            |  39 ++++-
>  include/linux/nfs4.h      |  25 +++
>  include/linux/nfs_fs.h    |   3 +-
>  include/linux/nfs_fs_sb.h |   1 +
>  include/linux/nfs_xdr.h   |  17 ++
>  22 files changed, 1429 insertions(+), 121 deletions(-)
>
> --
> 1.8.3.1
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 00/19] client and server support for "inter" SSC copy
  2019-09-30 19:06 ` [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
@ 2019-10-01 17:13   ` bfields
  2019-10-01 17:47     ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: bfields @ 2019-10-01 17:13 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: J. Bruce Fields, linux-nfs, Trond Myklebust, Anna Schumaker

On Mon, Sep 30, 2019 at 03:06:11PM -0400, Olga Kornievskaia wrote:
> Have you had a chance to take a look at the new patch series and have
> any more comments?

Honestly, last time I checked I was having trouble finding things to
complain about--it looked OK to me.

But I'm not sure I understood the management of copy id's, should I
should give it one more read.  And then agree on how to merge it.

I was thinking maybe you could give us a git branch based on 5.5-rc1 or
5.5-rc2, Trond (I think it's Trond this time?) could pull the client
ones into his tree, and I could pull the rest into mine.

Trond/Anna?

--b.

> 
> On Mon, Sep 16, 2019 at 5:13 PM Olga Kornievskaia
> <olga.kornievskaia@gmail.com> wrote:
> >
> > v7:
> > --- rebased patches ontop of Bruce's nfsd-next
> >
> > Olga Kornievskaia (19):
> >   NFS NFSD: defining nl4_servers structure needed by both
> >   NFS: add COPY_NOTIFY operation
> >   NFS: add ca_source_server<> to COPY
> >   NFS: also send OFFLOAD_CANCEL to source server
> >   NFS: inter ssc open
> >   NFS: skip recovery of copy open on dest server
> >   NFS: for "inter" copy treat ESTALE as ENOTSUPP
> >   NFS: COPY handle ERR_OFFLOAD_DENIED
> >   NFS: handle source server reboot
> >   NFS: replace cross device check in copy_file_range
> >   NFSD fill-in netloc4 structure
> >   NFSD add ca_source_server<> to COPY
> >   NFSD return nfs4_stid in nfs4_preprocess_stateid_op
> >   NFSD COPY_NOTIFY xdr
> >   NFSD add COPY_NOTIFY operation
> >   NFSD check stateids against copy stateids
> >   NFSD generalize nfsd4_compound_state flag names
> >   NFSD: allow inter server COPY to have a STALE source server fh
> >   NFSD add nfs4 inter ssc to nfsd4_copy
> >
> >  fs/nfs/nfs42.h            |  15 +-
> >  fs/nfs/nfs42proc.c        | 193 ++++++++++++++++----
> >  fs/nfs/nfs42xdr.c         | 190 +++++++++++++++++++-
> >  fs/nfs/nfs4_fs.h          |  11 ++
> >  fs/nfs/nfs4client.c       |   2 +-
> >  fs/nfs/nfs4file.c         | 125 ++++++++++++-
> >  fs/nfs/nfs4proc.c         |   6 +-
> >  fs/nfs/nfs4state.c        |  29 ++-
> >  fs/nfs/nfs4xdr.c          |   1 +
> >  fs/nfsd/Kconfig           |  10 ++
> >  fs/nfsd/nfs4proc.c        | 436 +++++++++++++++++++++++++++++++++++++++++-----
> >  fs/nfsd/nfs4state.c       | 215 ++++++++++++++++++++---
> >  fs/nfsd/nfs4xdr.c         | 155 +++++++++++++++-
> >  fs/nfsd/nfsd.h            |  32 ++++
> >  fs/nfsd/nfsfh.h           |   5 +-
> >  fs/nfsd/nfssvc.c          |   6 +
> >  fs/nfsd/state.h           |  34 +++-
> >  fs/nfsd/xdr4.h            |  39 ++++-
> >  include/linux/nfs4.h      |  25 +++
> >  include/linux/nfs_fs.h    |   3 +-
> >  include/linux/nfs_fs_sb.h |   1 +
> >  include/linux/nfs_xdr.h   |  17 ++
> >  22 files changed, 1429 insertions(+), 121 deletions(-)
> >
> > --
> > 1.8.3.1
> >

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 00/19] client and server support for "inter" SSC copy
  2019-10-01 17:13   ` bfields
@ 2019-10-01 17:47     ` Olga Kornievskaia
  2019-10-01 17:50       ` J. Bruce Fields
  0 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-01 17:47 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: J. Bruce Fields, linux-nfs, Trond Myklebust, Anna Schumaker

On Tue, Oct 1, 2019 at 1:13 PM J. Bruce Fields <bfields@fieldses.org> wrote:
>
> On Mon, Sep 30, 2019 at 03:06:11PM -0400, Olga Kornievskaia wrote:
> > Have you had a chance to take a look at the new patch series and have
> > any more comments?
>
> Honestly, last time I checked I was having trouble finding things to
> complain about--it looked OK to me.
>
> But I'm not sure I understood the management of copy id's, should I
> should give it one more read.  And then agree on how to merge it.

Let me know what you would like to discuss about how copy ids are
managed on the server. I thought that cover letter plus commit
descriptions talk about how copy stateids and copy_notify states are
managed. Do you want me to cut and paste that together here? Yes I did
skip putting the same summary in v7 as I did in earlier submissions.

> I was thinking maybe you could give us a git branch based on 5.5-rc1 or
> 5.5-rc2, Trond (I think it's Trond this time?) could pull the client
> ones into his tree, and I could pull the rest into mine.

I do have git space on linux-nfs so I could put my patches there.
However, I'm confused about the ask to be based on 5.5-rc1 as we are
still on 5.4-rc. Are you estimating that review will skip pushing this
feature for 5.5 and you are aiming for 5.6? I guess just tell me of
whose (current) git branch you'd like me to based off. The last one
was of your tree and your branch was in 5.3-rc (my default is to go
from Trond's).

> Trond/Anna?
>
> --b.
>
> >
> > On Mon, Sep 16, 2019 at 5:13 PM Olga Kornievskaia
> > <olga.kornievskaia@gmail.com> wrote:
> > >
> > > v7:
> > > --- rebased patches ontop of Bruce's nfsd-next
> > >
> > > Olga Kornievskaia (19):
> > >   NFS NFSD: defining nl4_servers structure needed by both
> > >   NFS: add COPY_NOTIFY operation
> > >   NFS: add ca_source_server<> to COPY
> > >   NFS: also send OFFLOAD_CANCEL to source server
> > >   NFS: inter ssc open
> > >   NFS: skip recovery of copy open on dest server
> > >   NFS: for "inter" copy treat ESTALE as ENOTSUPP
> > >   NFS: COPY handle ERR_OFFLOAD_DENIED
> > >   NFS: handle source server reboot
> > >   NFS: replace cross device check in copy_file_range
> > >   NFSD fill-in netloc4 structure
> > >   NFSD add ca_source_server<> to COPY
> > >   NFSD return nfs4_stid in nfs4_preprocess_stateid_op
> > >   NFSD COPY_NOTIFY xdr
> > >   NFSD add COPY_NOTIFY operation
> > >   NFSD check stateids against copy stateids
> > >   NFSD generalize nfsd4_compound_state flag names
> > >   NFSD: allow inter server COPY to have a STALE source server fh
> > >   NFSD add nfs4 inter ssc to nfsd4_copy
> > >
> > >  fs/nfs/nfs42.h            |  15 +-
> > >  fs/nfs/nfs42proc.c        | 193 ++++++++++++++++----
> > >  fs/nfs/nfs42xdr.c         | 190 +++++++++++++++++++-
> > >  fs/nfs/nfs4_fs.h          |  11 ++
> > >  fs/nfs/nfs4client.c       |   2 +-
> > >  fs/nfs/nfs4file.c         | 125 ++++++++++++-
> > >  fs/nfs/nfs4proc.c         |   6 +-
> > >  fs/nfs/nfs4state.c        |  29 ++-
> > >  fs/nfs/nfs4xdr.c          |   1 +
> > >  fs/nfsd/Kconfig           |  10 ++
> > >  fs/nfsd/nfs4proc.c        | 436 +++++++++++++++++++++++++++++++++++++++++-----
> > >  fs/nfsd/nfs4state.c       | 215 ++++++++++++++++++++---
> > >  fs/nfsd/nfs4xdr.c         | 155 +++++++++++++++-
> > >  fs/nfsd/nfsd.h            |  32 ++++
> > >  fs/nfsd/nfsfh.h           |   5 +-
> > >  fs/nfsd/nfssvc.c          |   6 +
> > >  fs/nfsd/state.h           |  34 +++-
> > >  fs/nfsd/xdr4.h            |  39 ++++-
> > >  include/linux/nfs4.h      |  25 +++
> > >  include/linux/nfs_fs.h    |   3 +-
> > >  include/linux/nfs_fs_sb.h |   1 +
> > >  include/linux/nfs_xdr.h   |  17 ++
> > >  22 files changed, 1429 insertions(+), 121 deletions(-)
> > >
> > > --
> > > 1.8.3.1
> > >

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 00/19] client and server support for "inter" SSC copy
  2019-10-01 17:47     ` Olga Kornievskaia
@ 2019-10-01 17:50       ` J. Bruce Fields
  2019-10-01 19:03         ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: J. Bruce Fields @ 2019-10-01 17:50 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: J. Bruce Fields, linux-nfs, Trond Myklebust, Anna Schumaker

On Tue, Oct 01, 2019 at 01:47:22PM -0400, Olga Kornievskaia wrote:
> On Tue, Oct 1, 2019 at 1:13 PM J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > On Mon, Sep 30, 2019 at 03:06:11PM -0400, Olga Kornievskaia wrote:
> > > Have you had a chance to take a look at the new patch series and have
> > > any more comments?
> >
> > Honestly, last time I checked I was having trouble finding things to
> > complain about--it looked OK to me.
> >
> > But I'm not sure I understood the management of copy id's, should I
> > should give it one more read.  And then agree on how to merge it.
> 
> Let me know what you would like to discuss about how copy ids are
> managed on the server. I thought that cover letter plus commit
> descriptions talk about how copy stateids and copy_notify states are
> managed. Do you want me to cut and paste that together here? Yes I did
> skip putting the same summary in v7 as I did in earlier submissions.

You did fine, I just need to read it carefully and make sure I
understand.

> > I was thinking maybe you could give us a git branch based on 5.5-rc1 or
> > 5.5-rc2, Trond (I think it's Trond this time?) could pull the client
> > ones into his tree, and I could pull the rest into mine.
> 
> I do have git space on linux-nfs so I could put my patches there.
> However, I'm confused about the ask to be based on 5.5-rc1 as we are
> still on 5.4-rc.

Whoops, sorry, just a typo, I meant 5.4-rc.

--b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 00/19] client and server support for "inter" SSC copy
  2019-10-01 17:50       ` J. Bruce Fields
@ 2019-10-01 19:03         ` Olga Kornievskaia
  0 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-01 19:03 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: J. Bruce Fields, linux-nfs, Trond Myklebust, Anna Schumaker

On Tue, Oct 1, 2019 at 1:50 PM J. Bruce Fields <bfields@redhat.com> wrote:
>
> On Tue, Oct 01, 2019 at 01:47:22PM -0400, Olga Kornievskaia wrote:
> > On Tue, Oct 1, 2019 at 1:13 PM J. Bruce Fields <bfields@fieldses.org> wrote:
> > >
> > > On Mon, Sep 30, 2019 at 03:06:11PM -0400, Olga Kornievskaia wrote:
> > > > Have you had a chance to take a look at the new patch series and have
> > > > any more comments?
> > >
> > > Honestly, last time I checked I was having trouble finding things to
> > > complain about--it looked OK to me.
> > >
> > > But I'm not sure I understood the management of copy id's, should I
> > > should give it one more read.  And then agree on how to merge it.
> >
> > Let me know what you would like to discuss about how copy ids are
> > managed on the server. I thought that cover letter plus commit
> > descriptions talk about how copy stateids and copy_notify states are
> > managed. Do you want me to cut and paste that together here? Yes I did
> > skip putting the same summary in v7 as I did in earlier submissions.
>
> You did fine, I just need to read it carefully and make sure I
> understand.

Ok.

> > > I was thinking maybe you could give us a git branch based on 5.5-rc1 or
> > > 5.5-rc2, Trond (I think it's Trond this time?) could pull the client
> > > ones into his tree, and I could pull the rest into mine.
> >
> > I do have git space on linux-nfs so I could put my patches there.
> > However, I'm confused about the ask to be based on 5.5-rc1 as we are
> > still on 5.4-rc.
>
> Whoops, sorry, just a typo, I meant 5.4-rc.

Ok.  I have them in git://git.linux-nfs.org/projects/aglo/linux.git
linux-ssc-for-5.5 branch.
>
> --b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 15/19] NFSD add COPY_NOTIFY operation
  2019-09-16 21:13 ` [PATCH v7 15/19] NFSD add COPY_NOTIFY operation Olga Kornievskaia
@ 2019-10-01 20:59   ` bfields
  2019-10-02  0:14     ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: bfields @ 2019-10-01 20:59 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: trond.myklebust, anna.schumaker, bfields, linux-nfs

On Mon, Sep 16, 2019 at 05:13:49PM -0400, Olga Kornievskaia wrote:
> @@ -2914,7 +2983,8 @@ static bool client_has_state(struct nfs4_client *clp)
>  #endif
>  		|| !list_empty(&clp->cl_delegations)
>  		|| !list_empty(&clp->cl_sessions)
> -		|| !list_empty(&clp->async_copies);
> +		|| !list_empty(&clp->async_copies)
> +		|| client_has_copy_notifies(clp);

Sorry, remind me--how is the copy_notify stateid cleaned up?  Is it just
timed out by the laundromat thread, or is our client destroying it when
the copy is done?

I'm just wondering if this can result in NFSERR_CLID_INUSE just because
a copy was done recently.

--b.

>  }
>  
>  static __be32 copy_impl_id(struct nfs4_client *clp,
> @@ -5192,6 +5262,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
>  	struct list_head *pos, *next, reaplist;
>  	time_t cutoff = get_seconds() - nn->nfsd4_lease;
>  	time_t t, new_timeo = nn->nfsd4_lease;
> +	struct nfs4_cpntf_state *cps;
> +	copy_stateid_t *cps_t;
> +	int i;
>  
>  	dprintk("NFSD: laundromat service - starting\n");
>  
> @@ -5202,6 +5275,17 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
>  	dprintk("NFSD: end of grace period\n");
>  	nfsd4_end_grace(nn);
>  	INIT_LIST_HEAD(&reaplist);
> +
> +	spin_lock(&nn->s2s_cp_lock);
> +	idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
> +		cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
> +		if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
> +				!time_after((unsigned long)cps->cpntf_time,
> +				(unsigned long)cutoff))
> +			_free_cpntf_state_locked(nn, cps);
> +	}
> +	spin_unlock(&nn->s2s_cp_lock);
> +
>  	spin_lock(&nn->client_lock);
>  	list_for_each_safe(pos, next, &nn->client_lru) {
>  		clp = list_entry(pos, struct nfs4_client, cl_lru);
> @@ -5577,6 +5661,24 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
>  out:
>  	return status;
>  }
> +static void
> +_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> +{
> +	WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
> +	if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
> +		return;
> +	list_del(&cps->cp_list);
> +	idr_remove(&nn->s2s_cp_stateids,
> +		   cps->cp_stateid.stid.si_opaque.so_id);
> +	kfree(cps);
> +}
> +
> +void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> +{
> +	spin_lock(&nn->s2s_cp_lock);
> +	_free_cpntf_state_locked(nn, cps);
> +	spin_unlock(&nn->s2s_cp_lock);
> +}
>  
>  /*
>   * Checks for stateid operations
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index d9e7cbd..967b937 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -56,6 +56,14 @@
>  	stateid_opaque_t        si_opaque;
>  } stateid_t;
>  
> +typedef struct {
> +	stateid_t		stid;
> +#define NFS4_COPY_STID 1
> +#define NFS4_COPYNOTIFY_STID 2
> +	unsigned char		sc_type;
> +	refcount_t		sc_count;
> +} copy_stateid_t;
> +
>  #define STATEID_FMT	"(%08x/%08x/%08x/%08x)"
>  #define STATEID_VAL(s) \
>  	(s)->si_opaque.so_clid.cl_boot, \
> @@ -96,6 +104,7 @@ struct nfs4_stid {
>  #define NFS4_REVOKED_DELEG_STID 16
>  #define NFS4_CLOSED_DELEG_STID 32
>  #define NFS4_LAYOUT_STID 64
> +	struct list_head	sc_cp_list;
>  	unsigned char		sc_type;
>  	stateid_t		sc_stateid;
>  	spinlock_t		sc_lock;
> @@ -104,6 +113,17 @@ struct nfs4_stid {
>  	void			(*sc_free)(struct nfs4_stid *);
>  };
>  
> +/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
> + * parent OPEN/LOCK/DELEG stateid.
> + */
> +struct nfs4_cpntf_state {
> +	copy_stateid_t		cp_stateid;
> +	struct list_head	cp_list;	/* per parent nfs4_stid */
> +	stateid_t		cp_p_stateid;	/* copy of parent's stateid */
> +	clientid_t		cp_p_clid;	/* copy of parent's clid */
> +	time_t			cpntf_time;	/* last time stateid used */
> +};
> +
>  /*
>   * Represents a delegation stateid. The nfs4_client holds references to these
>   * and they are put when it is being destroyed or when the delegation is
> @@ -624,8 +644,10 @@ __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);
> +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
> +void nfs4_free_copy_state(struct nfsd4_copy *copy);
> +struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
> +			struct nfs4_stid *p_stid);
>  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);
> @@ -655,6 +677,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
>  extern void nfs4_put_copy(struct nfsd4_copy *copy);
>  extern struct nfsd4_copy *
>  find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
> +extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
> +				 struct nfs4_cpntf_state *cps);
>  static inline void get_nfs4_file(struct nfs4_file *fi)
>  {
>  	refcount_inc(&fi->fi_ref);
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 8231fe0..2937e06 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -542,7 +542,7 @@ struct nfsd4_copy {
>  	struct nfsd_file        *nf_src;
>  	struct nfsd_file        *nf_dst;
>  
> -	stateid_t		cp_stateid;
> +	copy_stateid_t		cp_stateid;
>  
>  	struct list_head	copies;
>  	struct task_struct	*copy_task;
> -- 
> 1.8.3.1

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 15/19] NFSD add COPY_NOTIFY operation
  2019-10-01 20:59   ` bfields
@ 2019-10-02  0:14     ` Olga Kornievskaia
  2019-10-02  1:35       ` J. Bruce Fields
  0 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-02  0:14 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Tue, Oct 1, 2019 at 4:59 PM J. Bruce Fields <bfields@fieldses.org> wrote:
>
> On Mon, Sep 16, 2019 at 05:13:49PM -0400, Olga Kornievskaia wrote:
> > @@ -2914,7 +2983,8 @@ static bool client_has_state(struct nfs4_client *clp)
> >  #endif
> >               || !list_empty(&clp->cl_delegations)
> >               || !list_empty(&clp->cl_sessions)
> > -             || !list_empty(&clp->async_copies);
> > +             || !list_empty(&clp->async_copies)
> > +             || client_has_copy_notifies(clp);
>
> Sorry, remind me--how is the copy_notify stateid cleaned up?  Is it just
> timed out by the laundromat thread, or is our client destroying it when
> the copy is done?

Copy_notify stateid in most cases should be removed by
nfs4_put_stid()/ the "parent" stateid going away (close, unlock,
delegreturn) (or in unlikely case, if the client sent an
OFFLOAD_CANCEL to the stateid, say if copy was canceled). Otherwise,
copy notify stateid will time out and be removed by the laundromat
thread. So if a client didn't send a close/unlock/delegreturn and
quickly tries to delete a clientid, it will get ERR_CLID_INUSE but I
think if there was no close, the server will have an issue of having
an open stateid state.

> I'm just wondering if this can result in NFSERR_CLID_INUSE just because
> a copy was done recently.
>
> --b.
>
> >  }
> >
> >  static __be32 copy_impl_id(struct nfs4_client *clp,
> > @@ -5192,6 +5262,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> >       struct list_head *pos, *next, reaplist;
> >       time_t cutoff = get_seconds() - nn->nfsd4_lease;
> >       time_t t, new_timeo = nn->nfsd4_lease;
> > +     struct nfs4_cpntf_state *cps;
> > +     copy_stateid_t *cps_t;
> > +     int i;
> >
> >       dprintk("NFSD: laundromat service - starting\n");
> >
> > @@ -5202,6 +5275,17 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> >       dprintk("NFSD: end of grace period\n");
> >       nfsd4_end_grace(nn);
> >       INIT_LIST_HEAD(&reaplist);
> > +
> > +     spin_lock(&nn->s2s_cp_lock);
> > +     idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
> > +             cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
> > +             if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
> > +                             !time_after((unsigned long)cps->cpntf_time,
> > +                             (unsigned long)cutoff))
> > +                     _free_cpntf_state_locked(nn, cps);
> > +     }
> > +     spin_unlock(&nn->s2s_cp_lock);
> > +
> >       spin_lock(&nn->client_lock);
> >       list_for_each_safe(pos, next, &nn->client_lru) {
> >               clp = list_entry(pos, struct nfs4_client, cl_lru);
> > @@ -5577,6 +5661,24 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
> >  out:
> >       return status;
> >  }
> > +static void
> > +_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > +{
> > +     WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
> > +     if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
> > +             return;
> > +     list_del(&cps->cp_list);
> > +     idr_remove(&nn->s2s_cp_stateids,
> > +                cps->cp_stateid.stid.si_opaque.so_id);
> > +     kfree(cps);
> > +}
> > +
> > +void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > +{
> > +     spin_lock(&nn->s2s_cp_lock);
> > +     _free_cpntf_state_locked(nn, cps);
> > +     spin_unlock(&nn->s2s_cp_lock);
> > +}
> >
> >  /*
> >   * Checks for stateid operations
> > diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> > index d9e7cbd..967b937 100644
> > --- a/fs/nfsd/state.h
> > +++ b/fs/nfsd/state.h
> > @@ -56,6 +56,14 @@
> >       stateid_opaque_t        si_opaque;
> >  } stateid_t;
> >
> > +typedef struct {
> > +     stateid_t               stid;
> > +#define NFS4_COPY_STID 1
> > +#define NFS4_COPYNOTIFY_STID 2
> > +     unsigned char           sc_type;
> > +     refcount_t              sc_count;
> > +} copy_stateid_t;
> > +
> >  #define STATEID_FMT  "(%08x/%08x/%08x/%08x)"
> >  #define STATEID_VAL(s) \
> >       (s)->si_opaque.so_clid.cl_boot, \
> > @@ -96,6 +104,7 @@ struct nfs4_stid {
> >  #define NFS4_REVOKED_DELEG_STID 16
> >  #define NFS4_CLOSED_DELEG_STID 32
> >  #define NFS4_LAYOUT_STID 64
> > +     struct list_head        sc_cp_list;
> >       unsigned char           sc_type;
> >       stateid_t               sc_stateid;
> >       spinlock_t              sc_lock;
> > @@ -104,6 +113,17 @@ struct nfs4_stid {
> >       void                    (*sc_free)(struct nfs4_stid *);
> >  };
> >
> > +/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
> > + * parent OPEN/LOCK/DELEG stateid.
> > + */
> > +struct nfs4_cpntf_state {
> > +     copy_stateid_t          cp_stateid;
> > +     struct list_head        cp_list;        /* per parent nfs4_stid */
> > +     stateid_t               cp_p_stateid;   /* copy of parent's stateid */
> > +     clientid_t              cp_p_clid;      /* copy of parent's clid */
> > +     time_t                  cpntf_time;     /* last time stateid used */
> > +};
> > +
> >  /*
> >   * Represents a delegation stateid. The nfs4_client holds references to these
> >   * and they are put when it is being destroyed or when the delegation is
> > @@ -624,8 +644,10 @@ __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);
> > +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
> > +void nfs4_free_copy_state(struct nfsd4_copy *copy);
> > +struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
> > +                     struct nfs4_stid *p_stid);
> >  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);
> > @@ -655,6 +677,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
> >  extern void nfs4_put_copy(struct nfsd4_copy *copy);
> >  extern struct nfsd4_copy *
> >  find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
> > +extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
> > +                              struct nfs4_cpntf_state *cps);
> >  static inline void get_nfs4_file(struct nfs4_file *fi)
> >  {
> >       refcount_inc(&fi->fi_ref);
> > diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> > index 8231fe0..2937e06 100644
> > --- a/fs/nfsd/xdr4.h
> > +++ b/fs/nfsd/xdr4.h
> > @@ -542,7 +542,7 @@ struct nfsd4_copy {
> >       struct nfsd_file        *nf_src;
> >       struct nfsd_file        *nf_dst;
> >
> > -     stateid_t               cp_stateid;
> > +     copy_stateid_t          cp_stateid;
> >
> >       struct list_head        copies;
> >       struct task_struct      *copy_task;
> > --
> > 1.8.3.1

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 15/19] NFSD add COPY_NOTIFY operation
  2019-10-02  0:14     ` Olga Kornievskaia
@ 2019-10-02  1:35       ` J. Bruce Fields
  2019-10-02 15:32         ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: J. Bruce Fields @ 2019-10-02  1:35 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Tue, Oct 01, 2019 at 08:14:39PM -0400, Olga Kornievskaia wrote:
> On Tue, Oct 1, 2019 at 4:59 PM J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > On Mon, Sep 16, 2019 at 05:13:49PM -0400, Olga Kornievskaia wrote:
> > > @@ -2914,7 +2983,8 @@ static bool client_has_state(struct nfs4_client *clp)
> > >  #endif
> > >               || !list_empty(&clp->cl_delegations)
> > >               || !list_empty(&clp->cl_sessions)
> > > -             || !list_empty(&clp->async_copies);
> > > +             || !list_empty(&clp->async_copies)
> > > +             || client_has_copy_notifies(clp);
> >
> > Sorry, remind me--how is the copy_notify stateid cleaned up?  Is it just
> > timed out by the laundromat thread, or is our client destroying it when
> > the copy is done?
> 
> Copy_notify stateid in most cases should be removed by
> nfs4_put_stid()/ the "parent" stateid going away (close, unlock,
> delegreturn)

Oh, right, the parent stateid going away will be enough, good.

But doesn't that mean the client_has_copy_notifies() check here is
redundant?  If it's true, then the earlier client_has_openowner() check
was also true.

--b.

> (or in unlikely case, if the client sent an
> OFFLOAD_CANCEL to the stateid, say if copy was canceled). Otherwise,
> copy notify stateid will time out and be removed by the laundromat
> thread. So if a client didn't send a close/unlock/delegreturn and
> quickly tries to delete a clientid, it will get ERR_CLID_INUSE but I
> think if there was no close, the server will have an issue of having
> an open stateid state.
> 
> > I'm just wondering if this can result in NFSERR_CLID_INUSE just because
> > a copy was done recently.
> >
> > --b.
> >
> > >  }
> > >
> > >  static __be32 copy_impl_id(struct nfs4_client *clp,
> > > @@ -5192,6 +5262,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> > >       struct list_head *pos, *next, reaplist;
> > >       time_t cutoff = get_seconds() - nn->nfsd4_lease;
> > >       time_t t, new_timeo = nn->nfsd4_lease;
> > > +     struct nfs4_cpntf_state *cps;
> > > +     copy_stateid_t *cps_t;
> > > +     int i;
> > >
> > >       dprintk("NFSD: laundromat service - starting\n");
> > >
> > > @@ -5202,6 +5275,17 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> > >       dprintk("NFSD: end of grace period\n");
> > >       nfsd4_end_grace(nn);
> > >       INIT_LIST_HEAD(&reaplist);
> > > +
> > > +     spin_lock(&nn->s2s_cp_lock);
> > > +     idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
> > > +             cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
> > > +             if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
> > > +                             !time_after((unsigned long)cps->cpntf_time,
> > > +                             (unsigned long)cutoff))
> > > +                     _free_cpntf_state_locked(nn, cps);
> > > +     }
> > > +     spin_unlock(&nn->s2s_cp_lock);
> > > +
> > >       spin_lock(&nn->client_lock);
> > >       list_for_each_safe(pos, next, &nn->client_lru) {
> > >               clp = list_entry(pos, struct nfs4_client, cl_lru);
> > > @@ -5577,6 +5661,24 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
> > >  out:
> > >       return status;
> > >  }
> > > +static void
> > > +_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > > +{
> > > +     WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
> > > +     if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
> > > +             return;
> > > +     list_del(&cps->cp_list);
> > > +     idr_remove(&nn->s2s_cp_stateids,
> > > +                cps->cp_stateid.stid.si_opaque.so_id);
> > > +     kfree(cps);
> > > +}
> > > +
> > > +void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > > +{
> > > +     spin_lock(&nn->s2s_cp_lock);
> > > +     _free_cpntf_state_locked(nn, cps);
> > > +     spin_unlock(&nn->s2s_cp_lock);
> > > +}
> > >
> > >  /*
> > >   * Checks for stateid operations
> > > diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> > > index d9e7cbd..967b937 100644
> > > --- a/fs/nfsd/state.h
> > > +++ b/fs/nfsd/state.h
> > > @@ -56,6 +56,14 @@
> > >       stateid_opaque_t        si_opaque;
> > >  } stateid_t;
> > >
> > > +typedef struct {
> > > +     stateid_t               stid;
> > > +#define NFS4_COPY_STID 1
> > > +#define NFS4_COPYNOTIFY_STID 2
> > > +     unsigned char           sc_type;
> > > +     refcount_t              sc_count;
> > > +} copy_stateid_t;
> > > +
> > >  #define STATEID_FMT  "(%08x/%08x/%08x/%08x)"
> > >  #define STATEID_VAL(s) \
> > >       (s)->si_opaque.so_clid.cl_boot, \
> > > @@ -96,6 +104,7 @@ struct nfs4_stid {
> > >  #define NFS4_REVOKED_DELEG_STID 16
> > >  #define NFS4_CLOSED_DELEG_STID 32
> > >  #define NFS4_LAYOUT_STID 64
> > > +     struct list_head        sc_cp_list;
> > >       unsigned char           sc_type;
> > >       stateid_t               sc_stateid;
> > >       spinlock_t              sc_lock;
> > > @@ -104,6 +113,17 @@ struct nfs4_stid {
> > >       void                    (*sc_free)(struct nfs4_stid *);
> > >  };
> > >
> > > +/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
> > > + * parent OPEN/LOCK/DELEG stateid.
> > > + */
> > > +struct nfs4_cpntf_state {
> > > +     copy_stateid_t          cp_stateid;
> > > +     struct list_head        cp_list;        /* per parent nfs4_stid */
> > > +     stateid_t               cp_p_stateid;   /* copy of parent's stateid */
> > > +     clientid_t              cp_p_clid;      /* copy of parent's clid */
> > > +     time_t                  cpntf_time;     /* last time stateid used */
> > > +};
> > > +
> > >  /*
> > >   * Represents a delegation stateid. The nfs4_client holds references to these
> > >   * and they are put when it is being destroyed or when the delegation is
> > > @@ -624,8 +644,10 @@ __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);
> > > +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
> > > +void nfs4_free_copy_state(struct nfsd4_copy *copy);
> > > +struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
> > > +                     struct nfs4_stid *p_stid);
> > >  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);
> > > @@ -655,6 +677,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
> > >  extern void nfs4_put_copy(struct nfsd4_copy *copy);
> > >  extern struct nfsd4_copy *
> > >  find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
> > > +extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
> > > +                              struct nfs4_cpntf_state *cps);
> > >  static inline void get_nfs4_file(struct nfs4_file *fi)
> > >  {
> > >       refcount_inc(&fi->fi_ref);
> > > diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> > > index 8231fe0..2937e06 100644
> > > --- a/fs/nfsd/xdr4.h
> > > +++ b/fs/nfsd/xdr4.h
> > > @@ -542,7 +542,7 @@ struct nfsd4_copy {
> > >       struct nfsd_file        *nf_src;
> > >       struct nfsd_file        *nf_dst;
> > >
> > > -     stateid_t               cp_stateid;
> > > +     copy_stateid_t          cp_stateid;
> > >
> > >       struct list_head        copies;
> > >       struct task_struct      *copy_task;
> > > --
> > > 1.8.3.1

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 15/19] NFSD add COPY_NOTIFY operation
  2019-10-02  1:35       ` J. Bruce Fields
@ 2019-10-02 15:32         ` Olga Kornievskaia
  0 siblings, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-02 15:32 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Tue, Oct 1, 2019 at 9:35 PM J. Bruce Fields <bfields@fieldses.org> wrote:
>
> On Tue, Oct 01, 2019 at 08:14:39PM -0400, Olga Kornievskaia wrote:
> > On Tue, Oct 1, 2019 at 4:59 PM J. Bruce Fields <bfields@fieldses.org> wrote:
> > >
> > > On Mon, Sep 16, 2019 at 05:13:49PM -0400, Olga Kornievskaia wrote:
> > > > @@ -2914,7 +2983,8 @@ static bool client_has_state(struct nfs4_client *clp)
> > > >  #endif
> > > >               || !list_empty(&clp->cl_delegations)
> > > >               || !list_empty(&clp->cl_sessions)
> > > > -             || !list_empty(&clp->async_copies);
> > > > +             || !list_empty(&clp->async_copies)
> > > > +             || client_has_copy_notifies(clp);
> > >
> > > Sorry, remind me--how is the copy_notify stateid cleaned up?  Is it just
> > > timed out by the laundromat thread, or is our client destroying it when
> > > the copy is done?
> >
> > Copy_notify stateid in most cases should be removed by
> > nfs4_put_stid()/ the "parent" stateid going away (close, unlock,
> > delegreturn)
>
> Oh, right, the parent stateid going away will be enough, good.
>
> But doesn't that mean the client_has_copy_notifies() check here is
> redundant?  If it's true, then the earlier client_has_openowner() check
> was also true.

Honestly, I didn't remove it because I didn't know if I was missing
some weird case where on clientid destruction we'd still have copy
notify left and thus need to delay it. But as you see nfs4_put_stid()
calls nfs4_free_cpntf_statelist() which iterates the list of the
copy_notify states and deletes them. Sounds like I should just remove
the client_has_copy_notifies() check.

>
> --b.
>
> > (or in unlikely case, if the client sent an
> > OFFLOAD_CANCEL to the stateid, say if copy was canceled). Otherwise,
> > copy notify stateid will time out and be removed by the laundromat
> > thread. So if a client didn't send a close/unlock/delegreturn and
> > quickly tries to delete a clientid, it will get ERR_CLID_INUSE but I
> > think if there was no close, the server will have an issue of having
> > an open stateid state.
> >
> > > I'm just wondering if this can result in NFSERR_CLID_INUSE just because
> > > a copy was done recently.
> > >
> > > --b.
> > >
> > > >  }
> > > >
> > > >  static __be32 copy_impl_id(struct nfs4_client *clp,
> > > > @@ -5192,6 +5262,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> > > >       struct list_head *pos, *next, reaplist;
> > > >       time_t cutoff = get_seconds() - nn->nfsd4_lease;
> > > >       time_t t, new_timeo = nn->nfsd4_lease;
> > > > +     struct nfs4_cpntf_state *cps;
> > > > +     copy_stateid_t *cps_t;
> > > > +     int i;
> > > >
> > > >       dprintk("NFSD: laundromat service - starting\n");
> > > >
> > > > @@ -5202,6 +5275,17 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
> > > >       dprintk("NFSD: end of grace period\n");
> > > >       nfsd4_end_grace(nn);
> > > >       INIT_LIST_HEAD(&reaplist);
> > > > +
> > > > +     spin_lock(&nn->s2s_cp_lock);
> > > > +     idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
> > > > +             cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
> > > > +             if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
> > > > +                             !time_after((unsigned long)cps->cpntf_time,
> > > > +                             (unsigned long)cutoff))
> > > > +                     _free_cpntf_state_locked(nn, cps);
> > > > +     }
> > > > +     spin_unlock(&nn->s2s_cp_lock);
> > > > +
> > > >       spin_lock(&nn->client_lock);
> > > >       list_for_each_safe(pos, next, &nn->client_lru) {
> > > >               clp = list_entry(pos, struct nfs4_client, cl_lru);
> > > > @@ -5577,6 +5661,24 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
> > > >  out:
> > > >       return status;
> > > >  }
> > > > +static void
> > > > +_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > > > +{
> > > > +     WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
> > > > +     if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
> > > > +             return;
> > > > +     list_del(&cps->cp_list);
> > > > +     idr_remove(&nn->s2s_cp_stateids,
> > > > +                cps->cp_stateid.stid.si_opaque.so_id);
> > > > +     kfree(cps);
> > > > +}
> > > > +
> > > > +void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
> > > > +{
> > > > +     spin_lock(&nn->s2s_cp_lock);
> > > > +     _free_cpntf_state_locked(nn, cps);
> > > > +     spin_unlock(&nn->s2s_cp_lock);
> > > > +}
> > > >
> > > >  /*
> > > >   * Checks for stateid operations
> > > > diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> > > > index d9e7cbd..967b937 100644
> > > > --- a/fs/nfsd/state.h
> > > > +++ b/fs/nfsd/state.h
> > > > @@ -56,6 +56,14 @@
> > > >       stateid_opaque_t        si_opaque;
> > > >  } stateid_t;
> > > >
> > > > +typedef struct {
> > > > +     stateid_t               stid;
> > > > +#define NFS4_COPY_STID 1
> > > > +#define NFS4_COPYNOTIFY_STID 2
> > > > +     unsigned char           sc_type;
> > > > +     refcount_t              sc_count;
> > > > +} copy_stateid_t;
> > > > +
> > > >  #define STATEID_FMT  "(%08x/%08x/%08x/%08x)"
> > > >  #define STATEID_VAL(s) \
> > > >       (s)->si_opaque.so_clid.cl_boot, \
> > > > @@ -96,6 +104,7 @@ struct nfs4_stid {
> > > >  #define NFS4_REVOKED_DELEG_STID 16
> > > >  #define NFS4_CLOSED_DELEG_STID 32
> > > >  #define NFS4_LAYOUT_STID 64
> > > > +     struct list_head        sc_cp_list;
> > > >       unsigned char           sc_type;
> > > >       stateid_t               sc_stateid;
> > > >       spinlock_t              sc_lock;
> > > > @@ -104,6 +113,17 @@ struct nfs4_stid {
> > > >       void                    (*sc_free)(struct nfs4_stid *);
> > > >  };
> > > >
> > > > +/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
> > > > + * parent OPEN/LOCK/DELEG stateid.
> > > > + */
> > > > +struct nfs4_cpntf_state {
> > > > +     copy_stateid_t          cp_stateid;
> > > > +     struct list_head        cp_list;        /* per parent nfs4_stid */
> > > > +     stateid_t               cp_p_stateid;   /* copy of parent's stateid */
> > > > +     clientid_t              cp_p_clid;      /* copy of parent's clid */
> > > > +     time_t                  cpntf_time;     /* last time stateid used */
> > > > +};
> > > > +
> > > >  /*
> > > >   * Represents a delegation stateid. The nfs4_client holds references to these
> > > >   * and they are put when it is being destroyed or when the delegation is
> > > > @@ -624,8 +644,10 @@ __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);
> > > > +int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
> > > > +void nfs4_free_copy_state(struct nfsd4_copy *copy);
> > > > +struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
> > > > +                     struct nfs4_stid *p_stid);
> > > >  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);
> > > > @@ -655,6 +677,8 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
> > > >  extern void nfs4_put_copy(struct nfsd4_copy *copy);
> > > >  extern struct nfsd4_copy *
> > > >  find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
> > > > +extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
> > > > +                              struct nfs4_cpntf_state *cps);
> > > >  static inline void get_nfs4_file(struct nfs4_file *fi)
> > > >  {
> > > >       refcount_inc(&fi->fi_ref);
> > > > diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> > > > index 8231fe0..2937e06 100644
> > > > --- a/fs/nfsd/xdr4.h
> > > > +++ b/fs/nfsd/xdr4.h
> > > > @@ -542,7 +542,7 @@ struct nfsd4_copy {
> > > >       struct nfsd_file        *nf_src;
> > > >       struct nfsd_file        *nf_dst;
> > > >
> > > > -     stateid_t               cp_stateid;
> > > > +     copy_stateid_t          cp_stateid;
> > > >
> > > >       struct list_head        copies;
> > > >       struct task_struct      *copy_task;
> > > > --
> > > > 1.8.3.1

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-09-16 21:13 ` [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op Olga Kornievskaia
@ 2019-10-02 15:52   ` bfields
  2019-10-02 16:12     ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: bfields @ 2019-10-02 15:52 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: trond.myklebust, anna.schumaker, bfields, linux-nfs

On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
>  static __be32
>  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  		  stateid_t *src_stateid, struct nfsd_file **src,
> -		  stateid_t *dst_stateid, struct nfsd_file **dst)
> +		  stateid_t *dst_stateid, struct nfsd_file **dst,
> +		  struct nfs4_stid **stid)
>  {
>  	__be32 status;
>  
...
> @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
>  	__be32 status;
>  
>  	status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> -				   &clone->cl_dst_stateid, &dst);
> +				   &clone->cl_dst_stateid, &dst, NULL);
>  	if (status)
>  		goto out;
>  
> @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
>  
>  	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
>  				   &copy->nf_src, &copy->cp_dst_stateid,
> -				   &copy->nf_dst);
> +				   &copy->nf_dst, NULL);
>  	if (status)
>  		goto out;
>  

So both callers pass NULL for the new stid parameter.  Looks like that's
still true after the full series of patches, too.

--b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-10-02 15:52   ` bfields
@ 2019-10-02 16:12     ` Olga Kornievskaia
  2019-10-02 16:15       ` Olga Kornievskaia
  2019-10-02 16:34       ` J. Bruce Fields
  0 siblings, 2 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-02 16:12 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Wed, Oct 2, 2019 at 11:52 AM J. Bruce Fields <bfields@fieldses.org> wrote:
>
> On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> > @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> >  static __be32
> >  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> >                 stateid_t *src_stateid, struct nfsd_file **src,
> > -               stateid_t *dst_stateid, struct nfsd_file **dst)
> > +               stateid_t *dst_stateid, struct nfsd_file **dst,
> > +               struct nfs4_stid **stid)
> >  {
> >       __be32 status;
> >
> ...
> > @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> >       __be32 status;
> >
> >       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> > -                                &clone->cl_dst_stateid, &dst);
> > +                                &clone->cl_dst_stateid, &dst, NULL);
> >       if (status)
> >               goto out;
> >
> > @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
> >
> >       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
> >                                  &copy->nf_src, &copy->cp_dst_stateid,
> > -                                &copy->nf_dst);
> > +                                &copy->nf_dst, NULL);
> >       if (status)
> >               goto out;
> >
>
> So both callers pass NULL for the new stid parameter.  Looks like that's
> still true after the full series of patches, too.
>

If you look at an earlier chunk it uses it (there is only a single
user of it: copy notify state)
@@ -1034,14 +1035,14 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst
*rqstp, struct svc_fh *fh)
                return nfserr_nofilehandle;

        status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
-                                           src_stateid, RD_STATE, src);
+                                           src_stateid, RD_STATE, src, NULL);
        if (status) {
                dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
                goto out;
        }

        status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
-                                           dst_stateid, WR_STATE, dst);
+                                           dst_stateid, WR_STATE, dst, stid);
        if (status) {
                dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
                goto out_put_src;

> --b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-10-02 16:12     ` Olga Kornievskaia
@ 2019-10-02 16:15       ` Olga Kornievskaia
  2019-10-02 16:34       ` J. Bruce Fields
  1 sibling, 0 replies; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-02 16:15 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Wed, Oct 2, 2019 at 12:12 PM Olga Kornievskaia
<olga.kornievskaia@gmail.com> wrote:
>
> On Wed, Oct 2, 2019 at 11:52 AM J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> > > @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > >  static __be32
> > >  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > >                 stateid_t *src_stateid, struct nfsd_file **src,
> > > -               stateid_t *dst_stateid, struct nfsd_file **dst)
> > > +               stateid_t *dst_stateid, struct nfsd_file **dst,
> > > +               struct nfs4_stid **stid)
> > >  {
> > >       __be32 status;
> > >
> > ...
> > > @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > >       __be32 status;
> > >
> > >       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> > > -                                &clone->cl_dst_stateid, &dst);
> > > +                                &clone->cl_dst_stateid, &dst, NULL);
> > >       if (status)
> > >               goto out;
> > >
> > > @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
> > >
> > >       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
> > >                                  &copy->nf_src, &copy->cp_dst_stateid,
> > > -                                &copy->nf_dst);
> > > +                                &copy->nf_dst, NULL);
> > >       if (status)
> > >               goto out;
> > >
> >
> > So both callers pass NULL for the new stid parameter.  Looks like that's
> > still true after the full series of patches, too.
> >
>
> If you look at an earlier chunk it uses it (there is only a single
> user of it: copy notify state)

actually the 2 user nfsd4_verify_copy and nfsd4_copy_notify in a different patch

> @@ -1034,14 +1035,14 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst
> *rqstp, struct svc_fh *fh)
>                 return nfserr_nofilehandle;
>
>         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
> -                                           src_stateid, RD_STATE, src);
> +                                           src_stateid, RD_STATE, src, NULL);
>         if (status) {
>                 dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
>                 goto out;
>         }
>
>         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
> -                                           dst_stateid, WR_STATE, dst);
> +                                           dst_stateid, WR_STATE, dst, stid);
>         if (status) {
>                 dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
>                 goto out_put_src;
>
> > --b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-10-02 16:12     ` Olga Kornievskaia
  2019-10-02 16:15       ` Olga Kornievskaia
@ 2019-10-02 16:34       ` J. Bruce Fields
  2019-10-02 16:52         ` Olga Kornievskaia
  1 sibling, 1 reply; 39+ messages in thread
From: J. Bruce Fields @ 2019-10-02 16:34 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: J. Bruce Fields, trond.myklebust, Anna Schumaker, linux-nfs

On Wed, Oct 02, 2019 at 12:12:17PM -0400, Olga Kornievskaia wrote:
> On Wed, Oct 2, 2019 at 11:52 AM J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> > > @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > >  static __be32
> > >  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > >                 stateid_t *src_stateid, struct nfsd_file **src,
> > > -               stateid_t *dst_stateid, struct nfsd_file **dst)
> > > +               stateid_t *dst_stateid, struct nfsd_file **dst,
> > > +               struct nfs4_stid **stid)
> > >  {
> > >       __be32 status;
> > >
> > ...
> > > @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > >       __be32 status;
> > >
> > >       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> > > -                                &clone->cl_dst_stateid, &dst);
> > > +                                &clone->cl_dst_stateid, &dst, NULL);
> > >       if (status)
> > >               goto out;
> > >
> > > @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
> > >
> > >       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
> > >                                  &copy->nf_src, &copy->cp_dst_stateid,
> > > -                                &copy->nf_dst);
> > > +                                &copy->nf_dst, NULL);
> > >       if (status)
> > >               goto out;
> > >
> >
> > So both callers pass NULL for the new stid parameter.  Looks like that's
> > still true after the full series of patches, too.
> >
> 
> If you look at an earlier chunk it uses it (there is only a single
> user of it: copy notify state)

You're talking about nfs4_preprocess_stateid_op, the above is
nfsd4_verify_copy.

--b.

> @@ -1034,14 +1035,14 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst
> *rqstp, struct svc_fh *fh)
>                 return nfserr_nofilehandle;
> 
>         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
> -                                           src_stateid, RD_STATE, src);
> +                                           src_stateid, RD_STATE, src, NULL);
>         if (status) {
>                 dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
>                 goto out;
>         }
> 
>         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
> -                                           dst_stateid, WR_STATE, dst);
> +                                           dst_stateid, WR_STATE, dst, stid);
>         if (status) {
>                 dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
>                 goto out_put_src;
> 
> > --b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-10-02 16:34       ` J. Bruce Fields
@ 2019-10-02 16:52         ` Olga Kornievskaia
  2019-10-02 16:57           ` J. Bruce Fields
  0 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-02 16:52 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: J. Bruce Fields, trond.myklebust, Anna Schumaker, linux-nfs

On Wed, Oct 2, 2019 at 12:34 PM J. Bruce Fields <bfields@redhat.com> wrote:
>
> On Wed, Oct 02, 2019 at 12:12:17PM -0400, Olga Kornievskaia wrote:
> > On Wed, Oct 2, 2019 at 11:52 AM J. Bruce Fields <bfields@fieldses.org> wrote:
> > >
> > > On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> > > > @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > > >  static __be32
> > > >  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > >                 stateid_t *src_stateid, struct nfsd_file **src,
> > > > -               stateid_t *dst_stateid, struct nfsd_file **dst)
> > > > +               stateid_t *dst_stateid, struct nfsd_file **dst,
> > > > +               struct nfs4_stid **stid)
> > > >  {
> > > >       __be32 status;
> > > >
> > > ...
> > > > @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > > >       __be32 status;
> > > >
> > > >       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> > > > -                                &clone->cl_dst_stateid, &dst);
> > > > +                                &clone->cl_dst_stateid, &dst, NULL);
> > > >       if (status)
> > > >               goto out;
> > > >
> > > > @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
> > > >
> > > >       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
> > > >                                  &copy->nf_src, &copy->cp_dst_stateid,
> > > > -                                &copy->nf_dst);
> > > > +                                &copy->nf_dst, NULL);
> > > >       if (status)
> > > >               goto out;
> > > >
> > >
> > > So both callers pass NULL for the new stid parameter.  Looks like that's
> > > still true after the full series of patches, too.
> > >
> >
> > If you look at an earlier chunk it uses it (there is only a single
> > user of it: copy notify state)
>
> You're talking about nfs4_preprocess_stateid_op, the above is
> nfsd4_verify_copy.

I see. You are right, looks like after reworks the nfsd4_verify_copy
doesn't need a stid. Previously both copy stateid and copy_notify
stateids were tied to its parents but I've removed the link for the
copy stateid a while back. Should I now combine this patch with "NFSD
add COPY_NOTIFY operation" because that's the only caller of
nfsd4_preprocess_stateid_op that needs the stid.

>
> --b.
>
> > @@ -1034,14 +1035,14 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst
> > *rqstp, struct svc_fh *fh)
> >                 return nfserr_nofilehandle;
> >
> >         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
> > -                                           src_stateid, RD_STATE, src);
> > +                                           src_stateid, RD_STATE, src, NULL);
> >         if (status) {
> >                 dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
> >                 goto out;
> >         }
> >
> >         status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
> > -                                           dst_stateid, WR_STATE, dst);
> > +                                           dst_stateid, WR_STATE, dst, stid);
> >         if (status) {
> >                 dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
> >                 goto out_put_src;
> >
> > > --b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op
  2019-10-02 16:52         ` Olga Kornievskaia
@ 2019-10-02 16:57           ` J. Bruce Fields
  0 siblings, 0 replies; 39+ messages in thread
From: J. Bruce Fields @ 2019-10-02 16:57 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: J. Bruce Fields, trond.myklebust, Anna Schumaker, linux-nfs

On Wed, Oct 02, 2019 at 12:52:37PM -0400, Olga Kornievskaia wrote:
> On Wed, Oct 2, 2019 at 12:34 PM J. Bruce Fields <bfields@redhat.com> wrote:
> >
> > On Wed, Oct 02, 2019 at 12:12:17PM -0400, Olga Kornievskaia wrote:
> > > On Wed, Oct 2, 2019 at 11:52 AM J. Bruce Fields <bfields@fieldses.org> wrote:
> > > >
> > > > On Mon, Sep 16, 2019 at 05:13:47PM -0400, Olga Kornievskaia wrote:
> > > > > @@ -1026,7 +1026,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > > > >  static __be32
> > > > >  nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > > > >                 stateid_t *src_stateid, struct nfsd_file **src,
> > > > > -               stateid_t *dst_stateid, struct nfsd_file **dst)
> > > > > +               stateid_t *dst_stateid, struct nfsd_file **dst,
> > > > > +               struct nfs4_stid **stid)
> > > > >  {
> > > > >       __be32 status;
> > > > >
> > > > ...
> > > > > @@ -1072,7 +1073,7 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
> > > > >       __be32 status;
> > > > >
> > > > >       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
> > > > > -                                &clone->cl_dst_stateid, &dst);
> > > > > +                                &clone->cl_dst_stateid, &dst, NULL);
> > > > >       if (status)
> > > > >               goto out;
> > > > >
> > > > > @@ -1260,7 +1261,7 @@ static int nfsd4_do_async_copy(void *data)
> > > > >
> > > > >       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
> > > > >                                  &copy->nf_src, &copy->cp_dst_stateid,
> > > > > -                                &copy->nf_dst);
> > > > > +                                &copy->nf_dst, NULL);
> > > > >       if (status)
> > > > >               goto out;
> > > > >
> > > >
> > > > So both callers pass NULL for the new stid parameter.  Looks like that's
> > > > still true after the full series of patches, too.
> > > >
> > >
> > > If you look at an earlier chunk it uses it (there is only a single
> > > user of it: copy notify state)
> >
> > You're talking about nfs4_preprocess_stateid_op, the above is
> > nfsd4_verify_copy.
> 
> I see. You are right, looks like after reworks the nfsd4_verify_copy
> doesn't need a stid. Previously both copy stateid and copy_notify
> stateids were tied to its parents but I've removed the link for the
> copy stateid a while back. Should I now combine this patch with "NFSD
> add COPY_NOTIFY operation" because that's the only caller of
> nfsd4_preprocess_stateid_op that needs the stid.

Yeah, maybe so.

--b.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh
  2019-09-16 21:13 ` [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh Olga Kornievskaia
@ 2019-10-02 19:55   ` bfields
  2019-10-07 14:31     ` Olga Kornievskaia
  0 siblings, 1 reply; 39+ messages in thread
From: bfields @ 2019-10-02 19:55 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: trond.myklebust, anna.schumaker, bfields, linux-nfs

On Mon, Sep 16, 2019 at 05:13:52PM -0400, Olga Kornievskaia wrote:
> @@ -1956,6 +1964,45 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
>  		- rqstp->rq_auth_slack;
>  }
>  
> +#ifdef CONFIG_NFSD_V4_2_INTER_SSC
> +static __be32
> +check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
> +{
> +	struct nfsd4_op	*op, *current_op, *saved_op;

current_op and saved_op need to be initialized to NULL here.

> +	struct nfsd4_copy *copy;
> +	struct nfsd4_putfh *putfh;
> +	int i;
> +
> +	/* traverse all operation and if it's a COPY compound, mark the
> +	 * source filehandle to skip verification
> +	 */
> +	for (i = 0; i < args->opcnt; i++) {
> +		op = &args->ops[i];
> +		if (op->opnum == OP_PUTFH)
> +			current_op = op;
> +		else if (op->opnum == OP_SAVEFH)
> +			saved_op = current_op;
> +		else if (op->opnum == OP_RESTOREFH)
> +			current_op = saved_op;
> +		else if (op->opnum == OP_COPY) {
> +			copy = (struct nfsd4_copy *)&op->u;
> +			if (!saved_op)
> +				return nfserr_nofilehandle;

Looks like this results in returning an empty compound result with just
the bare result.  I believe what we need to do is execute all the
ops preceding the COPY normally, then return the nofilehandle error on
the COPY.

One approach might be

		if (!saved_op) {
			op->status = nfserr_nofilehandle;
			return;
		}

and change check_if_stalefh_allowed to have no return value.

--b.

> +			putfh = (struct nfsd4_putfh *)&saved_op->u;
> +			if (!copy->cp_intra)
> +				putfh->no_verify = true;
> +		}
> +	}
> +	return nfs_ok;
> +}
...
> @@ -2004,6 +2051,9 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
>  		resp->opcnt = 1;
>  		goto encode_op;
>  	}
> +	status = check_if_stalefh_allowed(args);
> +	if (status)
> +		goto out;

>  
>  	trace_nfsd_compound(rqstp, args->opcnt);
>  	while (!status && resp->opcnt < args->opcnt) {

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh
  2019-10-02 19:55   ` bfields
@ 2019-10-07 14:31     ` Olga Kornievskaia
  2019-10-07 18:20       ` J. Bruce Fields
  0 siblings, 1 reply; 39+ messages in thread
From: Olga Kornievskaia @ 2019-10-07 14:31 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Wed, Oct 2, 2019 at 3:55 PM J. Bruce Fields <bfields@fieldses.org> wrote:
>
> On Mon, Sep 16, 2019 at 05:13:52PM -0400, Olga Kornievskaia wrote:
> > @@ -1956,6 +1964,45 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
> >               - rqstp->rq_auth_slack;
> >  }
> >
> > +#ifdef CONFIG_NFSD_V4_2_INTER_SSC
> > +static __be32
> > +check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
> > +{
> > +     struct nfsd4_op *op, *current_op, *saved_op;
>
> current_op and saved_op need to be initialized to NULL here.
>
> > +     struct nfsd4_copy *copy;
> > +     struct nfsd4_putfh *putfh;
> > +     int i;
> > +
> > +     /* traverse all operation and if it's a COPY compound, mark the
> > +      * source filehandle to skip verification
> > +      */
> > +     for (i = 0; i < args->opcnt; i++) {
> > +             op = &args->ops[i];
> > +             if (op->opnum == OP_PUTFH)
> > +                     current_op = op;
> > +             else if (op->opnum == OP_SAVEFH)
> > +                     saved_op = current_op;
> > +             else if (op->opnum == OP_RESTOREFH)
> > +                     current_op = saved_op;
> > +             else if (op->opnum == OP_COPY) {
> > +                     copy = (struct nfsd4_copy *)&op->u;
> > +                     if (!saved_op)
> > +                             return nfserr_nofilehandle;
>
> Looks like this results in returning an empty compound result with just
> the bare result.  I believe what we need to do is execute all the
> ops preceding the COPY normally, then return the nofilehandle error on
> the COPY.
>
> One approach might be
>
>                 if (!saved_op) {
>                         op->status = nfserr_nofilehandle;
>                         return;
>                 }
>
> and change check_if_stalefh_allowed to have no return value.

Ok thanks. I'm just curious if op->status assignment is necessary or I
can just do a return. When nfsd4_copy() calls nfs4_verify_copy() it
would check
        if (!cstate->save_fh.fh_dentry)
                return nfserr_nofilehandle;

>
> --b.
>
> > +                     putfh = (struct nfsd4_putfh *)&saved_op->u;
> > +                     if (!copy->cp_intra)
> > +                             putfh->no_verify = true;
> > +             }
> > +     }
> > +     return nfs_ok;
> > +}
> ...
> > @@ -2004,6 +2051,9 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
> >               resp->opcnt = 1;
> >               goto encode_op;
> >       }
> > +     status = check_if_stalefh_allowed(args);
> > +     if (status)
> > +             goto out;
>
> >
> >       trace_nfsd_compound(rqstp, args->opcnt);
> >       while (!status && resp->opcnt < args->opcnt) {

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh
  2019-10-07 14:31     ` Olga Kornievskaia
@ 2019-10-07 18:20       ` J. Bruce Fields
  0 siblings, 0 replies; 39+ messages in thread
From: J. Bruce Fields @ 2019-10-07 18:20 UTC (permalink / raw)
  To: Olga Kornievskaia
  Cc: trond.myklebust, Anna Schumaker, J. Bruce Fields, linux-nfs

On Mon, Oct 07, 2019 at 10:31:04AM -0400, Olga Kornievskaia wrote:
> On Wed, Oct 2, 2019 at 3:55 PM J. Bruce Fields <bfields@fieldses.org> wrote:
> >
> > On Mon, Sep 16, 2019 at 05:13:52PM -0400, Olga Kornievskaia wrote:
> > > @@ -1956,6 +1964,45 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
> > >               - rqstp->rq_auth_slack;
> > >  }
> > >
> > > +#ifdef CONFIG_NFSD_V4_2_INTER_SSC
> > > +static __be32
> > > +check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
> > > +{
> > > +     struct nfsd4_op *op, *current_op, *saved_op;
> >
> > current_op and saved_op need to be initialized to NULL here.
> >
> > > +     struct nfsd4_copy *copy;
> > > +     struct nfsd4_putfh *putfh;
> > > +     int i;
> > > +
> > > +     /* traverse all operation and if it's a COPY compound, mark the
> > > +      * source filehandle to skip verification
> > > +      */
> > > +     for (i = 0; i < args->opcnt; i++) {
> > > +             op = &args->ops[i];
> > > +             if (op->opnum == OP_PUTFH)
> > > +                     current_op = op;
> > > +             else if (op->opnum == OP_SAVEFH)
> > > +                     saved_op = current_op;
> > > +             else if (op->opnum == OP_RESTOREFH)
> > > +                     current_op = saved_op;
> > > +             else if (op->opnum == OP_COPY) {
> > > +                     copy = (struct nfsd4_copy *)&op->u;
> > > +                     if (!saved_op)
> > > +                             return nfserr_nofilehandle;
> >
> > Looks like this results in returning an empty compound result with just
> > the bare result.  I believe what we need to do is execute all the
> > ops preceding the COPY normally, then return the nofilehandle error on
> > the COPY.
> >
> > One approach might be
> >
> >                 if (!saved_op) {
> >                         op->status = nfserr_nofilehandle;
> >                         return;
> >                 }
> >
> > and change check_if_stalefh_allowed to have no return value.
> 
> Ok thanks. I'm just curious if op->status assignment is necessary or I
> can just do a return. When nfsd4_copy() calls nfs4_verify_copy() it
> would check
>         if (!cstate->save_fh.fh_dentry)
>                 return nfserr_nofilehandle;

Catching the error here might be a little safer if you think there's
ever a risk of messing up the later logic?  But, really, either should
work.

Since a real client is never going to hit any interesting cases here, it
could be useful to have a pynfs test or two that sent some weird illegal
compounds.

--b.

> 
> >
> > --b.
> >
> > > +                     putfh = (struct nfsd4_putfh *)&saved_op->u;
> > > +                     if (!copy->cp_intra)
> > > +                             putfh->no_verify = true;
> > > +             }
> > > +     }
> > > +     return nfs_ok;
> > > +}
> > ...
> > > @@ -2004,6 +2051,9 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
> > >               resp->opcnt = 1;
> > >               goto encode_op;
> > >       }
> > > +     status = check_if_stalefh_allowed(args);
> > > +     if (status)
> > > +             goto out;
> >
> > >
> > >       trace_nfsd_compound(rqstp, args->opcnt);
> > >       while (!status && resp->opcnt < args->opcnt) {

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, back to index

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-16 21:13 [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 01/19] NFS NFSD: defining nl4_servers structure needed by both Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 02/19] NFS: add COPY_NOTIFY operation Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 03/19] NFS: add ca_source_server<> to COPY Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 04/19] NFS: also send OFFLOAD_CANCEL to source server Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 05/19] NFS: inter ssc open Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 06/19] NFS: skip recovery of copy open on dest server Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 07/19] NFS: for "inter" copy treat ESTALE as ENOTSUPP Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 08/19] NFS: COPY handle ERR_OFFLOAD_DENIED Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 09/19] NFS: handle source server reboot Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 10/19] NFS: replace cross device check in copy_file_range Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 11/19] NFSD fill-in netloc4 structure Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 12/19] NFSD add ca_source_server<> to COPY Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 13/19] NFSD return nfs4_stid in nfs4_preprocess_stateid_op Olga Kornievskaia
2019-10-02 15:52   ` bfields
2019-10-02 16:12     ` Olga Kornievskaia
2019-10-02 16:15       ` Olga Kornievskaia
2019-10-02 16:34       ` J. Bruce Fields
2019-10-02 16:52         ` Olga Kornievskaia
2019-10-02 16:57           ` J. Bruce Fields
2019-09-16 21:13 ` [PATCH v7 14/19] NFSD COPY_NOTIFY xdr Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 15/19] NFSD add COPY_NOTIFY operation Olga Kornievskaia
2019-10-01 20:59   ` bfields
2019-10-02  0:14     ` Olga Kornievskaia
2019-10-02  1:35       ` J. Bruce Fields
2019-10-02 15:32         ` Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 16/19] NFSD check stateids against copy stateids Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 17/19] NFSD generalize nfsd4_compound_state flag names Olga Kornievskaia
2019-09-16 21:13 ` [PATCH v7 18/19] NFSD: allow inter server COPY to have a STALE source server fh Olga Kornievskaia
2019-10-02 19:55   ` bfields
2019-10-07 14:31     ` Olga Kornievskaia
2019-10-07 18:20       ` J. Bruce Fields
2019-09-16 21:13 ` [PATCH v7 19/19] NFSD add nfs4 inter ssc to nfsd4_copy Olga Kornievskaia
2019-09-19 19:55   ` [PATCH 1/1] " Olga Kornievskaia
2019-09-30 19:06 ` [PATCH v7 00/19] client and server support for "inter" SSC copy Olga Kornievskaia
2019-10-01 17:13   ` bfields
2019-10-01 17:47     ` Olga Kornievskaia
2019-10-01 17:50       ` J. Bruce Fields
2019-10-01 19:03         ` Olga Kornievskaia

Linux-NFS Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-nfs/0 linux-nfs/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-nfs linux-nfs/ https://lore.kernel.org/linux-nfs \
		linux-nfs@vger.kernel.org
	public-inbox-index linux-nfs

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-nfs


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git