Add support for ext_pgs mbufs to nfsm_uiombuflist() and nfsm_split().

This patch uses a slightly different algorithm for nfsm_uiombuflist() for
the non-ext_pgs case, where a variable called "mcp" is maintained, pointing to
the current location that mbuf data can be filled into. This avoids use of
mtod(mp, char *) + mp->m_len to calculate the location, since this does
not work for ext_pgs mbufs and I think it makes the algorithm more readable.
This change should not result in semantic changes for the non-ext_pgs case.
The patch also deletes come unneeded code.

It also adds support for anonymous page ext_pgs mbufs to nfsm_split().

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.
At this time for this case, use of ext_pgs mbufs cannot be enabled, since
ktls_encrypt() replaces the unencrypted data with encrypted data in place.

Until such time as this can be enabled, there should be no semantic change.
Also, note that this code is only used by the NFS client for a mirrored pNFS
server.
This commit is contained in:
Rick Macklem 2020-07-24 23:17:09 +00:00
parent a2e160c5af
commit cfaafa7908
3 changed files with 141 additions and 37 deletions

View file

@ -365,7 +365,7 @@ struct mbuf *nfsm_add_ext_pgs(struct mbuf *, int, int *);
/* nfs_clcomsubs.c */
void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
struct mbuf *nfsm_uiombuflist(struct uio *, int, struct mbuf **, char **);
struct mbuf *nfsm_uiombuflist(struct uio *, int, u_int);
nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int);
u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *);
int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **);

View file

@ -160,26 +160,33 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
* NOTE: can ony handle iovcnt == 1
*/
struct mbuf *
nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
{
char *uiocp;
struct mbuf *mp, *mp2, *firstmp;
int i, left, mlen, rem, xfer;
int extpg, extpgsiz = 0, i, left, mlen, rem, xfer;
int uiosiz, clflg;
char *mcp, *tcp;
KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
clflg = 1;
else
clflg = 0;
if (clflg != 0)
NFSMCLGET(mp, M_WAITOK);
else
NFSMGET(mp);
if (maxext > 0) {
mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
mcp = (char *)(void *)PHYS_TO_DMAP(mp->m_epg_pa[0]);
extpg = 0;
extpgsiz = PAGE_SIZE;
} else {
if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
clflg = 1;
else
clflg = 0;
if (clflg != 0)
NFSMCLGET(mp, M_WAITOK);
else
NFSMGET(mp);
mcp = mtod(mp, char *);
}
mp->m_len = 0;
mcp = mtod(mp, char *);
firstmp = mp2 = mp;
rem = NFSM_RNDUP(siz) - siz;
while (siz > 0) {
@ -189,17 +196,28 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
left = siz;
uiosiz = left;
while (left > 0) {
mlen = M_TRAILINGSPACE(mp);
if (mlen == 0) {
if (clflg)
NFSMCLGET(mp, M_WAITOK);
else
NFSMGET(mp);
mp->m_len = 0;
mcp = mtod(mp, char *);
mp2->m_next = mp;
mp2 = mp;
if (maxext > 0)
mlen = extpgsiz;
else
mlen = M_TRAILINGSPACE(mp);
if (mlen == 0) {
if (maxext > 0) {
mp = nfsm_add_ext_pgs(mp, maxext,
&extpg);
mlen = extpgsiz = PAGE_SIZE;
mcp = (char *)(void *)PHYS_TO_DMAP(
mp->m_epg_pa[extpg]);
} else {
if (clflg)
NFSMCLGET(mp, M_WAITOK);
else
NFSMGET(mp);
mcp = mtod(mp, char *);
mlen = M_TRAILINGSPACE(mp);
mp->m_len = 0;
mp2->m_next = mp;
mp2 = mp;
}
}
xfer = (left > mlen) ? mlen : left;
if (uiop->uio_segflg == UIO_SYSSPACE)
@ -208,6 +226,10 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
copyin(uiocp, mcp, xfer);
mp->m_len += xfer;
mcp += xfer;
if (maxext > 0) {
extpgsiz -= xfer;
mp->m_epg_last_len += xfer;
}
left -= xfer;
uiocp += xfer;
uiop->uio_offset += xfer;
@ -220,16 +242,15 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp)
siz -= uiosiz;
}
if (rem > 0) {
KASSERT(rem <= M_TRAILINGSPACE(mp),
KASSERT((mp->m_flags & M_EXTPG) != 0 ||
rem <= M_TRAILINGSPACE(mp),
("nfsm_uiombuflist: no space for padding"));
for (i = 0; i < rem; i++)
*mcp++ = '\0';
mp->m_len += rem;
if (maxext > 0)
mp->m_epg_last_len += rem;
}
if (cpp != NULL)
*cpp = mtod(mp, caddr_t) + mp->m_len;
if (mbp != NULL)
*mbp = mp;
return (firstmp);
}

View file

@ -5862,7 +5862,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
uiop->uio_iov->iov_base;
iovlen = uiop->uio_iov->iov_len;
m = nfsm_uiombuflist(uiop, len,
NULL, NULL);
0);
}
tdrpc = drpc = malloc(sizeof(*drpc) *
(mirrorcnt - 1), M_TEMP, M_WAITOK |
@ -6545,12 +6545,6 @@ nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
if (len > 0) {
/* Put data in mbuf chain. */
nd->nd_mb->m_next = m;
/* Set nd_mb and nd_bpos to end of data. */
while (m->m_next != NULL)
m = m->m_next;
nd->nd_mb = m;
nd->nd_bpos = mtod(m, char *) + m->m_len;
NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len);
}
nrp = dsp->nfsclds_sockp;
if (nrp == NULL)
@ -8625,8 +8619,97 @@ nfsmout:
static struct mbuf *
nfsm_split(struct mbuf *mp, uint64_t xfer)
{
struct mbuf *m;
struct mbuf *m, *m2;
vm_page_t pg;
int i, j, left, pgno, plen, trim;
char *cp, *cp2;
m = m_split(mp, xfer, M_WAITOK);
return (m);
if ((mp->m_flags & M_EXTPG) == 0) {
m = m_split(mp, xfer, M_WAITOK);
return (m);
}
/* Find the correct mbuf to split at. */
for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next)
xfer -= m->m_len;
if (m == NULL)
return (NULL);
/* If xfer == m->m_len, we can just split the mbuf list. */
if (xfer == m->m_len) {
m2 = m->m_next;
m->m_next = NULL;
return (m2);
}
/* Find the page to split at. */
pgno = 0;
left = xfer;
do {
if (pgno == 0)
plen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
else
plen = m_epg_pagelen(m, pgno, 0);
if (left <= plen)
break;
left -= plen;
pgno++;
} while (pgno < m->m_epg_npgs);
if (pgno == m->m_epg_npgs)
panic("nfsm_split: eroneous ext_pgs mbuf");
m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs);
m2->m_epg_flags |= EPG_FLAG_ANON;
/*
* If left < plen, allocate a new page for the new mbuf
* and copy the data after left in the page to this new
* page.
*/
if (left < plen) {
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);
m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg);
m2->m_epg_npgs = 1;
/* Copy the data after left to the new page. */
trim = plen - left;
cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
if (pgno == 0)
cp += m->m_epg_1st_off;
cp += left;
cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]);
if (pgno == m->m_epg_npgs - 1)
m2->m_epg_last_len = trim;
else {
cp2 += PAGE_SIZE - trim;
m2->m_epg_1st_off = PAGE_SIZE - trim;
m2->m_epg_last_len = m->m_epg_last_len;
}
memcpy(cp2, cp, trim);
m2->m_len = trim;
} else {
m2->m_len = 0;
m2->m_epg_last_len = m->m_epg_last_len;
}
/* Move the pages beyond pgno to the new mbuf. */
for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) {
m2->m_epg_pa[j] = m->m_epg_pa[i];
/* Never moves page 0. */
m2->m_len += m_epg_pagelen(m, i, 0);
}
m2->m_epg_npgs = j;
m->m_epg_npgs = pgno + 1;
m->m_epg_last_len = left;
m->m_len = xfer;
m2->m_next = m->m_next;
m->m_next = NULL;
return (m2);
}