svn commit: r363748 - in head/sys/fs: nfs nfsserver

Rick Macklem rmacklem at FreeBSD.org
Fri Jul 31 23:35:50 UTC 2020


Author: rmacklem
Date: Fri Jul 31 23:35:49 2020
New Revision: 363748
URL: https://svnweb.freebsd.org/changeset/base/363748

Log:
  Add optional support for ext_pgs mbufs to the NFS server's read, readlink
  and getxattr operations.
  
  This patch optionally enables generation of read, readlink and getxattr replies
  in ext_pgs mbufs.  Since neither of ND_EXTPG or ND_TLS are currently ever set,
  there is no change in semantics at this time.
  It also corrects the message in a couple of panic()s that should never occur.
  
  This is another in the series of commits that add support to the NFS client
  and server for building RPC messages in ext_pgs mbufs with anonymous pages.
  This is useful so that the entire mbuf list does not need to be
  copied before calling sosend() when NFS over TLS is enabled.
  
  Use of ext_pgs mbufs will not be enabled until the kernel RPC is updated
  to handle TLS.

Modified:
  head/sys/fs/nfs/nfs_var.h
  head/sys/fs/nfsserver/nfs_nfsdport.c
  head/sys/fs/nfsserver/nfs_nfsdserv.c

Modified: head/sys/fs/nfs/nfs_var.h
==============================================================================
--- head/sys/fs/nfs/nfs_var.h	Fri Jul 31 23:02:17 2020	(r363747)
+++ head/sys/fs/nfs/nfs_var.h	Fri Jul 31 23:35:49 2020	(r363748)
@@ -680,9 +680,9 @@ int nfsvno_namei(struct nfsrv_descript *, struct namei
     vnode_t, int, struct nfsexstuff *, NFSPROC_T *, vnode_t *);
 void nfsvno_setpathbuf(struct nameidata *, char **, u_long **);
 void nfsvno_relpathbuf(struct nameidata *);
-int nfsvno_readlink(vnode_t, struct ucred *, NFSPROC_T *, struct mbuf **,
+int nfsvno_readlink(vnode_t, struct ucred *, int, NFSPROC_T *, struct mbuf **,
     struct mbuf **, int *);
-int nfsvno_read(vnode_t, off_t, int, struct ucred *, NFSPROC_T *,
+int nfsvno_read(vnode_t, off_t, int, struct ucred *, int, NFSPROC_T *,
     struct mbuf **, struct mbuf **);
 int nfsvno_write(vnode_t, off_t, int, int *, struct mbuf *, char *,
     struct ucred *, NFSPROC_T *);
@@ -748,7 +748,7 @@ int nfsvno_seek(struct nfsrv_descript *, struct vnode 
     bool *, struct ucred *, NFSPROC_T *);
 int nfsvno_allocate(struct vnode *, off_t, off_t, struct ucred *, NFSPROC_T *);
 int nfsvno_getxattr(struct vnode *, char *, uint32_t, struct ucred *,
-    struct thread *, struct mbuf **, struct mbuf **, int *);
+    uint64_t, int, 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 *,

Modified: head/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdport.c	Fri Jul 31 23:02:17 2020	(r363747)
+++ head/sys/fs/nfsserver/nfs_nfsdport.c	Fri Jul 31 23:35:49 2020	(r363748)
@@ -108,6 +108,8 @@ extern struct nfsdevicehead nfsrv_devidhead;
 
 static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **,
     struct iovec **);
+static int nfsrv_createiovec_extpgs(int, int, struct mbuf **,
+    struct mbuf **, struct iovec **);
 static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **,
     int *);
 static void nfsrv_pnfscreate(struct vnode *, struct vattr *, struct ucred *,
@@ -738,8 +740,8 @@ nfsvno_relpathbuf(struct nameidata *ndp)
  * Readlink vnode op into an mbuf list.
  */
 int
-nfsvno_readlink(struct vnode *vp, struct ucred *cred, struct thread *p,
-    struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
+nfsvno_readlink(struct vnode *vp, struct ucred *cred, int maxextsiz,
+    struct thread *p, struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
 {
 	struct iovec *iv;
 	struct uio io, *uiop = &io;
@@ -747,7 +749,11 @@ nfsvno_readlink(struct vnode *vp, struct ucred *cred, 
 	int len, tlen, error = 0;
 
 	len = NFS_MAXPATHLEN;
-	uiop->uio_iovcnt = nfsrv_createiovec(len, &mp3, &mp, &iv);
+	if (maxextsiz > 0)
+		uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz,
+		    &mp3, &mp, &iv);
+	else
+		uiop->uio_iovcnt = nfsrv_createiovec(len, &mp3, &mp, &iv);
 	uiop->uio_iov = iv;
 	uiop->uio_offset = 0;
 	uiop->uio_resid = len;
@@ -819,7 +825,7 @@ nfsrv_createiovec(int len, struct mbuf **mpp, struct m
 	i = 0;
 	while (left > 0) {
 		if (m == NULL)
-			panic("nfsvno_read iov");
+			panic("nfsrv_createiovec iov");
 		siz = min(M_TRAILINGSPACE(m), left);
 		if (siz > 0) {
 			iv->iov_base = mtod(m, caddr_t) + m->m_len;
@@ -837,11 +843,76 @@ nfsrv_createiovec(int len, struct mbuf **mpp, struct m
 }
 
 /*
+ * Create an mbuf chain and an associated iovec that can be used to Read
+ * or Getextattr of data.
+ * Upon success, return pointers to the first and last mbufs in the chain
+ * plus the malloc'd iovec and its iovlen.
+ * Same as above, but creates ext_pgs mbuf(s).
+ */
+static int
+nfsrv_createiovec_extpgs(int len, int maxextsiz, struct mbuf **mpp,
+    struct mbuf **mpendp, struct iovec **ivp)
+{
+	struct mbuf *m, *m2 = NULL, *m3;
+	struct iovec *iv;
+	int i, left, pgno, siz;
+
+	left = len;
+	m3 = NULL;
+	/*
+	 * Generate the mbuf list with the uio_iov ref. to it.
+	 */
+	i = 0;
+	while (left > 0) {
+		siz = min(left, maxextsiz);
+		m = mb_alloc_ext_plus_pages(siz, M_WAITOK);
+		left -= siz;
+		i += m->m_epg_npgs;
+		if (m3 != NULL)
+			m2->m_next = m;
+		else
+			m3 = m;
+		m2 = m;
+	}
+	*ivp = iv = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK);
+	m = m3;
+	left = len;
+	i = 0;
+	pgno = 0;
+	while (left > 0) {
+		if (m == NULL)
+			panic("nfsvno_createiovec_extpgs iov");
+		siz = min(PAGE_SIZE, left);
+		if (siz > 0) {
+			iv->iov_base = (void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
+			iv->iov_len = siz;
+			m->m_len += siz;
+			if (pgno == m->m_epg_npgs - 1)
+				m->m_epg_last_len = siz;
+			left -= siz;
+			iv++;
+			i++;
+			pgno++;
+		}
+		if (pgno == m->m_epg_npgs && left > 0) {
+			m = m->m_next;
+			if (m == NULL)
+				panic("nfsvno_createiovec_extpgs iov");
+			pgno = 0;
+		}
+	}
+	*mpp = m3;
+	*mpendp = m2;
+	return (i);
+}
+
+/*
  * Read vnode op call into mbuf list.
  */
 int
 nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred,
-    struct thread *p, struct mbuf **mpp, struct mbuf **mpendp)
+    int maxextsiz, struct thread *p, struct mbuf **mpp,
+    struct mbuf **mpendp)
 {
 	struct mbuf *m;
 	struct iovec *iv;
@@ -860,7 +931,11 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, stru
 		return (error);
 
 	len = NFSM_RNDUP(cnt);
-	uiop->uio_iovcnt = nfsrv_createiovec(len, &m3, &m, &iv);
+	if (maxextsiz > 0)
+		uiop->uio_iovcnt = nfsrv_createiovec_extpgs(len, maxextsiz,
+		    &m3, &m, &iv);
+	else
+		uiop->uio_iovcnt = nfsrv_createiovec(len, &m3, &m, &iv);
 	uiop->uio_iov = iv;
 	uiop->uio_offset = off;
 	uiop->uio_resid = len;
@@ -938,7 +1013,7 @@ nfsrv_createiovecw(int retlen, struct mbuf *m, char *c
 	len = retlen;
 	while (len > 0) {
 		if (mp == NULL)
-			panic("nfsvno_write");
+			panic("nfsrv_createiovecw");
 		if (i > 0) {
 			i = min(i, len);
 			ivp->iov_base = cp;
@@ -6241,8 +6316,8 @@ nfsvno_allocate(struct vnode *vp, off_t off, off_t len
  */
 int
 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 ucred *cred, uint64_t flag, int maxextsiz, struct thread *p,
+    struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
 {
 	struct iovec *iv;
 	struct uio io, *uiop = &io;
@@ -6260,7 +6335,21 @@ nfsvno_getxattr(struct vnode *vp, char *name, uint32_t
 	len = siz;
 	tlen = NFSM_RNDUP(len);
 	if (tlen > 0) {
-		uiop->uio_iovcnt = nfsrv_createiovec(tlen, &m, &m2, &iv);
+		/*
+		 * If cnt > MCLBYTES and the reply will not be saved, use
+		 * ext_pgs mbufs for TLS.
+		 * For NFSv4.0, we do not know for sure if the reply will
+		 * be saved, so do not use ext_pgs mbufs for NFSv4.0.
+		 * Always use ext_pgs mbufs if ND_EXTPG is set.
+		 */
+		if ((flag & ND_EXTPG) != 0 || (tlen > MCLBYTES &&
+		    (flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
+		    (flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
+			uiop->uio_iovcnt = nfsrv_createiovec_extpgs(tlen,
+			    maxextsiz, &m, &m2, &iv);
+		else
+			uiop->uio_iovcnt = nfsrv_createiovec(tlen, &m, &m2,
+			    &iv);
 		uiop->uio_iov = iv;
 	} else {
 		uiop->uio_iovcnt = 0;

Modified: head/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdserv.c	Fri Jul 31 23:02:17 2020	(r363747)
+++ head/sys/fs/nfsserver/nfs_nfsdserv.c	Fri Jul 31 23:35:49 2020	(r363748)
@@ -667,6 +667,7 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused in
 	int getret = 1, len;
 	struct nfsvattr nva;
 	struct thread *p = curthread;
+	uint16_t off;
 
 	if (nd->nd_repstat) {
 		nfsrv_postopattr(nd, getret, &nva);
@@ -678,9 +679,14 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused in
 		else
 			nd->nd_repstat = EINVAL;
 	}
-	if (!nd->nd_repstat)
-		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
-		    &mp, &mpend, &len);
+	if (nd->nd_repstat == 0) {
+		if ((nd->nd_flag & ND_EXTPG) != 0)
+			nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
+			    nd->nd_maxextsiz, p, &mp, &mpend, &len);
+		else
+			nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
+			    0, p, &mp, &mpend, &len);
+	}
 	if (nd->nd_flag & ND_NFSV3)
 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	vput(vp);
@@ -693,7 +699,16 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused in
 	if (mp != NULL) {
 		nd->nd_mb->m_next = mp;
 		nd->nd_mb = mpend;
-		nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
+		if ((mpend->m_flags & M_EXTPG) != 0) {
+			nd->nd_bextpg = mpend->m_epg_npgs - 1;
+			nd->nd_bpos = (char *)(void *)
+			    PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
+			off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
+			nd->nd_bpos += off + mpend->m_epg_last_len;
+			nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
+			    off;
+		} else
+			nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
 	}
 
 out:
@@ -718,6 +733,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 	nfsv4stateid_t stateid;
 	nfsquad_t clientid;
 	struct thread *p = curthread;
+	uint16_t poff;
 
 	if (nd->nd_repstat) {
 		nfsrv_postopattr(nd, getret, &nva);
@@ -839,8 +855,21 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 		cnt = reqlen;
 	m3 = NULL;
 	if (cnt > 0) {
-		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
-		    &m3, &m2);
+		/*
+		 * If cnt > MCLBYTES and the reply will not be saved, use
+		 * ext_pgs mbufs for TLS.
+		 * For NFSv4.0, we do not know for sure if the reply will
+		 * be saved, so do not use ext_pgs mbufs for NFSv4.0.
+		 * Always use ext_pgs mbufs if ND_EXTPG is set.
+		 */
+		if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
+		    (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
+		    (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
+			nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
+			    nd->nd_maxextsiz, p, &m3, &m2);
+		else
+			nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
+			    0, p, &m3, &m2);
 		if (!(nd->nd_flag & ND_NFSV4)) {
 			getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 			if (!nd->nd_repstat)
@@ -875,7 +904,17 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 	if (m3) {
 		nd->nd_mb->m_next = m3;
 		nd->nd_mb = m2;
-		nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len;
+		if ((m2->m_flags & M_EXTPG) != 0) {
+			nd->nd_flag |= ND_EXTPG;
+			nd->nd_bextpg = m2->m_epg_npgs - 1;
+			nd->nd_bpos = (char *)(void *)
+			    PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
+			poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
+			nd->nd_bpos += poff + m2->m_epg_last_len;
+			nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
+			    poff;
+		} else
+			nd->nd_bpos = mtod(m2, char *) + m2->m_len;
 	}
 
 out:
@@ -5536,6 +5575,7 @@ nfsrvd_getxattr(struct nfsrv_descript *nd, __unused in
 	int error, len;
 	char *name;
 	struct thread *p = curthread;
+	uint16_t off;
 
 	error = 0;
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
@@ -5555,8 +5595,9 @@ 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_maxresp,
-		    nd->nd_cred, p, &mp, &mpend, &len);
+		nd->nd_repstat = nfsvno_getxattr(vp, name,
+		    nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
+		    nd->nd_maxextsiz, p, &mp, &mpend, &len);
 	if (nd->nd_repstat == ENOATTR)
 		nd->nd_repstat = NFSERR_NOXATTR;
 	else if (nd->nd_repstat == EOPNOTSUPP)
@@ -5567,7 +5608,19 @@ nfsrvd_getxattr(struct nfsrv_descript *nd, __unused in
 		if (len > 0) {
 			nd->nd_mb->m_next = mp;
 			nd->nd_mb = mpend;
-			nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len;
+			if ((mpend->m_flags & M_EXTPG) != 0) {
+				nd->nd_flag |= ND_EXTPG;
+				nd->nd_bextpg = mpend->m_epg_npgs - 1;
+				nd->nd_bpos = (char *)(void *)
+				   PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
+				off = (nd->nd_bextpg == 0) ?
+				    mpend->m_epg_1st_off : 0;
+				nd->nd_bpos += off + mpend->m_epg_last_len;
+				nd->nd_bextpgsiz = PAGE_SIZE -
+				    mpend->m_epg_last_len - off;
+			} else
+				nd->nd_bpos = mtod(mpend, char *) +
+				    mpend->m_len;
 		}
 	}
 	free(name, M_TEMP);


More information about the svn-src-all mailing list