svn commit: r358043 - projects/nfs-over-tls/sys/fs/nfs
Rick Macklem
rmacklem at FreeBSD.org
Mon Feb 17 20:19:44 UTC 2020
Author: rmacklem
Date: Mon Feb 17 20:19:43 2020
New Revision: 358043
URL: https://svnweb.freebsd.org/changeset/base/358043
Log:
Fix the NFS code so that it can handle ext_pgs mbufs. This is quite a
bit of churn, but I am trying to make sure I don't break the non-ext_pgs
mbufs case.
This updates sys/fs/nfs. Further commits will update sys/fs/nfsclient and
sys/fs/nfsserver.
Modified:
projects/nfs-over-tls/sys/fs/nfs/nfs.h
projects/nfs-over-tls/sys/fs/nfs/nfs_commonkrpc.c
projects/nfs-over-tls/sys/fs/nfs/nfs_commonsubs.c
projects/nfs-over-tls/sys/fs/nfs/nfs_var.h
projects/nfs-over-tls/sys/fs/nfs/nfscl.h
projects/nfs-over-tls/sys/fs/nfs/nfsm_subs.h
Modified: projects/nfs-over-tls/sys/fs/nfs/nfs.h
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfs/nfs.h Mon Feb 17 20:14:59 2020 (r358042)
+++ projects/nfs-over-tls/sys/fs/nfs/nfs.h Mon Feb 17 20:19:43 2020 (r358043)
@@ -645,7 +645,12 @@ struct nfsrv_descript {
NFSSOCKADDR_T nd_nam; /* and socket addr */
NFSSOCKADDR_T nd_nam2; /* return socket addr */
caddr_t nd_dpos; /* Current dissect pos */
+ int nd_dextpg; /* Current ext_pgs page */
+ int nd_dextpgsiz; /* Bytes left in page */
caddr_t nd_bpos; /* Current build pos */
+ int nd_bextpg; /* Current ext_pgs page */
+ int nd_bextpgsiz; /* Bytes left in page */
+ int nd_maxextsiz; /* Max ext_pgs mbuf size */
u_int64_t nd_flag; /* nd_flag */
u_int16_t nd_procnum; /* RPC # */
u_int32_t nd_repstat; /* Reply status */
@@ -711,6 +716,8 @@ struct nfsrv_descript {
#define ND_SAVEDCURSTATEID 0x100000000
#define ND_HASSLOTID 0x200000000
#define ND_NFSV42 0x400000000
+#define ND_EXTPG 0x800000000
+#define ND_TLS 0x1000000000
/*
* ND_GSS should be the "or" of all GSS type authentications.
Modified: projects/nfs-over-tls/sys/fs/nfs/nfs_commonkrpc.c
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfs/nfs_commonkrpc.c Mon Feb 17 20:14:59 2020 (r358042)
+++ projects/nfs-over-tls/sys/fs/nfs/nfs_commonkrpc.c Mon Feb 17 20:19:43 2020 (r358043)
@@ -285,7 +285,8 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
if ((nmp->nm_flag & NFSMNT_RESVPORT))
CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
-CLNT_CONTROL(client, CLSET_TLS, &one);
+ if (NFSHASTLS(nmp))
+ CLNT_CONTROL(client, CLSET_TLS, &one);
if (NFSHASSOFT(nmp)) {
if (nmp->nm_sotype == SOCK_DGRAM)
/*
@@ -897,9 +898,11 @@ tryagain:
* These could cause pointer alignment problems, so copy them to
* well aligned mbufs.
*/
+#ifdef notnow
newnfs_realign(&nd->nd_mrep, M_WAITOK);
+#endif
nd->nd_md = nd->nd_mrep;
- nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
+ nfsm_set(nd, false);
nd->nd_repstat = 0;
if (nd->nd_procnum != NFSPROC_NULL &&
nd->nd_procnum != NFSV4PROC_CBNULL) {
Modified: projects/nfs-over-tls/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfs-over-tls/sys/fs/nfs/nfs_commonsubs.c Mon Feb 17 20:14:59 2020 (r358042)
+++ projects/nfs-over-tls/sys/fs/nfs/nfs_commonsubs.c Mon Feb 17 20:19:43 2020 (r358043)
@@ -44,11 +44,14 @@ __FBSDID("$FreeBSD$");
#ifndef APPLEKEXT
#include "opt_inet.h"
#include "opt_inet6.h"
+#include "opt_kern_tls.h"
#include <fs/nfs/nfsport.h>
#include <sys/extattr.h>
+#include <rpc/krpc.h>
+
#include <security/mac/mac_framework.h>
/*
@@ -84,6 +87,9 @@ extern volatile int nfsrv_devidcnt;
extern int nfscl_debuglevel;
extern struct nfsdevicehead nfsrv_devidhead;
extern struct nfsstatsv1 nfsstatsv1;
+#ifdef KERN_TLS
+extern u_int ktls_maxlen;
+#endif
SYSCTL_DECL(_vfs_nfs);
SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
@@ -97,6 +103,10 @@ int nfs_maxcopyrange = 10 * 1024 * 1024;
SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
&nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
+bool nfs_use_ext_pgs = false;
+SYSCTL_BOOL(_vfs_nfs, OID_AUTO, use_ext_pgs, CTLFLAG_RW, &nfs_use_ext_pgs,
+ 0, "Set true to use TCP");
+
/*
* This array of structures indicates, for V4:
* retfh - which of 3 types of calling args are used
@@ -229,6 +239,11 @@ static void nfsrv_removeuser(struct nfsusrgrp *usrp, i
static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
int *, int *);
static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
+static int nfsm_copyfrommbuf(struct nfsrv_descript *, char *, enum uio_seg,
+ int);
+static int nfsm_copyfrommbuf_extpgs(struct nfsrv_descript *, char *,
+ enum uio_seg, int);
+static struct mbuf *nfsm_splitatpgno(struct mbuf *, int, int);
static struct {
int op;
@@ -319,7 +334,7 @@ static int nfs_bigrequest[NFSV42_NPROCS] = {
APPLESTATIC void
nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
- int vers, int minorvers)
+ int vers, int minorvers, bool use_ext)
{
struct mbuf *mb;
u_int32_t *tl;
@@ -352,17 +367,32 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum,
}
nd->nd_procnum = procnum;
nd->nd_repstat = 0;
+ nd->nd_maxextsiz = 16384;
+ if (use_ext && PMAP_HAS_DMAP != 0) {
+ nd->nd_flag |= ND_EXTPG;
+#ifdef KERN_TLS
+ nd->nd_maxextsiz = min(TLS_MAX_MSG_SIZE_V10_2,
+ ktls_maxlen);
+#endif
+ }
/*
* Get the first mbuf for the request.
*/
- if (nfs_bigrequest[procnum])
- NFSMCLGET(mb, M_WAITOK);
- else
- NFSMGET(mb);
- mbuf_setlen(mb, 0);
- nd->nd_mreq = nd->nd_mb = mb;
- nd->nd_bpos = NFSMTOD(mb, caddr_t);
+ if ((nd->nd_flag & ND_EXTPG) != 0) {
+ mb = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK, false,
+ mb_free_mext_pgs);
+ nd->nd_mreq = nd->nd_mb = mb;
+ nfsm_set(nd, true);
+ } else {
+ if (nfs_bigrequest[procnum])
+ NFSMCLGET(mb, M_WAITOK);
+ else
+ NFSMGET(mb);
+ mb->m_len = 0;
+ nd->nd_mreq = nd->nd_mb = mb;
+ nd->nd_bpos = mtod(mb, char *);
+ }
/*
* And fill the first file handle into the request.
@@ -609,15 +639,11 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vatt
int
nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
{
- char *mbufcp, *uiocp;
+ char *uiocp;
int xfer, left, len;
- mbuf_t mp;
long uiosiz, rem;
int error = 0;
- mp = nd->nd_md;
- mbufcp = nd->nd_dpos;
- len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
rem = NFSM_RNDUP(siz) - siz;
while (siz > 0) {
if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
@@ -630,35 +656,21 @@ nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *ui
left = siz;
uiosiz = left;
while (left > 0) {
- while (len == 0) {
- mp = mbuf_next(mp);
- if (mp == NULL) {
- error = EBADRPC;
- goto out;
- }
- mbufcp = NFSMTOD(mp, caddr_t);
- len = mbuf_len(mp);
- KASSERT(len >= 0,
- ("len %d, corrupted mbuf?", len));
- }
- xfer = (left > len) ? len : left;
-#ifdef notdef
- /* Not Yet.. */
- if (uiop->uio_iov->iov_op != NULL)
- (*(uiop->uio_iov->iov_op))
- (mbufcp, uiocp, xfer);
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ xfer = nfsm_copyfrommbuf_extpgs(nd, uiocp,
+ uiop->uio_segflg, left);
else
-#endif
- if (uiop->uio_segflg == UIO_SYSSPACE)
- NFSBCOPY(mbufcp, uiocp, xfer);
- else
- copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
+ xfer = nfsm_copyfrommbuf(nd, uiocp,
+ uiop->uio_segflg, left);
left -= xfer;
- len -= xfer;
- mbufcp += xfer;
uiocp += xfer;
uiop->uio_offset += xfer;
uiop->uio_resid -= xfer;
+ if (left > 0 && !nfsm_shiftnext(nd, &len)) {
+ error = EBADRPC;
+ goto out;
+ }
}
if (uiop->uio_iov->iov_len <= siz) {
uiop->uio_iovcnt--;
@@ -670,14 +682,8 @@ nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *ui
}
siz -= uiosiz;
}
- nd->nd_dpos = mbufcp;
- nd->nd_md = mp;
- if (rem > 0) {
- if (len < rem)
- error = nfsm_advance(nd, rem, len);
- else
- nd->nd_dpos += rem;
- }
+ if (rem > 0)
+ error = nfsm_advance(nd, rem, -1);
out:
NFSEXITCODE2(error, nd);
@@ -694,59 +700,94 @@ out:
APPLESTATIC void *
nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
{
- mbuf_t mp2;
+ struct mbuf *mp2;
+ struct mbuf_ext_pgs *pgs;
int siz2, xfer;
caddr_t p;
int left;
caddr_t retp;
retp = NULL;
- left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ left = nd->nd_dextpgsiz;
+ else
+ left = mtod(nd->nd_md, char *) + nd->nd_md->m_len -
+ nd->nd_dpos;
while (left == 0) {
- nd->nd_md = mbuf_next(nd->nd_md);
- if (nd->nd_md == NULL)
- return (retp);
- left = mbuf_len(nd->nd_md);
- nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP) && nd->nd_dextpg <
+ nd->nd_md->m_ext.ext_pgs->npgs - 1) {
+ pgs = nd->nd_md->m_ext.ext_pgs;
+ nd->nd_dextpg++;
+ nd->nd_dpos = (char *)(void *)
+ PHYS_TO_DMAP(pgs->pa[nd->nd_dextpg]);
+ left = nd->nd_dextpgsiz = mbuf_ext_pg_len(pgs,
+ nd->nd_dextpg, 0);
+ } else if (!nfsm_shiftnext(nd, &left))
+ return (NULL);
}
if (left >= siz) {
retp = nd->nd_dpos;
nd->nd_dpos += siz;
- } else if (mbuf_next(nd->nd_md) == NULL) {
- return (retp);
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ nd->nd_dextpgsiz -= siz;
} else if (siz > ncl_mbuf_mhlen) {
panic("nfs S too big");
} else {
+ /* Make sure an ext_pgs mbuf is at the last page. */
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP)) {
+ if (nd->nd_dextpg <
+ nd->nd_md->m_ext.ext_pgs->npgs - 1) {
+ mp2 = nfsm_splitatpgno(nd->nd_md,
+ nd->nd_dextpg, how);
+ if (mp2 == NULL)
+ return (NULL);
+ }
+ nd->nd_md->m_ext.ext_pgs->last_pg_len -=
+ left;
+ }
+ if (nd->nd_md->m_next == NULL)
+ return (NULL);
+
+ /* Allocate a new mbuf for the "siz" bytes of data. */
MGET(mp2, MT_DATA, how);
if (mp2 == NULL)
return (NULL);
- mbuf_setnext(mp2, mbuf_next(nd->nd_md));
- mbuf_setnext(nd->nd_md, mp2);
- mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
- nd->nd_md = mp2;
- retp = p = NFSMTOD(mp2, caddr_t);
- NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
+
+ /*
+ * Link the new mp2 mbuf into the list then copy left
+ * bytes from the mbuf before it and siz - left bytes
+ * from the mbuf after it.
+ */
+ mp2->m_next = nd->nd_md->m_next;
+ nd->nd_md->m_next = mp2;
+ nd->nd_md->m_len -= left;
+ retp = p = mtod(mp2, char *);
+ memcpy(p, nd->nd_dpos, left); /* Copy what was left */
siz2 = siz - left;
p += left;
- mp2 = mbuf_next(mp2);
+ mp2->m_len = siz;
+ nd->nd_md = mp2->m_next;
/* Loop around copying up the siz2 bytes */
while (siz2 > 0) {
- if (mp2 == NULL)
+ if (nd->nd_md == NULL)
return (NULL);
- xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
- if (xfer > 0) {
- NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
- NFSM_DATAP(mp2, xfer);
- mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
- p += xfer;
- siz2 -= xfer;
- }
+ nfsm_set(nd, false);
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ xfer = nfsm_copyfrommbuf_extpgs(nd, p,
+ UIO_SYSSPACE, siz2);
+ else
+ xfer = nfsm_copyfrommbuf(nd, p,
+ UIO_SYSSPACE, siz2);
+ p += xfer;
+ siz2 -= xfer;
if (siz2 > 0)
- mp2 = mbuf_next(mp2);
+ nd->nd_md = nd->nd_md->m_next;
}
- mbuf_setlen(nd->nd_md, siz);
- nd->nd_md = mp2;
- nd->nd_dpos = NFSMTOD(mp2, caddr_t);
}
return (retp);
}
@@ -760,7 +801,7 @@ nfsm_dissct(struct nfsrv_descript *nd, int siz, int ho
APPLESTATIC int
nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
{
- int error = 0;
+ int error = 0, xfer;
if (offs == 0)
goto out;
@@ -777,24 +818,41 @@ nfsm_advance(struct nfsrv_descript *nd, int offs, int
/*
* If left == -1, calculate it here.
*/
- if (left == -1)
- left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
- nd->nd_dpos;
+ if (left == -1) {
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ left = nd->nd_dextpgsiz;
+ else
+ left = mtod(nd->nd_md, char *) +
+ nd->nd_md->m_len - nd->nd_dpos;
+ }
/*
* Loop around, advancing over the mbuf data.
*/
while (offs > left) {
- offs -= left;
- nd->nd_md = mbuf_next(nd->nd_md);
- if (nd->nd_md == NULL) {
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP) && nd->nd_dextpg <
+ nd->nd_md->m_ext.ext_pgs->npgs - 1) {
+ xfer = nfsm_copyfrommbuf_extpgs(nd, NULL,
+ UIO_SYSSPACE, offs);
+ offs -= xfer;
+ } else
+ offs -= left;
+ left = 0;
+ if (offs > 0 && !nfsm_shiftnext(nd, &left)) {
error = EBADRPC;
goto out;
}
- left = mbuf_len(nd->nd_md);
- nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
}
- nd->nd_dpos += offs;
+ if (offs > 0) {
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ nfsm_copyfrommbuf_extpgs(nd, NULL,
+ UIO_SYSSPACE, offs);
+ else
+ nd->nd_dpos += offs;
+ }
out:
NFSEXITCODE(error);
@@ -821,22 +879,38 @@ nfsm_strtom(struct nfsrv_descript *nd, const char *cp,
bytesize = NFSX_UNSIGNED + siz + rem;
m2 = nd->nd_mb;
cp2 = nd->nd_bpos;
- left = M_TRAILINGSPACE(m2);
+ if ((nd->nd_flag & ND_EXTPG) != 0)
+ left = nd->nd_bextpgsiz;
+ else
+ left = M_TRAILINGSPACE(m2);
+ KASSERT(((m2->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP) && (nd->nd_flag & ND_EXTPG) != 0) ||
+ ((m2->m_flags & (M_EXT | M_NOMAP)) !=
+ (M_EXT | M_NOMAP) && (nd->nd_flag & ND_EXTPG) == 0),
+ ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
/*
* Loop around copying the string to mbuf(s).
*/
while (siz > 0) {
if (left == 0) {
- if (siz > ncl_mbuf_mlen)
- NFSMCLGET(m1, M_WAITOK);
- else
- NFSMGET(m1);
- mbuf_setlen(m1, 0);
- mbuf_setnext(m2, m1);
- m2 = m1;
- cp2 = NFSMTOD(m2, caddr_t);
- left = M_TRAILINGSPACE(m2);
+ if ((nd->nd_flag & ND_EXTPG) != 0) {
+ m2 = nfsm_add_ext_pgs(m2,
+ nd->nd_maxextsiz, &nd->nd_bextpg);
+ cp2 = (char *)(void *)PHYS_TO_DMAP(
+ m2->m_ext.ext_pgs->pa[nd->nd_bextpg]);
+ nd->nd_bextpgsiz = left = PAGE_SIZE;
+ } else {
+ if (siz > ncl_mbuf_mlen)
+ NFSMCLGET(m1, M_WAITOK);
+ else
+ NFSMGET(m1);
+ m1->m_len = 0;
+ cp2 = mtod(m1, char *);
+ left = M_TRAILINGSPACE(m1);
+ m2->m_next = m1;
+ m2 = m1;
+ }
}
if (left >= siz)
xfer = siz;
@@ -844,18 +918,31 @@ nfsm_strtom(struct nfsrv_descript *nd, const char *cp,
xfer = left;
NFSBCOPY(cp, cp2, xfer);
cp += xfer;
- mbuf_setlen(m2, mbuf_len(m2) + xfer);
+ cp2 += xfer;
+ m2->m_len += xfer;
siz -= xfer;
left -= xfer;
+ if ((nd->nd_flag & ND_EXTPG) != 0) {
+ nd->nd_bextpgsiz -= xfer;
+ m2->m_ext.ext_pgs->last_pg_len += xfer;
+ }
if (siz == 0 && rem) {
if (left < rem)
panic("nfsm_strtom");
- NFSBZERO(cp2 + xfer, rem);
- mbuf_setlen(m2, mbuf_len(m2) + rem);
+ NFSBZERO(cp2, rem);
+ m2->m_len += rem;
+ cp2 += rem;
+ if ((nd->nd_flag & ND_EXTPG) != 0) {
+ nd->nd_bextpgsiz -= rem;
+ m2->m_ext.ext_pgs->last_pg_len += rem;
+ }
}
}
nd->nd_mb = m2;
- nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
+ if ((nd->nd_flag & ND_EXTPG) != 0)
+ nd->nd_bpos = cp2;
+ else
+ nd->nd_bpos = mtod(m2, char *) + m2->m_len;
return (bytesize);
}
@@ -1008,66 +1095,46 @@ nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
/*
- * Trim the stuff already dissected off the mbuf list.
- */
-APPLESTATIC void
-newnfs_trimleading(nd)
- struct nfsrv_descript *nd;
-{
- mbuf_t m, n;
- int offs;
-
- /*
- * First, free up leading mbufs.
- */
- if (nd->nd_mrep != nd->nd_md) {
- m = nd->nd_mrep;
- while (mbuf_next(m) != nd->nd_md) {
- if (mbuf_next(m) == NULL)
- panic("nfsm trim leading");
- m = mbuf_next(m);
- }
- mbuf_setnext(m, NULL);
- mbuf_freem(nd->nd_mrep);
- }
- m = nd->nd_md;
-
- /*
- * Now, adjust this mbuf, based on nd_dpos.
- */
- offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
- if (offs == mbuf_len(m)) {
- n = m;
- m = mbuf_next(m);
- if (m == NULL)
- panic("nfsm trim leading2");
- mbuf_setnext(n, NULL);
- mbuf_freem(n);
- } else if (offs > 0) {
- mbuf_setlen(m, mbuf_len(m) - offs);
- NFSM_DATAP(m, offs);
- } else if (offs < 0)
- panic("nfsm trimleading offs");
- nd->nd_mrep = m;
- nd->nd_md = m;
- nd->nd_dpos = NFSMTOD(m, caddr_t);
-}
-
-/*
* Trim trailing data off the mbuf list being built.
*/
APPLESTATIC void
-newnfs_trimtrailing(nd, mb, bpos)
- struct nfsrv_descript *nd;
- mbuf_t mb;
- caddr_t bpos;
+nfsm_trimtrailing(struct nfsrv_descript *nd, struct mbuf *mb, char *bpos,
+ int bextpg, int bextpgsiz)
{
+ struct mbuf_ext_pgs *pgs;
+ vm_page_t pg;
+ int fullpgsiz, i;
+ char *ppos;
- if (mbuf_next(mb)) {
- mbuf_freem(mbuf_next(mb));
- mbuf_setnext(mb, NULL);
+ if (mb->m_next != NULL) {
+ m_freem(mb->m_next);
+ mb->m_next = NULL;
}
- mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
+ if ((mb->m_flags & (M_EXT | M_NOMAP)) == (M_EXT | M_NOMAP)) {
+ pgs = mb->m_ext.ext_pgs;
+ /* First, get rid of any pages after this position. */
+ for (i = pgs->npgs - 1; i > bextpg; i--) {
+ pg = PHYS_TO_VM_PAGE(pgs->pa[i]);
+ vm_page_unwire_noq(pg);
+ vm_page_free(pg);
+ }
+ pgs->npgs = bextpg + 1;
+ if (bextpg == 0)
+ fullpgsiz = PAGE_SIZE - pgs->first_pg_off;
+ else
+ fullpgsiz = PAGE_SIZE;
+ pgs->last_pg_len = fullpgsiz - bextpgsiz;
+ mb->m_len = mbuf_ext_pg_len(pgs, 0, pgs->first_pg_off);
+ for (i = 1; i < pgs->npgs; i++)
+ mb->m_len += mbuf_ext_pg_len(pgs, i, 0);
+ ppos = (char *)(void *)PHYS_TO_DMAP(pgs->pa[bextpg]);
+ ppos += pgs->last_pg_len;
+ if (ppos != bpos)
+ printf("EEK trimtrail\n");
+ nd->nd_bextpgsiz = bextpgsiz;
+ nd->nd_bextpg = bextpg;
+ } else
+ mb->m_len = bpos - mtod(mb, char *);
nd->nd_mb = mb;
nd->nd_bpos = bpos;
}
@@ -2421,45 +2488,27 @@ nfsv4_wanted(struct nfsv4lock *lp)
APPLESTATIC int
nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
{
- char *cp;
- int xfer, len;
- mbuf_t mp;
- int rem, error = 0;
+ int rem, error = 0, xfer;
- mp = nd->nd_md;
- cp = nd->nd_dpos;
- len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
rem = NFSM_RNDUP(siz) - siz;
while (siz > 0) {
- if (len > siz)
- xfer = siz;
+ if ((nd->nd_md->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP))
+ xfer = nfsm_copyfrommbuf_extpgs(nd, str,
+ UIO_SYSSPACE, siz);
else
- xfer = len;
- NFSBCOPY(cp, str, xfer);
+ xfer = nfsm_copyfrommbuf(nd, str,
+ UIO_SYSSPACE, siz);
str += xfer;
siz -= xfer;
- if (siz > 0) {
- mp = mbuf_next(mp);
- if (mp == NULL) {
- error = EBADRPC;
- goto out;
- }
- cp = NFSMTOD(mp, caddr_t);
- len = mbuf_len(mp);
- } else {
- cp += xfer;
- len -= xfer;
+ if (siz > 0 && !nfsm_shiftnext(nd, &xfer)) {
+ error = EBADRPC;
+ goto out;
}
}
*str = '\0';
- nd->nd_dpos = cp;
- nd->nd_md = mp;
- if (rem > 0) {
- if (len < rem)
- error = nfsm_advance(nd, rem, len);
- else
- nd->nd_dpos += rem;
- }
+ if (rem > 0)
+ error = nfsm_advance(nd, rem, -1);
out:
NFSEXITCODE2(error, nd);
@@ -2550,7 +2599,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount
if (error == 0)
error = VOP_GETACL(vp, ACL_TYPE_NFS4,
naclp, cred, p);
- NFSVOPUNLOCK(vp);
+ NFSVOPUNLOCK(vp, 0);
} else
error = NFSERR_PERM;
if (error != 0) {
@@ -2570,7 +2619,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount
if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
"xxx", NULL, &atsiz, cred, p);
- NFSVOPUNLOCK(vp);
+ NFSVOPUNLOCK(vp, 0);
if (error != EOPNOTSUPP)
xattrsupp = true;
}
@@ -4439,21 +4488,31 @@ nfsrvd_rephead(struct nfsrv_descript *nd)
{
mbuf_t mreq;
- /*
- * If this is a big reply, use a cluster.
- */
- if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
- nfs_bigreply[nd->nd_procnum]) {
- NFSMCLGET(mreq, M_WAITOK);
- nd->nd_mreq = mreq;
- nd->nd_mb = mreq;
+ if ((nd->nd_flag & ND_EXTPG) != 0) {
+ mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK, false,
+ mb_free_mext_pgs);
+ nd->nd_mreq = nd->nd_mb = mreq;
+ nd->nd_bpos = (char *)(void *)
+ PHYS_TO_DMAP(mreq->m_ext.ext_pgs->pa[0]);
+ nd->nd_bextpg = 0;
+ nd->nd_bextpgsiz = PAGE_SIZE;
} else {
- NFSMGET(mreq);
- nd->nd_mreq = mreq;
- nd->nd_mb = mreq;
+ /*
+ * If this is a big reply, use a cluster.
+ */
+ if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
+ nfs_bigreply[nd->nd_procnum]) {
+ NFSMCLGET(mreq, M_WAITOK);
+ nd->nd_mreq = mreq;
+ nd->nd_mb = mreq;
+ } else {
+ NFSMGET(mreq);
+ nd->nd_mreq = mreq;
+ nd->nd_mb = mreq;
+ }
+ nd->nd_bpos = mtod(mreq, char *);
+ mreq->m_len = 0;
}
- nd->nd_bpos = NFSMTOD(mreq, caddr_t);
- mbuf_setlen(mreq, 0);
if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
@@ -4826,5 +4885,290 @@ nfsv4_findmirror(struct nfsmount *nmp)
}
}
return (ds);
+}
+
+/*
+ * Fill in the fields of "struct nfsrv_descript" for a new ext_pgs mbuf.
+ * The build argument is true for build and false for dissect.
+ */
+int
+nfsm_set(struct nfsrv_descript *nd, bool build)
+{
+ struct mbuf *m;
+ struct mbuf_ext_pgs *pgs;
+ int rlen;
+
+ if (build)
+ m = nd->nd_mb;
+ else
+ m = nd->nd_md;
+ if ((m->m_flags & (M_EXT | M_NOMAP)) == (M_EXT | M_NOMAP)) {
+ if (build) {
+ pgs = m->m_ext.ext_pgs;
+ nd->nd_bpos = (char *)(void *)
+ PHYS_TO_DMAP(pgs->pa[0]);
+ nd->nd_bpos += pgs->first_pg_off;
+ nd->nd_bextpg = 0;
+ /* For build, set the size that can be filled. */
+ rlen = nd->nd_bextpgsiz = PAGE_SIZE -
+ pgs->first_pg_off;
+ } else {
+ pgs = m->m_ext.ext_pgs;
+ nd->nd_dpos = (char *)(void *)
+ PHYS_TO_DMAP(pgs->pa[0]);
+ nd->nd_dpos += pgs->first_pg_off;
+ nd->nd_dextpg = 0;
+ /* For dissect, set the size already filled. */
+ rlen = nd->nd_dextpgsiz = mbuf_ext_pg_len(pgs, 0,
+ pgs->first_pg_off);
+ }
+ } else if (build) {
+ nd->nd_bpos = mtod(m, char *);
+ rlen = m->m_len;
+ } else {
+ nd->nd_dpos = mtod(m, char *);
+ rlen = m->m_len;
+ }
+ return (rlen);
+}
+
+/*
+ * Copy up to "len" bytes from the mbuf into "cp" and adjust the
+ * mbuf accordingly.
+ * If cp == NULL, do not do the actual copy, but adjust the mbuf.
+ * Return the number of bytes actually copied.
+ * Adjust m_data and m_len so that a future calculation of what
+ * is left using mtod() will work correctly.
+ */
+static int
+nfsm_copyfrommbuf(struct nfsrv_descript *nd, char *cp, enum uio_seg segflg,
+ int len)
+{
+ struct mbuf *m;
+ int xfer;
+
+ m = nd->nd_md;
+ xfer = mtod(m, char *) + m->m_len - nd->nd_dpos;
+ xfer = min(xfer, len);
+ if (xfer > 0) {
+ if (cp != NULL) {
+ if (segflg == UIO_SYSSPACE)
+ memcpy(cp, nd->nd_dpos, xfer);
+ else
+ copyout(nd->nd_dpos, cp, xfer);
+ }
+ nd->nd_dpos += xfer;
+ m->m_data += xfer;
+ m->m_len -= xfer;
+ }
+ return (xfer);
+}
+
+/*
+ * Copy up to "len" bytes from the mbuf into "cp" and adjust the
+ * mbuf accordingly.
+ * If cp == NULL, do not do the actual copy, but adjust the mbuf.
+ * Return the number of bytes actually copied.
+ * Same as above, but for an ext_pgs mbuf.
+ */
+static int
+nfsm_copyfrommbuf_extpgs(struct nfsrv_descript *nd, char *cp,
+ enum uio_seg segflg, int len)
+{
+ struct mbuf_ext_pgs *pgs;
+ int tlen, xfer;
+
+ pgs = nd->nd_md->m_ext.ext_pgs;
+ tlen = 0;
+ /* Copy from the page(s) into cp. */
+ do {
+ xfer = nd->nd_dextpgsiz;
+ xfer = min(xfer, len);
+ if (cp != NULL && xfer > 0) {
+ if (segflg == UIO_SYSSPACE)
+ memcpy(cp, nd->nd_dpos, xfer);
+ else
+ copyout(nd->nd_dpos, cp, xfer);
+ cp += xfer;
+ }
+ tlen += xfer;
+ len -= xfer;
+ nd->nd_dextpgsiz -= xfer;
+ nd->nd_dpos += xfer;
+ if (nd->nd_dextpgsiz == 0 && len > 0 &&
+ nd->nd_dextpg < pgs->npgs - 1) {
+ nd->nd_dextpg++;
+ nd->nd_dpos = (char *)(void *)
+ PHYS_TO_DMAP(pgs->pa[nd->nd_dextpg]);
+ nd->nd_dextpgsiz = mbuf_ext_pg_len(pgs,
+ nd->nd_dextpg, 0);
+ }
+ } while (len > 0 && nd->nd_dextpgsiz > 0);
+ return (tlen);
+}
+
+/*
+ * Split an ext_pgs mbuf into two ext_pgs mbufs on a page boundary.
+ */
+static struct mbuf *
+nfsm_splitatpgno(struct mbuf *mp, int pgno, int how)
+{
+ struct mbuf *m;
+ struct mbuf_ext_pgs *pgs, *pgs0;
+ int i, j, tlen;
+
+ KASSERT((mp->m_flags & (M_EXT | M_NOMAP)) ==
+ (M_EXT | M_NOMAP), ("nfsm_splitatpgno: mp not ext_pgs"));
+ pgs = mp->m_ext.ext_pgs;
+ KASSERT(pgno < pgs->npgs - 1, ("nfsm_splitatpgno:"
+ " at the last page"));
+ m = mb_alloc_ext_pgs(how, false, mb_free_mext_pgs);
+ if (m == NULL)
+ return (m);
+ pgs0 = m->m_ext.ext_pgs;
+
+ /* Move the pages beyond pgno to the new mbuf. */
+ for (i = pgno + 1, j = 0; i < pgs->npgs; i++, j++)
+ pgs0->pa[j] = pgs->pa[i];
+ pgs0->npgs = j;
+ pgs0->last_pg_len = pgs->last_pg_len;
+ pgs->npgs = pgno + 1;
+ pgs->last_pg_len = PAGE_SIZE;
+ if (pgno == 0)
+ pgs->last_pg_len -= pgs->first_pg_off;
+
+ /* Now set m_len for both mbufs. */
+ tlen = mbuf_ext_pg_len(pgs, 0, pgs->first_pg_off);
+ for (i = 1; i < pgs->npgs; i++)
+ tlen += mbuf_ext_pg_len(pgs, i, 0);
+ mp->m_len = tlen;
+
+ /* The new mbuf has first_pg_off == 0. */
+ tlen = 0;
+ for (i = 0; i < pgs0->npgs; i++)
+ tlen += mbuf_ext_pg_len(pgs0, i, 0);
+ m->m_len = tlen;
+
+ /* Link the new mbuf after mp. */
+ m->m_next = mp->m_next;
+ mp->m_next = m;
+ return (mp);
+}
+
+/*
+ * Shift to the next mbuf in the list list and update the nd fields.
+ * Return true if successful, false otherwise.
+ */
+bool
+nfsm_shiftnext(struct nfsrv_descript *nd, int *leftp)
+{
+
+ nd->nd_md = nd->nd_md->m_next;
+ if (nd->nd_md == NULL)
+ return (false);
+ *leftp = nfsm_set(nd, false);
+ return (true);
+}
+
+/*
+ * Grow a ext_pgs mbuf list. Either allocate another page or add
+ * an mbuf to the list.
+ */
+struct mbuf *
+nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
+{
+ struct mbuf_ext_pgs *pgs;
+ struct mbuf *mp;
+ vm_page_t pg;
+
+ pgs = m->m_ext.ext_pgs;
+ if ((pgs->npgs + 1) * PAGE_SIZE > maxextsiz) {
+ mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK,
+ false, mb_free_mext_pgs);
+ *bextpg = 0;
+ m->m_next = mp;
+ } else {
+ do {
+ pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP |
+ VM_ALLOC_WIRED);
+ if (pg == NULL)
+ vm_wait(NULL);
+ } while (pg == NULL);
+ pgs->pa[pgs->npgs] = VM_PAGE_TO_PHYS(pg);
+ *bextpg = pgs->npgs;
+ pgs->npgs++;
+ pgs->last_pg_len = 0;
+ mp = m;
+ }
+ return (mp);
+}
+
+/*
+ * Trim the ext_pgs mbuf to the current dissect position.
+ */
+void
+nfsm_trimatpos_extpgs(struct nfsrv_descript *nd)
+{
+ struct mbuf_ext_pgs *pgs;
+ vm_page_t pg;
+ int i, j;
+
+ pgs = nd->nd_md->m_ext.ext_pgs;
+ for (i = 0; i < nd->nd_dextpg; i++) {
+ pg = PHYS_TO_VM_PAGE(pgs->pa[0]);
+ vm_page_unwire_noq(pg);
+ vm_page_free(pg);
+ nd->nd_md->m_len -= mbuf_ext_pg_len(pgs, i,
+ pgs->first_pg_off);
+ pgs->first_pg_off = 0;
+ for (j = 0; j < pgs->npgs - 1; j++)
+ pgs->pa[j] = pgs->pa[j + 1];
+ pgs->npgs--;
+ }
+ nd->nd_dextpg = 0;
+ if (nd->nd_dextpgsiz > 0) {
+ j = mbuf_ext_pg_len(pgs, 0, pgs->first_pg_off);
+ j -= nd->nd_dextpgsiz;
+ pgs->first_pg_off += j;
+ nd->nd_md->m_len -= j;
+ if (nd->nd_dextpg == pgs->npgs - 1)
+ pgs->last_pg_len -= j;
+ }
+}
+
+/*
+ * Trim the ext_pgs mbuf back to "tlen" bytes in length.
+ */
+void
+nfsm_trimback_extpgs(struct mbuf *m, int len)
+{
+ struct mbuf_ext_pgs *pgs;
+ vm_page_t pg;
+ int i, j, pgno, tlen;
+
+ pgs = m->m_ext.ext_pgs;
+ pgno = 0;
+ tlen = len;
+ while (len > 0 && pgno < pgs->npgs) {
+ if (pgno == 0)
+ i = mbuf_ext_pg_len(pgs, pgno,
+ pgs->first_pg_off);
+ else
+ i = mbuf_ext_pg_len(pgs, pgno, 0);
+ if (len <= i) {
+ /* Free pages past pgno. */
+ for (j = pgno + 1; j < pgs->npgs; j++) {
+ pg = PHYS_TO_VM_PAGE(pgs->pa[j]);
+ vm_page_unwire_noq(pg);
+ vm_page_free(pg);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list