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.
This commit is contained in:
parent
0eed04c802
commit
cb889ce631
@ -680,9 +680,9 @@ int nfsvno_namei(struct nfsrv_descript *, struct nameidata *,
|
||||
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 *, u_long, off_t *, int,
|
||||
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 *,
|
||||
|
@ -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, struct thread *p,
|
||||
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 mbuf **mpendp,
|
||||
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;
|
||||
@ -836,12 +842,77 @@ nfsrv_createiovec(int len, struct mbuf **mpp, struct mbuf **mpendp,
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, struct ucred *cred,
|
||||
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 *cp, struct iovec **ivpp,
|
||||
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, struct ucred *cred,
|
||||
*/
|
||||
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 maxresp,
|
||||
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;
|
||||
|
@ -667,6 +667,7 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
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 int isdgram,
|
||||
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 int isdgram,
|
||||
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 isdgram,
|
||||
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 isdgram,
|
||||
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 isdgram,
|
||||
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 int isdgram,
|
||||
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 int isdgram,
|
||||
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 int isdgram,
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user