Commit c065c429 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd updates from Chuck Lever:
 "Highlights:

   - Update NFSv2 and NFSv3 XDR encoding functions

   - Add batch Receive posting to the server's RPC/RDMA transport (take 2)

   - Reduce page allocator traffic in svcrdma"

* tag 'nfsd-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (70 commits)
  NFSD: Use DEFINE_SPINLOCK() for spinlock
  sunrpc: Remove unused function ip_map_lookup
  NFSv4.2: fix copy stateid copying for the async copy
  UAPI: nfsfh.h: Replace one-element array with flexible-array member
  svcrdma: Clean up dto_q critical section in svc_rdma_recvfrom()
  svcrdma: Remove svc_rdma_recv_ctxt::rc_pages and ::rc_arg
  svcrdma: Remove sc_read_complete_q
  svcrdma: Single-stage RDMA Read
  SUNRPC: Move svc_xprt_received() call sites
  SUNRPC: Export svc_xprt_received()
  svcrdma: Retain the page backing rq_res.head[0].iov_base
  svcrdma: Remove unused sc_pages field
  svcrdma: Normalize Send page handling
  svcrdma: Add a "deferred close" helper
  svcrdma: Maintain a Receive water mark
  svcrdma: Use svc_rdma_refresh_recvs() in wc_receive
  svcrdma: Add a batch Receive posting mechanism
  svcrdma: Remove stale comment for svc_rdma_wc_receive()
  svcrdma: Provide an explanatory comment in CMA event handler
  svcrdma: RPCDBG_FACILITY is no longer used
  ...
parents b5b3097d b73ac680
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -136,6 +136,77 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
}
EXPORT_SYMBOL_GPL(nfsacl_encode);

/**
 * nfs_stream_encode_acl - Encode an NFSv3 ACL
 *
 * @xdr: an xdr_stream positioned to receive an encoded ACL
 * @inode: inode of file whose ACL this is
 * @acl: posix_acl to encode
 * @encode_entries: whether to encode ACEs as well
 * @typeflag: ACL type: NFS_ACL_DEFAULT or zero
 *
 * Return values:
 *   %false: The ACL could not be encoded
 *   %true: @xdr is advanced to the next available position
 */
bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
			   struct posix_acl *acl, int encode_entries,
			   int typeflag)
{
	const size_t elem_size = XDR_UNIT * 3;
	u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
	struct nfsacl_encode_desc nfsacl_desc = {
		.desc = {
			.elem_size = elem_size,
			.array_len = encode_entries ? entries : 0,
			.xcode = xdr_nfsace_encode,
		},
		.acl = acl,
		.typeflag = typeflag,
		.uid = inode->i_uid,
		.gid = inode->i_gid,
	};
	struct nfsacl_simple_acl aclbuf;
	unsigned int base;
	int err;

	if (entries > NFS_ACL_MAX_ENTRIES)
		return false;
	if (xdr_stream_encode_u32(xdr, entries) < 0)
		return false;

	if (encode_entries && acl && acl->a_count == 3) {
		struct posix_acl *acl2 = &aclbuf.acl;

		/* Avoid the use of posix_acl_alloc().  nfsacl_encode() is
		 * invoked in contexts where a memory allocation failure is
		 * fatal.  Fortunately this fake ACL is small enough to
		 * construct on the stack. */
		posix_acl_init(acl2, 4);

		/* Insert entries in canonical order: other orders seem
		 to confuse Solaris VxFS. */
		acl2->a_entries[0] = acl->a_entries[0];  /* ACL_USER_OBJ */
		acl2->a_entries[1] = acl->a_entries[1];  /* ACL_GROUP_OBJ */
		acl2->a_entries[2] = acl->a_entries[1];  /* ACL_MASK */
		acl2->a_entries[2].e_tag = ACL_MASK;
		acl2->a_entries[3] = acl->a_entries[2];  /* ACL_OTHER */
		nfsacl_desc.acl = acl2;
	}

	base = xdr_stream_pos(xdr);
	if (!xdr_reserve_space(xdr, XDR_UNIT +
			       elem_size * nfsacl_desc.desc.array_len))
		return false;
	err = xdr_encode_array2(xdr->buf, base, &nfsacl_desc.desc);
	if (err)
		return false;

	return true;
}
EXPORT_SYMBOL_GPL(nfs_stream_encode_acl);


struct nfsacl_decode_desc {
	struct xdr_array2_desc desc;
	unsigned int count;
+3 −3
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ config NFSD_BLOCKLAYOUT
	help
	  This option enables support for the exporting pNFS block layouts
	  in the kernel's NFS server. The pNFS block layout enables NFS
	  clients to directly perform I/O to block devices accesible to both
	  clients to directly perform I/O to block devices accessible to both
	  the server and the clients.  See RFC 5663 for more details.

	  If unsure, say N.
@@ -113,7 +113,7 @@ config NFSD_SCSILAYOUT
	help
	  This option enables support for the exporting pNFS SCSI layouts
	  in the kernel's NFS server. The pNFS SCSI layout enables NFS
	  clients to directly perform I/O to SCSI devices accesible to both
	  clients to directly perform I/O to SCSI devices accessible to both
	  the server and the clients.  See draft-ietf-nfsv4-scsi-layout for
	  more details.

@@ -127,7 +127,7 @@ config NFSD_FLEXFILELAYOUT
	  This option enables support for the exporting pNFS Flex File
	  layouts in the kernel's NFS server. The pNFS Flex File  layout
	  enables NFS clients to directly perform I/O to NFSv3 devices
	  accesible to both the server and the clients.  See
	  accessible to both the server and the clients.  See
	  draft-ietf-nfsv4-flex-files for more details.

	  Warning, this server implements the bare minimum functionality
+3 −3
Original line number Diff line number Diff line
@@ -51,9 +51,6 @@ struct nfsd_net {
	bool grace_ended;
	time64_t boot_time;

	/* internal mount of the "nfsd" pseudofilesystem: */
	struct vfsmount *nfsd_mnt;

	struct dentry *nfsd_client_dir;

	/*
@@ -130,6 +127,9 @@ struct nfsd_net {
	wait_queue_head_t ntf_wq;
	atomic_t ntf_refcnt;

	/* Allow umount to wait for nfsd state cleanup */
	struct completion nfsd_shutdown_complete;

	/*
	 * clientid and stateid data for construction of net unique COPY
	 * stateids.
+31 −56
Original line number Diff line number Diff line
@@ -242,79 +242,61 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
/* GETACL */
static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
{
	struct xdr_stream *xdr = &rqstp->rq_res_stream;
	struct nfsd3_getaclres *resp = rqstp->rq_resp;
	struct dentry *dentry = resp->fh.fh_dentry;
	struct inode *inode;
	struct kvec *head = rqstp->rq_res.head;
	unsigned int base;
	int n;
	int w;

	*p++ = resp->status;
	if (resp->status != nfs_ok)
		return xdr_ressize_check(rqstp, p);
	if (!svcxdr_encode_stat(xdr, resp->status))
		return 0;

	/*
	 * Since this is version 2, the check for nfserr in
	 * nfsd_dispatch actually ensures the following cannot happen.
	 * However, it seems fragile to depend on that.
	 */
	if (dentry == NULL || d_really_is_negative(dentry))
		return 0;
		return 1;
	inode = d_inode(dentry);

	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
	*p++ = htonl(resp->mask);
	if (!xdr_ressize_check(rqstp, p))
	if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
		return 0;
	if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
		return 0;
	base = (char *)p - (char *)head->iov_base;

	rqstp->rq_res.page_len = w = nfsacl_size(
		(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
		(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
	while (w > 0) {
		if (!*(rqstp->rq_next_page++))
			return 0;
			return 1;
		w -= PAGE_SIZE;
	}

	n = nfsacl_encode(&rqstp->rq_res, base, inode,
			  resp->acl_access,
			  resp->mask & NFS_ACL, 0);
	if (n > 0)
		n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
				  resp->acl_default,
				  resp->mask & NFS_DFACL,
				  NFS_ACL_DEFAULT);
	return (n > 0);
}

static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
{
	struct nfsd_attrstat *resp = rqstp->rq_resp;

	*p++ = resp->status;
	if (resp->status != nfs_ok)
		goto out;
	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
				   resp->mask & NFS_ACL, 0))
		return 0;
	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
				   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
		return 0;

	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
out:
	return xdr_ressize_check(rqstp, p);
	return 1;
}

/* ACCESS */
static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
{
	struct xdr_stream *xdr = &rqstp->rq_res_stream;
	struct nfsd3_accessres *resp = rqstp->rq_resp;

	*p++ = resp->status;
	if (resp->status != nfs_ok)
		goto out;
	if (!svcxdr_encode_stat(xdr, resp->status))
		return 0;
	switch (resp->status) {
	case nfs_ok:
		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
			return 0;
		if (xdr_stream_encode_u32(xdr, resp->access) < 0)
			return 0;
		break;
	}

	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
	*p++ = htonl(resp->access);
out:
	return xdr_ressize_check(rqstp, p);
	return 1;
}

/*
@@ -329,13 +311,6 @@ static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
	posix_acl_release(resp->acl_default);
}

static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp)
{
	struct nfsd_attrstat *resp = rqstp->rq_resp;

	fh_put(&resp->fh);
}

static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
{
	struct nfsd3_accessres *resp = rqstp->rq_resp;
@@ -375,8 +350,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
	[ACLPROC2_SETACL] = {
		.pc_func = nfsacld_proc_setacl,
		.pc_decode = nfsaclsvc_decode_setaclargs,
		.pc_encode = nfsaclsvc_encode_attrstatres,
		.pc_release = nfsaclsvc_release_attrstat,
		.pc_encode = nfssvc_encode_attrstatres,
		.pc_release = nfssvc_release_attrstat,
		.pc_argsize = sizeof(struct nfsd3_setaclargs),
		.pc_ressize = sizeof(struct nfsd_attrstat),
		.pc_cachetype = RC_NOCACHE,
@@ -386,8 +361,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
	[ACLPROC2_GETATTR] = {
		.pc_func = nfsacld_proc_getattr,
		.pc_decode = nfssvc_decode_fhandleargs,
		.pc_encode = nfsaclsvc_encode_attrstatres,
		.pc_release = nfsaclsvc_release_attrstat,
		.pc_encode = nfssvc_encode_attrstatres,
		.pc_release = nfssvc_release_attrstat,
		.pc_argsize = sizeof(struct nfsd_fhandle),
		.pc_ressize = sizeof(struct nfsd_attrstat),
		.pc_cachetype = RC_NOCACHE,
+22 −17
Original line number Diff line number Diff line
@@ -168,22 +168,25 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
/* GETACL */
static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
{
	struct xdr_stream *xdr = &rqstp->rq_res_stream;
	struct nfsd3_getaclres *resp = rqstp->rq_resp;
	struct dentry *dentry = resp->fh.fh_dentry;

	*p++ = resp->status;
	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
	if (resp->status == 0 && dentry && d_really_is_positive(dentry)) {
		struct inode *inode = d_inode(dentry);
	struct kvec *head = rqstp->rq_res.head;
	struct inode *inode = d_inode(dentry);
	unsigned int base;
	int n;
	int w;

		*p++ = htonl(resp->mask);
		if (!xdr_ressize_check(rqstp, p))
	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
		return 0;
	switch (resp->status) {
	case nfs_ok:
		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
			return 0;
		base = (char *)p - (char *)head->iov_base;
		if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
			return 0;

		base = (char *)xdr->p - (char *)head->iov_base;

		rqstp->rq_res.page_len = w = nfsacl_size(
			(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
@@ -204,9 +207,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
					  NFS_ACL_DEFAULT);
		if (n <= 0)
			return 0;
	} else
		if (!xdr_ressize_check(rqstp, p))
		break;
	default:
		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
			return 0;
	}

	return 1;
}
@@ -214,11 +219,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
/* SETACL */
static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p)
{
	struct xdr_stream *xdr = &rqstp->rq_res_stream;
	struct nfsd3_attrstat *resp = rqstp->rq_resp;

	*p++ = resp->status;
	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
	return xdr_ressize_check(rqstp, p);
	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
		svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh);
}

/*
Loading