linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: bfields@fieldses.org (J. Bruce Fields)
To: Olga Kornievskaia <kolga@netapp.com>
Cc: Trond.Myklebust@primarydata.com, anna.schumaker@netapp.com,
	bfields@redhat.com, linux-nfs@vger.kernel.org
Subject: Re: [RFC v3 28/42] NFSD add nfs4 inter ssc to nfsd4_copy
Date: Fri, 8 Sep 2017 16:28:13 -0400	[thread overview]
Message-ID: <20170908202813.GC18220@fieldses.org> (raw)
In-Reply-To: <20170711164416.1982-29-kolga@netapp.com>

On Tue, Jul 11, 2017 at 12:44:02PM -0400, Olga Kornievskaia wrote:
> 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.
> 
> Add Kconfig dependencies for inter server to server copy
> 
> Signed-off-by: Andy Adamson <andros@netapp.com>
> ---
>  fs/nfsd/Kconfig      |  10 ++
>  fs/nfsd/nfs4proc.c   | 262 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/nfs4.h |   1 +
>  3 files changed, 263 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
> index 20b1c17..37ff3d5 100644
> --- a/fs/nfsd/Kconfig
> +++ b/fs/nfsd/Kconfig
> @@ -131,6 +131,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 ceee852..b1095e9 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1072,16 +1072,227 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
>  	return status;
>  }
>  
> +#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 struct file *nfs42_ssc_close(struct file *filep);
> +
> +extern void nfs_sb_deactive(struct super_block *sb);
> +
> +#define NFSD42_INTERSSC_RAWDATA "minorversion=2,vers=4,addr=%s,clientaddr=%s"

INTERSCC_RAWDATA isn't the most helpful name.  Maybe MOUNTOPTS could be
in there?

> +
> +/**
> + * Support one copy source server for now.
> + */
> +static struct vfsmount *
> +nfsd4_interssc_connect(struct nl4_servers *nss, struct svc_rqst *rqstp)
> +{
> +	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, *ipaddr2, *raw_data;
> +	int len, raw_len, status = -EINVAL;
> +
> +	/* Currently support for one NL4_NETADDR source server */
> +	if (nss->nl_svr->nl4_type != NL4_NETADDR) {
> +		WARN(nss->nl_svr->nl4_type != NL4_NETADDR,
> +			"nfsd4_copy src server not NL4_NETADDR\n");
> +		goto out_err;
> +	}

We already checked this at xdr decoding time, didn't we?  Well, maybe
i'ts still worth a WARN.  Better, as mentioned before, maybe the data
structures just should assume only 1 NL4_NETADDR source server.

> +
> +	naddr = &nss->nl_svr->u.nl4_addr;
> +
> +	tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->na_uaddr,
> +					naddr->na_uaddr_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;
> +	}

What about the tcp/ipv4 case?  Oh, I see, it's handled by the
initialization above.  That's a little confusing.

> +
> +	if (naddr->na_netid_len != match_netid_len ||
> +	    strncmp(naddr->na_netid, match_netid, naddr->na_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'*/
> +	ipaddr2 = kzalloc(len + 5, GFP_KERNEL);
> +	if (!ipaddr2)
> +		goto out_free_ipaddr;
> +
> +	rpc_ntop((struct sockaddr *)&rqstp->rq_daddr, ipaddr2, len + 5);
> +
> +	raw_len = strlen(NFSD42_INTERSSC_RAWDATA) + strlen(ipaddr) +
> +			strlen(ipaddr2);
> +	raw_data = kzalloc(raw_len, GFP_KERNEL);
> +	if (!raw_data)
> +		goto out_free_ipaddr2;
> +
> +	snprintf(raw_data, raw_len, NFSD42_INTERSSC_RAWDATA, ipaddr,
> +		 ipaddr2);

Could "raw_data" be named more helpfully?

> +
> +	status = -ENODEV;
> +	type = get_fs_type("nfs");
> +	if (!type)
> +		goto out_free_rawdata;
> +
> +	/* Set the server:<export> for the vfs_kerne_mount call */
> +	memset(ipaddr2, 0, len + 5);
> +	snprintf(ipaddr2, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
> +
> +	dprintk("%s  Raw mount data:  %s server:export %s\n", __func__,
> +		raw_data, ipaddr2);
> +
> +	/* Use an 'internal' mount: MS_KERNMOUNT -> MNT_INTERNAL */
> +	ss_mnt = vfs_kern_mount(type, MS_KERNMOUNT, ipaddr2, raw_data);

I wonder if creating a mount (even a kernel internal one) has any
unexpected side effects.  Is it a problem that it could share caches
with any already-existing mounts of that export?

> +	if (IS_ERR(ss_mnt)) {
> +		status = PTR_ERR(ss_mnt);
> +		goto out_free_rawdata;
> +	}
> +
> +	kfree(raw_data);
> +	kfree(ipaddr2);
> +	kfree(ipaddr);
> +
> +	return ss_mnt;
> +
> +out_free_rawdata:
> +	kfree(raw_data);
> +out_free_ipaddr2:
> +	kfree(ipaddr2);
> +out_free_ipaddr:
> +	kfree(ipaddr);
> +out_err:
> +	dprintk("--> %s ERROR %d\n", __func__, status);
> +	return ERR_PTR(status);
> +}
> +
> +static void
> +nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
> +{
> +	mntput(ss_mnt);
> +	nfs_sb_deactive(ss_mnt->mnt_sb);

OK, I don't claim to understand that.

Are you sure it's still safe to dereference ss_mnt after calling
mntput() on it?

> +}
> +
> +/**
> + * 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 struct vfsmount *
> +nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> +			struct nfsd4_compound_state *cstate,
> +			struct nfsd4_copy *copy, struct file **src,
> +			struct file **dst)
> +{
> +	struct svc_fh *s_fh = NULL;
> +	stateid_t *s_stid = &copy->cp_src_stateid;
> +	struct nfs_fh fh;
> +	nfs4_stateid stateid;
> +	struct file *filp;
> +	struct vfsmount *ss_mnt;
> +	__be32 status;
> +
> +	/* 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, dst, NULL);
> +	if (status) {
> +		ss_mnt = ERR_PTR(be32_to_cpu(status));
> +		goto out;
> +	}
> +
> +	/* Inter copy source fh is always stale */

Not necessarily.

> +	CLEAR_CSTATE_FLAG(cstate, IS_STALE_FH);
> +
> +	ss_mnt = nfsd4_interssc_connect(&copy->cp_src, rqstp);
> +	if (IS_ERR(ss_mnt))
> +		goto out;
> +
> +	s_fh = &cstate->save_fh;
> +
> +	fh.size = s_fh->fh_handle.fh_size;
> +	memcpy(fh.data, &s_fh->fh_handle.fh_base, fh.size);
> +	stateid.seqid = s_stid->si_generation;
> +	memcpy(stateid.other, (void *)&s_stid->si_opaque,
> +		sizeof(stateid_opaque_t));
> +
> +	filp =  nfs42_ssc_open(ss_mnt, &fh, &stateid);

So that was defined in the client-side patches?

> +	if (IS_ERR(filp)) {
> +		nfsd4_interssc_disconnect(ss_mnt);
> +		return ERR_CAST(filp);
> +	}
> +	*src = filp;
> +out:
> +	return ss_mnt;
> +}
> +
> +static void
> +nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *src,
> +			struct file *dst)
> +{
> +	nfs42_ssc_close(src);
> +	fput(src);
> +	fput(dst);
> +
> +	nfsd4_interssc_disconnect(ss_mnt);
> +
> +}
> +
> +#else /* CONFIG_NFSD_V4_2_INTER_SSC */
> +
> +static struct vfsmount *
> +nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> +			struct nfsd4_compound_state *cstate,
> +			struct nfsd4_copy *copy, struct file **src,
> +			struct file **dst)
> +{
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static void
> +nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *src,
> +			struct file *dst)
> +{
> +}
> +
> +#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
> +
>  static __be32
> -nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> -		struct nfsd4_copy *copy)
> +nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
> +		      struct nfsd4_compound_state *cstate,
> +		      struct nfsd4_copy *copy, struct file **src,
> +		      struct file **dst)
>  {
> -	struct file *src, *dst;
>  	__be32 status;
> -	ssize_t bytes;
>  
> -	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid, &src,
> -				   &copy->cp_dst_stateid, &dst);
> +	status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid, src,
> +				   &copy->cp_dst_stateid, dst);
>  	if (status)
>  		goto out;
>  
> @@ -1089,7 +1300,37 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
>  	if (HAS_CSTATE_FLAG(cstate, IS_STALE_FH)) {
>  		CLEAR_CSTATE_FLAG(cstate, IS_STALE_FH);
>  		cstate->status = nfserr_copy_stalefh;
> -		goto out_put;
> +	}
> +out:
> +	return status;
> +}
> +
> +static void
> +nfsd4_cleanup_intra_ssc(struct file *src, struct file *dst)
> +{
> +	fput(src);
> +	fput(dst);
> +}
> +
> +static __be32
> +nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> +	struct nfsd4_copy *copy)
> +{
> +	struct vfsmount *ss_mnt = NULL;
> +	struct file *src, *dst;
> +	__be32 status;
> +	ssize_t bytes;
> +
> +	if (copy->cp_src.nl_nsvr > 0) { /* Inter server SSC */
> +		ss_mnt = nfsd4_setup_inter_ssc(rqstp, cstate, copy, &src, &dst);
> +		if (IS_ERR(ss_mnt)) {
> +			status = nfserrno(PTR_ERR(ss_mnt));
> +			goto out;

Touched on before, I think: this could use some checking to make sure
that the error returned is useful to the client.  (I'm not sure exactly
what the most likely failures are, though.)

--b.

> +		}
> +	} else {
> +		status = nfsd4_setup_intra_ssc(rqstp, cstate, copy, &src, &dst);
> +		if (status)
> +			goto out;
>  	}
>  
>  	bytes = nfsd_copy_file_range(src, copy->cp_src_pos,
> @@ -1106,9 +1347,10 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
>  		status = nfs_ok;
>  	}
>  
> -out_put:
> -	fput(src);
> -	fput(dst);
> +	if (copy->cp_src.nl_nsvr > 0)   /* Inter server SSC */
> +		nfsd4_cleanup_inter_ssc(ss_mnt, src, dst);
> +	else
> +		nfsd4_cleanup_intra_ssc(src, dst);
>  out:
>  	return status;
>  }
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 5aa36ac..843443b 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -16,6 +16,7 @@
>  #include <linux/uidgid.h>
>  #include <uapi/linux/nfs4.h>
>  #include <linux/sunrpc/msg_prot.h>
> +#include <linux/nfs.h>
>  
>  enum nfs4_acl_whotype {
>  	NFS4_ACL_WHO_NAMED = 0,
> -- 
> 1.8.3.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2017-09-08 20:28 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-11 16:43 [PATCH v3 00/42] NFS/NFSD support for async and inter COPY Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 01/42] fs: Don't copy beyond the end of the file Olga Kornievskaia
2017-07-11 18:39   ` Anna Schumaker
2017-07-11 16:43 ` [RFC v3 02/42] VFS permit cross device vfs_copy_file_range Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 03/42] NFS CB_OFFLOAD xdr Olga Kornievskaia
2017-07-11 20:27   ` Anna Schumaker
2017-07-11 16:43 ` [RFC v3 04/42] NFS OFFLOAD_STATUS xdr Olga Kornievskaia
2017-07-11 21:01   ` Anna Schumaker
2017-07-12 17:23     ` Olga Kornievskaia
2017-07-12 17:25       ` Anna Schumaker
2017-07-11 16:43 ` [RFC v3 05/42] NFS OFFLOAD_STATUS op Olga Kornievskaia
2017-07-12 12:41   ` Anna Schumaker
2017-07-11 16:43 ` [RFC v3 06/42] NFS OFFLOAD_CANCEL xdr Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 07/42] NFS COPY xdr handle async reply Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 08/42] NFS add support for asynchronous COPY Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 09/42] NFS handle COPY reply CB_OFFLOAD call race Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 10/42] NFS export nfs4_async_handle_error Olga Kornievskaia
2017-07-12 13:56   ` Anna Schumaker
2017-07-12 17:18     ` Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 11/42] NFS test for intra vs inter COPY Olga Kornievskaia
2017-07-12 14:06   ` Anna Schumaker
2017-07-12 17:21     ` Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 12/42] NFS send OFFLOAD_CANCEL when COPY killed Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 13/42] NFS handle COPY ERR_OFFLOAD_NO_REQS Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 14/42] NFS if we got partial copy ignore errors Olga Kornievskaia
2017-07-12 14:52   ` Anna Schumaker
2017-07-12 17:19     ` Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 15/42] NFS recover from destination server reboot for copies Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 16/42] NFS NFSD defining nl4_servers structure needed by both Olga Kornievskaia
2017-09-06 20:35   ` J. Bruce Fields
2017-09-08 20:51     ` Olga Kornievskaia
2017-09-11 16:22       ` J. Bruce Fields
2017-07-11 16:43 ` [RFC v3 17/42] NFS add COPY_NOTIFY operation Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 18/42] NFS add ca_source_server<> to COPY Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 19/42] NFS also send OFFLOAD_CANCEL to source server Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 20/42] NFS inter ssc open Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 21/42] NFS skip recovery of copy open on dest server Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 22/42] NFS for "inter" copy treat ESTALE as ENOTSUPP Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 23/42] NFS add a simple sync nfs4_proc_commit after async COPY Olga Kornievskaia
2017-07-12 17:13   ` Anna Schumaker
2017-07-12 17:18     ` Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 24/42] NFSD add ca_source_server<> to COPY Olga Kornievskaia
2017-07-11 16:43 ` [RFC v3 25/42] NFSD add COPY_NOTIFY operation Olga Kornievskaia
2017-09-06 20:45   ` J. Bruce Fields
2017-09-13 14:39     ` Olga Kornievskaia
2017-09-06 21:34   ` J. Bruce Fields
2017-09-13 14:38     ` Olga Kornievskaia
2017-09-06 21:37   ` J. Bruce Fields
2017-09-13 14:38     ` Olga Kornievskaia
2017-09-13 14:42       ` J. Bruce Fields
2017-07-11 16:44 ` [RFC v3 26/42] NFSD generalize nfsd4_compound_state flag names Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 27/42] NFSD: allow inter server COPY to have a STALE source server fh Olga Kornievskaia
2017-09-08 19:38   ` J. Bruce Fields
2017-09-08 19:52     ` Olga Kornievskaia
2017-09-08 19:57       ` J. Bruce Fields
2017-09-08 20:09         ` Olga Kornievskaia
2017-09-14 18:44     ` Olga Kornievskaia
2017-09-15  1:47       ` J. Bruce Fields
2017-09-15 19:46         ` Olga Kornievskaia
2017-09-15 20:02           ` J. Bruce Fields
2017-09-15 20:06             ` J. Bruce Fields
2017-09-15 20:11               ` Olga Kornievskaia
2017-09-16 14:44               ` J. Bruce Fields
2017-07-11 16:44 ` [RFC v3 28/42] NFSD add nfs4 inter ssc to nfsd4_copy Olga Kornievskaia
2017-09-08 20:28   ` J. Bruce Fields [this message]
2017-07-11 16:44 ` [RFC v3 29/42] NFSD return nfs4_stid in nfs4_preprocess_stateid_op Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 30/42] NFSD Unique stateid_t for inter server to server COPY authentication Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 31/42] NFSD CB_OFFLOAD xdr Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 32/42] NFSD OFFLOAD_STATUS xdr Olga Kornievskaia
2017-07-12 19:39   ` Anna Schumaker
2017-07-11 16:44 ` [RFC v3 33/42] NFSD OFFLOAD_CANCEL xdr Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 34/42] NFSD xdr callback stateid in async COPY reply Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 35/42] NFSD first draft of async copy Olga Kornievskaia
2017-07-12 20:29   ` Anna Schumaker
2017-07-11 16:44 ` [RFC v3 36/42] NFSD handle OFFLOAD_CANCEL op Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 37/42] NFSD stop queued async copies on client shutdown Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 38/42] NFSD create new stateid for async copy Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 39/42] NFSD define EBADF in nfserrno Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 40/42] NFSD support OFFLOAD_STATUS Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 41/42] NFSD remove copy stateid when vfs_copy_file_range completes Olga Kornievskaia
2017-07-11 16:44 ` [RFC v3 42/42] NFSD delay the umount after COPY Olga Kornievskaia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170908202813.GC18220@fieldses.org \
    --to=bfields@fieldses.org \
    --cc=Trond.Myklebust@primarydata.com \
    --cc=anna.schumaker@netapp.com \
    --cc=bfields@redhat.com \
    --cc=kolga@netapp.com \
    --cc=linux-nfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).