Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Sep 2019 04:09:43 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r351968 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver
Message-ID:  <201909070409.x8749h4O074603@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Sat Sep  7 04:09:43 2019
New Revision: 351968
URL: https://svnweb.freebsd.org/changeset/base/351968

Log:
  Add support for the List Extended Attributes RPC.
  
  This patch also saves the maxrequest and maxreply for the session in
  nd_maxreq and nd_maxresp so they can be used to limit the size of
  extended attribute requests/replies.
  The code for doing this on the client side still needs to be done.

Modified:
  projects/nfsv42/sys/fs/nfs/nfs.h
  projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c
  projects/nfsv42/sys/fs/nfs/nfs_var.h
  projects/nfsv42/sys/fs/nfs/nfsport.h
  projects/nfsv42/sys/fs/nfs/nfsproto.h
  projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c
  projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c
  projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c
  projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c
  projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c
  projects/nfsv42/sys/fs/nfsserver/nfs_nfsdstate.c

Modified: projects/nfsv42/sys/fs/nfs/nfs.h
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfs.h	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfs/nfs.h	Sat Sep  7 04:09:43 2019	(r351968)
@@ -667,6 +667,8 @@ struct nfsrv_descript {
 	uint32_t		*nd_sequence;	/* Sequence Op. ptr */
 	nfsv4stateid_t		nd_curstateid;	/* Current StateID */
 	nfsv4stateid_t		nd_savedcurstateid; /* Saved Current StateID */
+	uint32_t		nd_maxreq;	/* Max. request (session). */
+	uint32_t		nd_maxresp;	/* Max. reply (session). */
 };
 
 #define	nd_princlen	nd_gssnamelen

Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -182,7 +182,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Clone */
 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getxattr */
 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Setxattr */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Listxattrs */
+	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Listxattrs */
 	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Removexattr */
 };
 #endif	/* !APPLEKEXT */
@@ -211,7 +211,7 @@ static struct nfsrv_lughash	*nfsgroupnamehash;
 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
-    1, 0, 0 };
+    1, 0, 0, 1 };
 
 /* local functions */
 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
@@ -293,6 +293,7 @@ static struct {
 	{ NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
 	{ NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
 	{ NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
+	{ NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
 };
 
 /*
@@ -301,7 +302,7 @@ static struct {
 static int nfs_bigrequest[NFSV42_NPROCS] = {
 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0
+	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
 };
 
 /*
@@ -4632,6 +4633,8 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_d
 
 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
 	    sessionid);
+	nd->nd_maxreq = sep->sess_maxreq;
+	nd->nd_maxresp = sep->sess_maxresp;
 
 	/* Build the Sequence arguments. */
 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);

Modified: projects/nfsv42/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfs_var.h	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfs/nfs_var.h	Sat Sep  7 04:09:43 2019	(r351968)
@@ -290,6 +290,8 @@ int nfsrvd_setxattr(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
 int nfsrvd_rmxattr(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
+int nfsrvd_listxattr(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
 int nfsrvd_notsupp(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
 
@@ -555,6 +557,8 @@ int nfsrpc_getextattr(vnode_t, const char *, struct ui
     struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
 int nfsrpc_setextattr(vnode_t, const char *, struct uio *, struct nfsvattr *,
     int *, struct ucred *, NFSPROC_T *);
+int nfsrpc_listextattr(vnode_t, uint64_t *, struct uio *, size_t *, bool *,
+    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
 int nfsrpc_rmextattr(vnode_t, const char *, struct nfsvattr *, int *,
     struct ucred *, NFSPROC_T *);
 
@@ -740,12 +744,14 @@ void nfsrv_killrpcs(struct nfsmount *);
 int nfsrv_setacl(struct vnode *, NFSACL_T *, struct ucred *, NFSPROC_T *);
 int nfsvno_seek(struct nfsrv_descript *, struct vnode *, u_long, off_t *, int,
     bool *, struct ucred *, NFSPROC_T *);
-int nfsvno_getxattr(struct vnode *, char *, struct ucred *, struct thread *,
-    struct mbuf **, struct mbuf **, int *);
+int nfsvno_getxattr(struct vnode *, char *, uint32_t, struct ucred *,
+    struct thread *, struct mbuf **, struct mbuf **, int *);
 int nfsvno_setxattr(struct vnode *, char *, int, struct mbuf *, char *,
     struct ucred *, struct thread *);
 int nfsvno_rmxattr(struct nfsrv_descript *, struct vnode *, char *,
     struct ucred *, struct thread *);
+int nfsvno_listxattr(struct vnode *, uint64_t, struct ucred *, struct thread *,
+    u_char **, uint32_t *, bool *);
 
 /* nfs_commonkrpc.c */
 int newnfs_nmcancelreqs(struct nfsmount *);

Modified: projects/nfsv42/sys/fs/nfs/nfsport.h
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfsport.h	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfs/nfsport.h	Sat Sep  7 04:09:43 2019	(r351968)
@@ -410,11 +410,12 @@
 #define	NFSPROC_GETEXTATTR	61
 #define	NFSPROC_SETEXTATTR	62
 #define	NFSPROC_RMEXTATTR	63
+#define	NFSPROC_LISTEXTATTR	64
 
 /*
  * Must be defined as one higher than the last NFSv4.2 Proc# above.
  */
-#define	NFSV42_NPROCS		64
+#define	NFSV42_NPROCS		65
 
 #endif	/* NFS_V3NPROCS */
 
@@ -443,7 +444,7 @@ struct nfsstatsv1 {
 	uint64_t	readlink_bios;
 	uint64_t	biocache_readdirs;
 	uint64_t	readdir_bios;
-	uint64_t	rpccnt[NFSV42_NPROCS + 5];
+	uint64_t	rpccnt[NFSV42_NPROCS + 4];
 	uint64_t	rpcretries;
 	uint64_t	srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS];
 	uint64_t	srvrpc_errs;

Modified: projects/nfsv42/sys/fs/nfs/nfsproto.h
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfsproto.h	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfs/nfsproto.h	Sat Sep  7 04:09:43 2019	(r351968)
@@ -392,11 +392,12 @@
 #define	NFSPROC_GETEXTATTR	61
 #define	NFSPROC_SETEXTATTR	62
 #define	NFSPROC_RMEXTATTR	63
+#define	NFSPROC_LISTEXTATTR	64
 
 /*
  * Must be defined as one higher than the last NFSv4.2 Proc# above.
  */
-#define	NFSV42_NPROCS		64
+#define	NFSV42_NPROCS		65
 
 #endif	/* NFS_V3NPROCS */
 

Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
 
 #include <fs/nfs/nfsport.h>
 #include <fs/nfsclient/nfs.h>
+#include <sys/extattr.h>
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 
@@ -8381,6 +8382,83 @@ nfsrpc_rmextattr(vnode_t vp, const char *name, struct 
 		/* Just skip over the reply and Getattr op status. */
 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 2 *
 		    NFSX_UNSIGNED);
+		error = nfsm_loadattr(nd, nap);
+		if (error == 0)
+			*attrflagp = 1;
+	}
+	if (error == 0)
+		error = nd->nd_repstat;
+nfsmout:
+	mbuf_freem(nd->nd_mrep);
+	return (error);
+}
+
+/*
+ * The listextattr RPC.
+ */
+APPLESTATIC int
+nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop,
+    size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp,
+    struct ucred *cred, NFSPROC_T *p)
+{
+	uint32_t *tl;
+	int cnt, error, i, len;
+	struct nfsrv_descript nfsd;
+	struct nfsrv_descript *nd = &nfsd;
+	nfsattrbit_t attrbits;
+	u_char c;
+
+	*attrflagp = 0;
+	NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp);
+	NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
+	txdr_hyper(*cookiep, tl); tl += 2;
+	*tl++ = txdr_unsigned(*lenp);
+	*tl = txdr_unsigned(NFSV4OP_GETATTR);
+	NFSGETATTR_ATTRBIT(&attrbits);
+	nfsrv_putattrbit(nd, &attrbits);
+	error = nfscl_request(nd, vp, p, cred, NULL);
+	if (error != 0)
+		return (error);
+	*eofp = true;
+	*lenp = 0;
+	if (nd->nd_repstat == 0) {
+		NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
+		*cookiep = fxdr_hyper(tl); tl += 2;
+		cnt = fxdr_unsigned(int, *tl);
+		if (cnt <= 0) {
+			error = EBADRPC;
+			goto nfsmout;
+		}
+		for (i = 0; i < cnt; i++) {
+			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+			len = fxdr_unsigned(int, *tl);
+			if (len <= 0 || len > EXTATTR_MAXNAMELEN) {
+				error = EBADRPC;
+				goto nfsmout;
+			}
+			if (uiop == NULL)
+				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
+			else if (uiop->uio_resid >= len + 1) {
+				c = len;
+				error = uiomove(&c, sizeof(c), uiop);
+				if (error == 0)
+					error = nfsm_mbufuio(nd, uiop, len);
+			} else {
+				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
+				*eofp = false;
+			}
+			if (error != 0)
+				goto nfsmout;
+			*lenp += (len + 1);
+		}
+		/* Get the eof and skip over the Getattr op status. */
+		NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+		/*
+		 * *eofp is set false above, because it wasn't able to copy
+		 * all of the reply.
+		 */
+		if (*eofp && *tl == 0)
+			*eofp = false;
 		error = nfsm_loadattr(nd, nap);
 		if (error == 0)
 			*attrflagp = 1;

Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -150,6 +150,7 @@ static vop_copy_file_range_t nfs_copy_file_range;
 static vop_ioctl_t nfs_ioctl;
 static vop_getextattr_t nfs_getextattr;
 static vop_setextattr_t nfs_setextattr;
+static vop_listextattr_t nfs_listextattr;
 static vop_deleteextattr_t nfs_deleteextattr;
 
 /*
@@ -194,6 +195,7 @@ static struct vop_vector newnfs_vnodeops_nosig = {
 	.vop_ioctl =		nfs_ioctl,
 	.vop_getextattr =	nfs_getextattr,
 	.vop_setextattr =	nfs_setextattr,
+	.vop_listextattr =	nfs_listextattr,
 	.vop_deleteextattr =	nfs_deleteextattr,
 };
 
@@ -3847,6 +3849,80 @@ nfs_setextattr(struct vop_setextattr_args *ap)
 		if (error == 0 && ret != 0)
 			error = ret;
 	}
+
+	switch (error) {
+	case NFSERR_NOTSUPP:
+	case NFSERR_OPILLEGAL:
+		mtx_lock(&nmp->nm_mtx);
+		nmp->nm_privflag |= NFSMNTP_NOXATTR;
+		mtx_unlock(&nmp->nm_mtx);
+		error = EOPNOTSUPP;
+		break;
+	case NFSERR_NOXATTR:
+	case NFSERR_XATTR2BIG:
+		error = ENOATTR;
+		break;
+	default:
+		error = nfscl_maperr(td, error, 0, 0);
+		break;
+	}
+	return (error);
+}
+
+/*
+ * nfs listextattr call
+ */
+static int
+nfs_listextattr(struct vop_listextattr_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	struct nfsmount *nmp;
+	struct ucred *cred;
+	struct thread *td = ap->a_td;
+	struct nfsvattr nfsva;
+	size_t len, len2;
+	uint64_t cookie;
+	int attrflag, error, ret;
+	bool eof;
+
+	nmp = VFSTONFS(vp->v_mount);
+	mtx_lock(&nmp->nm_mtx);
+	if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION ||
+	    (nmp->nm_privflag & NFSMNTP_NOXATTR) != 0 ||
+	    ap->a_attrnamespace != EXTATTR_NAMESPACE_USER) {
+		mtx_unlock(&nmp->nm_mtx);
+		return (EOPNOTSUPP);
+	}
+	mtx_unlock(&nmp->nm_mtx);
+
+	cred = ap->a_cred;
+	if (cred == NULL)
+		cred = td->td_ucred;
+
+	/* Loop around doing List Extended Attribute RPCs. */
+	eof = false;
+	cookie = 0;
+	len2 = 0;
+	error = 0;
+	while (!eof && error == 0) {
+		len = nmp->nm_rsize;
+		attrflag = 0;
+		error = nfsrpc_listextattr(vp, &cookie, ap->a_uio, &len, &eof,
+		    &nfsva, &attrflag, cred, td);
+		if (attrflag != 0) {
+			ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
+			    1);
+			if (error == 0 && ret != 0)
+				error = ret;
+		}
+		if (error == 0) {
+			len2 += len;
+			if (len2 > SSIZE_MAX)
+				error = ENOATTR;
+		}
+	}
+	if (error == 0 && ap->a_size != NULL)
+		*ap->a_size = len2;
 
 	switch (error) {
 	case NFSERR_NOTSUPP:

Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdport.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -5914,8 +5914,9 @@ nfsvno_seek(struct nfsrv_descript *nd, struct vnode *v
  * Get Extended Atribute vnode op into an mbuf list.
  */
 int
-nfsvno_getxattr(struct vnode *vp, char *name, struct ucred *cred,
-    struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
+nfsvno_getxattr(struct vnode *vp, char *name, uint32_t maxresp,
+    struct ucred *cred, struct thread *p, struct mbuf **mpp,
+    struct mbuf **mpendp, int *lenp)
 {
 	struct iovec *iv;
 	struct uio io, *uiop = &io;
@@ -5928,7 +5929,7 @@ nfsvno_getxattr(struct vnode *vp, char *name, struct u
 	    &siz, cred, p);
 	if (error != 0)
 		return (NFSERR_NOXATTR);
-	if (siz > 1000000)
+	if (siz > maxresp - NFS_MAXXDR)
 		return (NFSERR_XATTR2BIG);
 	len = siz;
 	tlen = NFSM_RNDUP(len);
@@ -6039,6 +6040,72 @@ nfsvno_rmxattr(struct nfsrv_descript *nd, struct vnode
 #ifdef MAC
 out:
 #endif
+	NFSEXITCODE(error);
+	return (error);
+}
+
+/*
+ * List Extended Atribute vnode op into an mbuf list.
+ */
+int
+nfsvno_listxattr(struct vnode *vp, uint64_t cookie, struct ucred *cred,
+    struct thread *p, u_char **bufp, uint32_t *lenp, bool *eofp)
+{
+	struct iovec iv;
+	struct uio io;
+	int error;
+	size_t siz;
+
+	*bufp = NULL;
+	/* First, find out the size of the extended attribute. */
+	error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, NULL, &siz, cred,
+	    p);
+	if (error != 0)
+		return (NFSERR_NOXATTR);
+	if (siz <= cookie) {
+		*lenp = 0;
+		*eofp = true;
+		goto out;
+	}
+	if (siz > cookie + *lenp) {
+		siz = cookie + *lenp;
+		*eofp = false;
+	} else
+		*eofp = true;
+	/* Just choose a sanity limit of 10Mbytes for malloc(M_TEMP). */
+	if (siz > 10 * 1024 * 1024) {
+		error = NFSERR_XATTR2BIG;
+		goto out;
+	}
+	*bufp = malloc(siz, M_TEMP, M_WAITOK);
+	iv.iov_base = *bufp;
+	iv.iov_len = siz;
+	io.uio_iovcnt = 1;
+	io.uio_iov = &iv;
+	io.uio_offset = 0;
+	io.uio_resid = siz;
+	io.uio_rw = UIO_READ;
+	io.uio_segflg = UIO_SYSSPACE;
+	io.uio_td = p;
+#ifdef MAC
+	error = mac_vnode_check_listextattr(cred, vp, EXTATTR_NAMESPACE_USER);
+	if (error != 0)
+		goto out;
+#endif
+
+	error = VOP_LISTEXTATTR(vp, EXTATTR_NAMESPACE_USER, &io, NULL, cred,
+	    p);
+	if (error != 0)
+		goto out;
+	if (io.uio_resid > 0)
+		siz -= io.uio_resid;
+	*lenp = siz;
+
+out:
+	if (error != 0) {
+		free(*bufp, M_TEMP);
+		*bufp = NULL;
+	}
 	NFSEXITCODE(error);
 	return (error);
 }

Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -5482,8 +5482,8 @@ nfsrvd_getxattr(struct nfsrv_descript *nd, __unused in
 	name = malloc(len + 1, M_TEMP, M_WAITOK);
 	nd->nd_repstat = nfsrv_mtostr(nd, name, len);
 	if (nd->nd_repstat == 0)
-		nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_cred, p,
-		    &mp, &mpend, &len);
+		nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp,
+		    nd->nd_cred, p, &mp, &mpend, &len);
 	if (nd->nd_repstat == ENOATTR)
 		nd->nd_repstat = NFSERR_NOXATTR;
 	else if (nd->nd_repstat == EOPNOTSUPP)
@@ -5513,11 +5513,11 @@ nfsrvd_setxattr(struct nfsrv_descript *nd, __unused in
     vnode_t vp, __unused struct nfsexstuff *exp)
 {
 	uint32_t *tl;
-	mbuf_t mp = NULL, mpend = NULL;
 	struct nfsvattr ova, nva;
 	nfsattrbit_t attrbits;
-	int error, len, opt, retlen;
+	int error, len, opt;
 	char *name;
+	size_t siz;
 	struct thread *p = curthread;
 
 	error = 0;
@@ -5549,20 +5549,16 @@ nfsrvd_setxattr(struct nfsrv_descript *nd, __unused in
 	}
 	switch (opt) {
 	case NFSV4SXATTR_CREATE:
-		error = nfsvno_getxattr(vp, name, nd->nd_cred, p, &mp, &mpend,
-		    &retlen);
-		if (error == 0)
-			m_freem(mp);
+		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
+		    &siz, nd->nd_cred, p);
 		if (error != ENOATTR)
 			nd->nd_repstat = NFSERR_EXIST;
 		error = 0;
 		break;
 	case NFSV4SXATTR_REPLACE:
-		error = nfsvno_getxattr(vp, name, nd->nd_cred, p, &mp, &mpend,
-		    &retlen);
-		if (error == 0)
-			m_freem(mp);
-		else
+		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
+		    &siz, nd->nd_cred, p);
+		if (error != 0)
 			nd->nd_repstat = NFSERR_NOXATTR;
 		break;
 	case NFSV4SXATTR_EITHER:
@@ -5665,6 +5661,118 @@ nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int
 
 nfsmout:
 	free(name, M_TEMP);
+	if (nd->nd_repstat == 0)
+		nd->nd_repstat = error;
+	vput(vp);
+	NFSEXITCODE2(0, nd);
+	return (0);
+}
+
+/*
+ * nfs list extended attribute service
+ */
+APPLESTATIC int
+nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
+    vnode_t vp, __unused struct nfsexstuff *exp)
+{
+	uint32_t cnt, *tl, len, len2, i, pos, retlen;
+	int error;
+	uint64_t cookie, cookie2;
+	u_char *buf;
+	bool eof;
+	struct thread *p = curthread;
+
+	error = 0;
+	buf = NULL;
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
+	/*
+	 * The cookie doesn't need to be in net byte order, but FreeBSD
+	 * does so to make it more readable in packet traces.
+	 */
+	cookie = fxdr_hyper(tl); tl += 2;
+	len = fxdr_unsigned(uint32_t, *tl);
+	if (len == 0 || cookie >= IOSIZE_MAX) {
+		nd->nd_repstat = NFSERR_BADXDR;
+		goto nfsmout;
+	}
+	if (len > nd->nd_maxresp - NFS_MAXXDR)
+		len = nd->nd_maxresp - NFS_MAXXDR;
+	len2 = len;
+	nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
+	    &len, &eof);
+	if (nd->nd_repstat == EOPNOTSUPP)
+		nd->nd_repstat = NFSERR_NOTSUPP;
+	if (nd->nd_repstat == 0) {
+		cookie2 = cookie + len;
+		if (cookie2 < cookie)
+			nd->nd_repstat = NFSERR_BADXDR;
+	}
+	if (nd->nd_repstat == 0) {
+		/* Now copy the entries out. */
+		retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
+		if (len == 0 && retlen <= len2) {
+			/* The cookie was at eof. */
+			NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
+			    NFSX_UNSIGNED);
+			txdr_hyper(cookie2, tl); tl += 2;
+			*tl++ = txdr_unsigned(0);
+			*tl = newnfs_true;
+			goto nfsmout;
+		}
+
+		/* Sanity check the cookie. */
+		for (pos = 0; pos < len; pos += (i + 1)) {
+			if (pos == cookie)
+				break;
+			i = buf[pos];
+		}
+		if (pos != cookie) {
+			nd->nd_repstat = NFSERR_INVAL;
+			goto nfsmout;
+		}
+
+		/* Loop around copying the entrie(s) out. */
+		cnt = 0;
+		len -= cookie;
+		i = buf[pos];
+		while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
+		    NFSX_UNSIGNED) {
+			if (cnt == 0) {
+				NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
+				    NFSX_UNSIGNED);
+				txdr_hyper(cookie2, tl); tl += 2;
+			}
+			retlen += nfsm_strtom(nd, &buf[pos + 1], i);
+			len -= (i + 1);
+			pos += (i + 1);
+			i = buf[pos];
+			cnt++;
+		}
+		/*
+		 * eof is set true/false by nfsvno_listxattr(), but if we
+		 * can't copy all entries returned by nfsvno_listxattr(),
+		 * we are not at eof.
+		 */
+		if (len > 0)
+			eof = false;
+		if (cnt > 0) {
+			/* *tl is set above. */
+			*tl = txdr_unsigned(cnt);
+			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+			if (eof)
+				*tl = newnfs_true;
+			else
+				*tl = newnfs_false;
+		} else
+			nd->nd_repstat = NFSERR_TOOSMALL;
+	}
+
+nfsmout:
+	free(buf, M_TEMP);
 	if (nd->nd_repstat == 0)
 		nd->nd_repstat = error;
 	vput(vp);

Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -211,7 +211,7 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript 
 	nfsrvd_notsupp,
 	nfsrvd_getxattr,
 	nfsrvd_setxattr,
-	nfsrvd_notsupp,
+	nfsrvd_listxattr,
 	nfsrvd_rmxattr,
 };
 

Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdstate.c	Sat Sep  7 03:51:26 2019	(r351967)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdstate.c	Sat Sep  7 04:09:43 2019	(r351968)
@@ -6209,6 +6209,10 @@ nfsrv_checksequence(struct nfsrv_descript *nd, uint32_
 	nd->nd_clientid.qval = sep->sess_clp->lc_clientid.qval;
 	nd->nd_flag |= ND_IMPLIEDCLID;
 
+	/* Save maximum request and reply sizes. */
+	nd->nd_maxreq = sep->sess_maxreq;
+	nd->nd_maxresp = sep->sess_maxresp;
+
 	/*
 	 * If this session handles the backchannel, save the nd_xprt for this
 	 * RPC, since this is the one being used.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909070409.x8749h4O074603>