Note: this is not nearly finished, and is nowhere near to compiling. It also contains many inconsistent changes, since I was trying out different approaches. Index: nfs.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs.h,v retrieving revision 1.56 diff -u -r1.56 nfs.h --- nfs.h 2000/10/24 10:13:36 1.56 +++ nfs.h 2001/02/06 17:09:58 @@ -330,14 +330,21 @@ ((s) & PR_CONNREQUIRED) == 0) /* + * A chain of mbufs, with a current position. + */ +struct nfs_chain { + struct mbuf *nc_mhead; /* Head of message mbuf chain */ + struct mbuf *nc_m; /* The mbuf containing current position */ + caddr_t nc_pos; /* Byte position in nc_m */ +}; + +/* * Nfs outstanding request list element */ struct nfsreq { TAILQ_ENTRY(nfsreq) r_chain; + struct nfs_chain r_rep; struct mbuf *r_mreq; - struct mbuf *r_mrep; - struct mbuf *r_md; - caddr_t r_dpos; struct nfsmount *r_nmp; struct vnode *r_vp; u_int32_t r_xid; @@ -489,12 +496,10 @@ LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */ LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */ LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */ - struct mbuf *nd_mrep; /* Request mbuf list */ - struct mbuf *nd_md; /* Current dissect mbuf */ - struct mbuf *nd_mreq; /* Reply mbuf list */ + struct nfs_chain nd_req; /* Request mbuf list */ + struct nfs_chain nd_rep; /* Reply mbuf list */ struct sockaddr *nd_nam; /* and socket addr */ struct sockaddr *nd_nam2; /* return socket addr */ - caddr_t nd_dpos; /* Current dissect pos */ u_int32_t nd_procnum; /* RPC # */ int nd_stable; /* storage type */ int nd_flag; /* nd_flag */ @@ -583,14 +588,14 @@ int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); int nfs_send __P((struct socket *, struct sockaddr *, struct mbuf *, struct nfsreq *)); -int nfs_rephead __P((int, struct nfsrv_descript *, struct nfssvc_sock *, - int, int, u_quad_t *, struct mbuf **, struct mbuf **, - caddr_t *)); +int nfs_rephead(struct nfs_chain *ncp, struct nfsrv_descript *nd, + struct nfssvc_sock *slp, int err, int sizehint, int cache, u_quad_t frev); int nfs_sndlock __P((struct nfsreq *)); void nfs_sndunlock __P((struct nfsreq *)); int nfs_slplock __P((struct nfssvc_sock *, int)); void nfs_slpunlock __P((struct nfssvc_sock *)); -int nfs_disct __P((struct mbuf **, caddr_t *, int, int, caddr_t *)); +int nfs_dissect(struct nfs_chain *ncp, int size, void *startp); +int nfs_build(struct nfs_chain *ncp, int size, void *spacep); int nfs_vinvalbuf __P((struct vnode *, int, struct ucred *, struct proc *, int)); int nfs_readrpc __P((struct vnode *, struct uio *, struct ucred *)); @@ -604,8 +609,7 @@ int nfs_readlinkrpc __P((struct vnode *, struct uio *, struct ucred *)); int nfs_sigintr __P((struct nfsmount *, struct nfsreq *, struct proc *)); int nfs_readdirplusrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfsm_disct __P((struct mbuf **, caddr_t *, int, int, caddr_t *)); -void nfsm_srvfattr __P((struct nfsrv_descript *, struct vattr *, +void nfs_srvfillattr __P((struct nfsrv_descript *, struct vattr *, struct nfs_fattr *)); void nfsm_srvwcc __P((struct nfsrv_descript *, int, struct vattr *, int, struct vattr *, struct mbuf **, char **)); @@ -613,9 +617,8 @@ struct mbuf **, char **)); int netaddr_match __P((int, union nethostaddr *, struct sockaddr *)); int nfs_request __P((struct vnode *, struct mbuf *, int, struct proc *, - struct ucred *, struct mbuf **, struct mbuf **, - caddr_t *)); -int nfs_loadattrcache __P((struct vnode **, struct mbuf **, caddr_t *, + struct ucred *, struct nfs_chain *)); +int nfs_loadattrcache __P((struct vnode **, struct nfs_chain *, struct vattr *, int)); int nfs_namei __P((struct nameidata *, fhandle_t *, int, struct nfssvc_sock *, struct sockaddr *, struct mbuf **, @@ -630,7 +633,7 @@ int nfs_savenickauth __P((struct nfsmount *, struct ucred *, int, NFSKERBKEY_T, struct mbuf **, char **, struct mbuf *)); -int nfs_adv __P((struct mbuf **, caddr_t *, int, int)); +int nfs_adv(struct nfs_chain *ncp, int size); void nfs_nhinit __P((void)); void nfs_timer __P((void*)); u_long nfs_hash __P((nfsfh_t *, int)); @@ -647,6 +650,13 @@ int nfsm_strtmbuf __P((struct mbuf **, char **, const char *, long)); int nfs_bioread __P((struct vnode *, struct uio *, int, struct ucred *)); int nfsm_uiotombuf __P((struct uio *, struct mbuf **, int, caddr_t *)); +int nfs_fhtom(struct nfs_chain *ncp, struct vnode *vp, int isv3); + +int nfs_srvfhtom(struct nfs_chain *ncp, fhandle_t *fhp, int isv3); +int nfs_srvmtofh(struct nfs_chain *ncp, fhandle_t *fhp, int isv3); +int nfs_srvsattr(struct nfs_chain *ncp, struct vattr *vap); + + void nfsrv_init __P((int)); void nfs_clearcommit __P((struct mount *)); int nfsrv_errmap __P((struct nfsrv_descript *, int)); Index: nfs_nqlease.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_nqlease.c,v retrieving revision 1.55 diff -u -r1.55 nfs_nqlease.c --- nfs_nqlease.c 2000/12/21 21:44:24 1.55 +++ nfs_nqlease.c 2001/01/29 01:23:37 @@ -100,6 +100,8 @@ struct nfssvc_sock *slp, struct sockaddr *nam, struct ucred *cred)); +static int nqsrv_host_eviction(struct vnode *vp, struct nqhost *lph, + struct nfssvc_sock *slp, struct sockaddr *nam, struct ucred *cred); static void nqsrv_unlocklease __P((struct nqlease *lp)); static void nqsrv_waitfor_expiry __P((struct nqlease *lp)); #endif @@ -491,102 +493,124 @@ struct sockaddr *nam; struct ucred *cred; { - register struct nqhost *lph = &lp->lc_host; - register int siz; - struct nqm *lphnext = lp->lc_morehosts; - struct mbuf *m, *mreq, *mb, *mb2, *mheadend; + struct nqhost *lph = &lp->lc_host; + struct nqm *lpm; + int i; + + if ((lph->lph_flag & LC_VALID) == 0) + return; + + nqsrv_host_eviction(vp, lph, slp, nam, cred); + + for (lpm = lp->lc_morehosts; lpm != NULL; lpm = lpm->lpm_next) { + lph = lpm->lpm_hosts; + for (i = 0; i < LC_MOREHOSTSIZ; i++) { + if ((lph->lph_flag & LC_VALID) == 0) + break; + nqsrv_host_eviction(vp, lph, slp, nam, cred); + lph++; + } + } +} + +/* + * Send out eviction notice messages to a single host. + */ +static int +nqsrv_host_eviction(vp, lph, slp, nam, cred) + struct vnode *vp; + struct nqhost *lph; + struct nfssvc_sock *slp; + struct sockaddr *nam; + struct ucred *cred; +{ + struct nfs_chain reqc; + struct mbuf *m; + int siz, error = 0; struct sockaddr *nam2; struct sockaddr_in *saddr; nfsfh_t nfh; fhandle_t *fhp; - caddr_t bpos, cp; - u_int32_t xid, *tl; - int len = 1, ok = 1, i = 0; + u_int32_t xid; + struct socket *so; + int sotype; + int *solockp = NULL; - while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(slp, nam, lph)) { - lph->lph_flag |= LC_VACATED; - } else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { - struct socket *so; - int sotype; - int *solockp = NULL; - - so = lph->lph_slp->ns_so; - if (lph->lph_flag & LC_UDP) { - MALLOC(nam2, struct sockaddr *, - sizeof *nam2, M_SONAME, M_WAITOK); - saddr = (struct sockaddr_in *)nam2; - saddr->sin_len = sizeof *saddr; - saddr->sin_family = AF_INET; - saddr->sin_addr.s_addr = lph->lph_inetaddr; - saddr->sin_port = lph->lph_port; - } else if (lph->lph_slp->ns_flag & SLP_VALID) { - nam2 = (struct sockaddr *)0; - } else { - goto nextone; - } - sotype = so->so_type; - if (so->so_proto->pr_flags & PR_CONNREQUIRED) - solockp = &lph->lph_slp->ns_solock; - nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED, - NFSX_V3FH + NFSX_UNSIGNED); - fhp = &nfh.fh_generic; - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - VFS_VPTOFH(vp, &fhp->fh_fid); - nfsm_srvfhtom(fhp, 1); - m = mreq; - siz = 0; - while (m) { - siz += m->m_len; - m = m->m_next; - } - if (siz <= 0 || siz > NFS_MAXPACKET) { - printf("mbuf siz=%d\n",siz); - panic("Bad nfs svc reply"); - } - m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS), - NQNFSPROC_EVICTED, - RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, - 0, (char *)NULL, mreq, siz, &mheadend, &xid); - /* - * For stream protocols, prepend a Sun RPC - * Record Mark. - */ - if (sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | - (m->m_pkthdr.len - NFSX_UNSIGNED)); - } - /* - * nfs_sndlock if PR_CONNREQUIRED XXX - */ + if (nqsrv_cmpnam(slp, nam, lph)) { + lph->lph_flag |= LC_VACATED; + return (0); + } - if ((lph->lph_flag & LC_UDP) == 0 && - ((lph->lph_slp->ns_flag & SLP_VALID) == 0 || - nfs_slplock(lph->lph_slp, 0) == 0)) { - m_freem(m); - } else { - (void) nfs_send(so, nam2, m, - (struct nfsreq *)0); - if (solockp) - nfs_slpunlock(lph->lph_slp); - } - if (lph->lph_flag & LC_UDP) - FREE(nam2, M_SONAME); - } -nextone: - if (++i == len) { - if (lphnext) { - i = 0; - len = LC_MOREHOSTSIZ; - lph = lphnext->lpm_hosts; - lphnext = lphnext->lpm_next; - } else - ok = 0; - } else - lph++; + if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) != 0) + return (0); + + NFSCHAIN_INIT(&reqc); + so = lph->lph_slp->ns_so; + nam2 = NULL; + if (lph->lph_flag & LC_UDP) { + MALLOC(nam2, struct sockaddr *, sizeof *nam2, M_SONAME, + M_WAITOK); + saddr = (struct sockaddr_in *)nam2; + saddr->sin_len = sizeof *saddr; + saddr->sin_family = AF_INET; + saddr->sin_addr.s_addr = lph->lph_inetaddr; + saddr->sin_port = lph->lph_port; + } else if (lph->lph_slp->ns_flag & SLP_VALID) { + nam2 = NULL; + } else + return (0); + + sotype = so->so_type; + if (so->so_proto->pr_flags & PR_CONNREQUIRED) + solockp = &lph->lph_slp->ns_solock; + nfsm_reqhead(&reqc, NULL, NQNFSPROC_EVICTED, + NFSX_V3FH + NFSX_UNSIGNED, errout); + fhp = &nfh.fh_generic; + bzero(fhp, sizeof(nfh)); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + VFS_VPTOFH(vp, &fhp->fh_fid); + nfs_srvfhtom(&reqc, fhp, 1); + m = reqc.nc_mhead; + siz = 0; + for (m = reqc.nc_mhead; m != NULL; m = m->m_next) + siz += m->m_len; + if (siz <= 0 || siz > NFS_MAXPACKET) { + printf("mbuf siz=%d\n",siz); + panic("Bad nfs svc reply"); + } + m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS), + NQNFSPROC_EVICTED, RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, NULL, 0, NULL, + reqc.nc_mhead, siz, NULL, &xid); + reqc.nc_mhead = NULL; + /* + * For stream protocols, prepend a Sun RPC Record Mark. + */ + if (sotype == SOCK_STREAM) { + M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); + *mtod(m, u_int32_t *) = htonl(0x80000000 | + (m->m_pkthdr.len - NFSX_UNSIGNED)); } + /* + * nfs_sndlock if PR_CONNREQUIRED XXX + */ + + if ((lph->lph_flag & LC_UDP) == 0 && + ((lph->lph_slp->ns_flag & SLP_VALID) == 0 || + nfs_slplock(lph->lph_slp, 0) == 0)) { + m_freem(m); + } else { + nfs_send(so, nam2, m, NULL); + if (solockp) + nfs_slpunlock(lph->lph_slp); + } + +errout: + + NFSCHAIN_FREE(&reqc); + if (nam2 != NULL) + FREE(nam2, M_SONAME); + return (error); + } /* @@ -719,59 +743,72 @@ * do the real work. */ int -nqnfsrv_getlease(nfsd, slp, procp, mrq) - struct nfsrv_descript *nfsd; +nqnfsrv_getlease(nd, slp, procp) + struct nfsrv_descript *nd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; + struct nfs_chain *req, *rep; + struct sockaddr *nam = nd->nd_nam; + struct ucred *cred = &nd->nd_cr; register struct nfs_fattr *fp; struct vattr va; - register struct vattr *vap = &va; - struct vnode *vp; + struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; register u_int32_t *tl; - register int32_t t1; u_quad_t frev; - caddr_t bpos; int error = 0; - char *cp2; - struct mbuf *mb, *mb2, *mreq; int flags, rdonly, cache; + req = &nd->nd_req; + rep = &nd->nd_rep; fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + + /* Break down the request */ + nfsm_srvmtofh(req, fhp, 1 /*v3*/, errout); + nfsm_dissect(req, tl, u_int32_t *, 2 * NFSX_UNSIGNED, errout); flags = fxdr_unsigned(int, *tl++); - nfsd->nd_duration = fxdr_unsigned(int, *tl); + nd->nd_duration = fxdr_unsigned(int, *tl); + NFSCHAIN_FREE(req); + + /* Vnode ops. */ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(0); - goto nfsmout; - } - if (rdonly && flags == ND_WRITE) { + (nd->nd_flag & ND_KERBAUTH), TRUE); + if (!error && rdonly && flags == ND_WRITE) error = EROFS; - vput(vp); - nfsm_reply(0); - } - (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp, - nam, &cache, &frev, cred); - error = VOP_GETATTR(vp, vap, cred, procp); + if (error) + goto errrep; + nqsrv_getlease(vp, &nd->nd_duration, flags, slp, procp, nam, + &cache, &frev, cred); + error = VOP_GETATTR(vp, &va, cred, procp); + if (error) + goto errrep; vput(vp); - nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + vp = NULL; + + /* Construct the reply. */ + nfsm_reply(rep, nd, slp, error, NFSX_V3FATTR + 4 * NFSX_UNSIGNED, + errout); + nfsm_build(rep, tl, u_int32_t *, 4 * NFSX_UNSIGNED, errout); *tl++ = txdr_unsigned(cache); - *tl++ = txdr_unsigned(nfsd->nd_duration); + *tl++ = txdr_unsigned(nd->nd_duration); txdr_hyper(frev, tl); - nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR); - nfsm_srvfillattr(vap, fp); - nfsm_srvdone; + nfsm_build(rep, fp, struct nfs_fattr *, NFSX_V3FATTR, errout); + nfs_srvfillattr(nd, &va, fp); + + return (0); + +errrep: + if (vp) { + vput(vp); + vp = NULL; + } + nfsm_replyerror(rep, nd, slp, error, errout); + error = 0; +errout: + KASSERT(vp == NULL, "nqnfsrv_getlease: vp"); + return (error); } /* @@ -779,44 +816,40 @@ * client. Find the entry and expire it. */ int -nqnfsrv_vacated(nfsd, slp, procp, mrq) +nqnfsrv_vacated(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain *req, *rep; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; register struct nqlease *lp; register struct nqhost *lph; - struct nqlease *tlp = (struct nqlease *)0; + struct nqlease *tlp = NULL; nfsfh_t nfh; fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; struct nqm *lphnext; - struct mbuf *mreq, *mb; - int error = 0, i, len, ok, gotit = 0, cache = 0; - char *cp2, *bpos; - u_quad_t frev; + int error = 0, i, len, ok, gotit = 0; + req = &nfsd->nd_req; + rep = &nfsd->nd_rep; fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - m_freem(mrep); + + /* Break down the request. */ + nfsm_srvmtofh(req, fhp, 1, errout); + /* * Find the lease by searching the hash list. */ - for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0; - lp = lp->lc_hash.le_next) + LIST_FOREACH(lp, NQFHHASH(fhp->fh_fid.fid_data), lc_hash) { if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] && fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] && - !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, - MAXFIDSZ)) { + !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, MAXFIDSZ)) { /* Found it */ tlp = lp; break; } + } if (tlp != 0) { lp = tlp; len = 1; @@ -845,10 +878,10 @@ lp->lc_flag &= ~LC_EXPIREDWANTED; wakeup((caddr_t)&lp->lc_flag); } -nfsmout: - return (EPERM); } return (EPERM); +errout: + return (error); } #endif /* NFS_NOSERVER */ @@ -858,43 +891,43 @@ */ int nqnfs_getlease(vp, rwflag, cred, p) - register struct vnode *vp; + struct vnode *vp; int rwflag; struct ucred *cred; struct proc *p; { - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - register struct nfsnode *np; + u_int32_t *tl; + struct nfsnode *np; + struct nfs_chain reqc, repc; struct nfsmount *nmp = VFSTONFS(vp->v_mount); - caddr_t bpos, dpos, cp2; time_t reqtime; int error = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int cachable; u_quad_t frev; nfsstats.rpccnt[NQNFSPROC_GETLEASE]++; - mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED, - &bpos); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED, + errout); + nfsm_fhtom(&reqc, vp, 1, errout); + nfsm_build(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, errout); *tl++ = txdr_unsigned(rwflag); *tl = txdr_unsigned(nmp->nm_leaseterm); reqtime = time_second; - nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred); + nfsm_request(&reqc, &repc, vp, NQNFSPROC_GETLEASE, p, cred, errout); np = VTONFS(vp); - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, 4 * NFSX_UNSIGNED, errout); cachable = fxdr_unsigned(int, *tl++); reqtime += fxdr_unsigned(int, *tl++); if (reqtime > time_second) { frev = fxdr_hyper(tl); nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev); - nfsm_loadattr(vp, (struct vattr *)0); + nfsm_loadattr(&repc, vp, NULL, errout); } else error = NQNFS_EXPIRED; - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } @@ -907,30 +940,23 @@ register struct vnode *vp; struct ucred *cred; { - register caddr_t cp; + struct nfs_chain reqc; register int i; - register u_int32_t *tl; - register int32_t t2; - caddr_t bpos; u_int32_t xid; int error = 0; - struct mbuf *m, *mreq, *mb, *mb2, *mheadend; + struct mbuf *m; struct nfsmount *nmp; struct nfsreq myrep; nmp = VFSTONFS(vp->v_mount); nfsstats.rpccnt[NQNFSPROC_VACATED]++; - nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - m = mreq; + nfsm_reqhead(&reqc, vp, NQNFSPROC_VACATED, NFSX_FH(1), errout); + nfsm_fhtom(&reqc, vp, 1, errout); i = 0; - while (m) { + for (m = reqc.nc_mhead; m != NULL; m = m->m_next) i += m->m_len; - m = m->m_next; - } - m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED, - RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, - 0, (char *)NULL, mreq, i, &mheadend, &xid); + m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED, RPCAUTH_UNIX, + 5 * NFSX_UNSIGNED, NULL, 0, NULL, reqc.nc_mhead, i, NULL, &xid); if (nmp->nm_sotype == SOCK_STREAM) { M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); *mtod(m, u_int32_t *) = htonl(0x80000000 | (m->m_pkthdr.len - @@ -939,11 +965,14 @@ myrep.r_flags = 0; myrep.r_nmp = nmp; if (nmp->nm_soflags & PR_CONNREQUIRED) - (void) nfs_sndlock(&myrep); - (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); + nfs_sndlock(&myrep); + nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); if (nmp->nm_soflags & PR_CONNREQUIRED) nfs_sndunlock(&myrep); -nfsmout: + goto done; +errout: + NFSCHAIN_FREE(&reqc); +done: return (error); } @@ -951,47 +980,31 @@ * Called for client side callbacks */ int -nqnfs_callback(nmp, mrep, md, dpos) +nqnfs_callback(nmp, reqc) struct nfsmount *nmp; - struct mbuf *mrep, *md; - caddr_t dpos; + struct nfs_chain *reqc; { - register struct vnode *vp; - register u_int32_t *tl; - register int32_t t1; + struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; struct nfsnode *np; struct nfsd tnfsd; - struct nfssvc_sock *slp; struct nfsrv_descript ndesc; - register struct nfsrv_descript *nfsd = &ndesc; - struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq; - int error = 0, cache = 0; - char *cp2, *bpos; - u_quad_t frev; + int error = 0; -#ifndef nolint - slp = NULL; -#endif - nfsd->nd_mrep = mrep; - nfsd->nd_md = md; - nfsd->nd_dpos = dpos; - error = nfs_getreq(nfsd, &tnfsd, FALSE); + ndesc.nd_req = *reqc; + error = nfs_getreq(&ndesc, &tnfsd, FALSE); if (error) - return (error); - md = nfsd->nd_md; - dpos = nfsd->nd_dpos; - if (nfsd->nd_procnum != NQNFSPROC_EVICTED) { - m_freem(mrep); - return (EPERM); + goto errout; + if (ndesc.nd_procnum != NQNFSPROC_EVICTED) { + error = EPERM; + goto errout; } fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - m_freem(mrep); + nfsm_srvmtofh(&ndesc.nd_req, fhp, 1, errout); error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np); if (error) - return (error); + goto errout; vp = NFSTOV(np); if (TAILQ_NEXT(np, n_timer) != 0) { np->n_expiry = 0; @@ -1002,7 +1015,9 @@ } } vput(vp); - nfsm_srvdone; + return (0); +errout: + return (error); } @@ -1073,7 +1088,7 @@ nmp->nm_so->so_rcv.sb_cc > 0) { myrep.r_flags = R_GETONEREP; myrep.r_nmp = nmp; - myrep.r_mrep = (struct mbuf *)0; + NFSCHAIN_INIT(&myrep.r_rep); myrep.r_procp = (struct proc *)0; (void) nfs_reply(&myrep); } Index: nfs_serv.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_serv.c,v retrieving revision 1.98 diff -u -r1.98 nfs_serv.c --- nfs_serv.c 2000/12/21 21:44:24 1.98 +++ nfs_serv.c 2001/02/05 01:22:02 @@ -48,6 +48,23 @@ * - do not mix the phases, since the nfsm_?? macros can return failures * on a bad rpc or similar and do not do any vrele() or vput()'s * + + Operations generally terminate in one of the following ways + + success + return 0, nd_repstat is 0, reply has been + generated and stored in nd_rep. + + operation was performed, but result was an error + return 0, nd_repstat is error code, error reply + has been gnerated and stored in nd_rep. + + request format/content error, requires error reply + return EBADRPC, nd_repstat not changed + + request could not be completed, no reply to be generated. + return error code + * - the nfsm_reply() macro generates an nfs rpc reply with the nfs * error number iff error != 0 whereas * returning an error from the server function implies a fatal error @@ -143,6 +160,9 @@ static int nfs_commit_miss; SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0, ""); SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, ""); +static int nfs_server_readahead = 1; +SYSCTL_INT(_vfs_nfs, OID_AUTO, server_readahead, CTLFLAG_RW, + &nfs_server_readahead, 0, "enable NFS server readahead heuristic"); static int nfsrv_access __P((struct vnode *,int,struct ucred *,int, struct proc *, int)); @@ -168,44 +188,35 @@ * nfs v3 access service */ int -nfsrv3_access(nfsd, slp, procp, mrq) +nfsrv3_access(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, getret; - char *cp2; - struct mbuf *mb, *mreq, *mb2; - struct vattr vattr, *vap = &vattr; + u_int32_t *tl; + int error = 0, rdonly, getret = 1; + struct vattr vattr; u_long testmode, nfsmode; - u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif + NFSCHAIN_INIT(&repc); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + + /* Break down request. */ + nfsm_srvmtofh(&reqc, fhp, /*v3*/ 1, errout); + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); + + /* Vnode ops. */ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; nfsmode = fxdr_unsigned(u_int32_t, *tl); if ((nfsmode & NFSV3ACCESS_READ) && nfsrv_access(vp, VREAD, cred, rdonly, procp, 0)) @@ -225,73 +236,96 @@ if ((nfsmode & testmode) && nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0)) nfsmode &= ~testmode; - getret = VOP_GETATTR(vp, vap, cred, procp); + getret = VOP_GETATTR(vp, &vattr, cred, procp); vput(vp); vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, vap); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + + /* Construct the reply. */ + nfsm_reply(&repc, nfsd, slp, error, NFSX_POSTOPATTR(1) + NFSX_UNSIGNED, + errout); + nfs_srvpostop_attr(nd, getret, &vattr, &repc); + nfsm_build(&repc, tl, u_int32_t *, NFSX_UNSIGNED, errout); *tl = txdr_unsigned(nfsmode); -nfsmout: - if (vp) + + nfsd->nd_rep = repc; + return (0); + +ereply: + if (vp) { vput(vp); - return(error); + vp = NULL; + } + nfsm_replyerror(&repc, nfsd, slp, error, errout); + nfs_srvpostop_attr(nfsd, 1, NULL, &repc); + error = 0; +errout: + nfsd->nd_rep = repc; + KASSERT(vp == NULL, ("vref leak")); + return (error); } /* * nfs getattr service */ int -nfsrv_getattr(nfsd, slp, procp, mrq) +nfsrv_getattr(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; - register struct nfs_fattr *fp; + struct nfs_fattr *fp; struct vattr va; - register struct vattr *vap = &va; struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; + u_int32_t *tl; + int32_t t1; int error = 0, rdonly, cache; char *cp2; struct mbuf *mb, *mb2, *mreq; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); + + /* Break down request. */ fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); + + /* Vnode ops. */ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(0); - error = 0; - goto nfsmout; - } + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); + if (error) + goto ereply; nqsrv_getl(vp, ND_READ); - error = VOP_GETATTR(vp, vap, cred, procp); + if ((error = VOP_GETATTR(vp, &va, cred, procp)) != 0) + goto ereply; vput(vp); vp = NULL; - nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); - nfsm_srvfillattr(vap, fp); - /* fall through */ -nfsmout: - if (vp) + /* Construct the reply. */ + nfsm_reply(&repc, nfsd, slp, error, + NFSX_FATTR(nfsd->nd_flag & ND_NFSV3), errout); + nfsm_build(&repc, fp, struct nfs_fattr *, + NFSX_FATTR(nfsd->nd_flag & ND_NFSV3), errout); + nfs_srvfillattr(&va, fp); + + nfsd->nd_rep = repc; + return (0); + +ereply: + if (vp) { vput(vp); + vp = NULL; + } + nfsm_replyerror(&repc, nfsd, slp, error, errout); + error = 0; +errout: + nfsd->nd_rep = repc; + KASSERT(vp == NULL, ("vref leak")); return(error); } @@ -305,49 +339,41 @@ struct proc *procp; struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr va, preat; - register struct vattr *vap = &va; - register struct nfsv2_sattr *sp; - register struct nfs_fattr *fp; + struct nfsv2_sattr *sp; + struct nfs_fattr *fp; struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; register u_int32_t *tl; - register int32_t t1; caddr_t bpos; int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - u_quad_t frev; struct timespec guard; struct mount *mp = NULL; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); + + /* Break down request. */ fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) - return (ESTALE); - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) - return (error); - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - VATTR_NULL(vap); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); + VATTR_NULL(&va); if (v3) { - nfsm_srvsattr(vap); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_srvsattr(&reqc, &va, errout); + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); gcheck = fxdr_unsigned(int, *tl); if (gcheck) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); fxdr_nfsv3time(tl, &guard); } } else { - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_dissect(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); /* * Nah nah nah nah na nah * There is a bug in the Sun client that puts 0xffff in the mode @@ -356,99 +382,91 @@ * --> check the low order 2 bytes for 0xffff */ if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) - vap->va_mode = nfstov_mode(sp->sa_mode); + va.va_mode = nfstov_mode(sp->sa_mode); if (sp->sa_uid != nfs_xdrneg1) - vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); + va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid); if (sp->sa_gid != nfs_xdrneg1) - vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); + va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid); if (sp->sa_size != nfs_xdrneg1) - vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size); + va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size); if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { -#ifdef notyet - fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime); -#else - vap->va_atime.tv_sec = + va.va_atime.tv_sec = fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec); - vap->va_atime.tv_nsec = 0; -#endif + va.va_atime.tv_nsec = 0; } if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) - fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); - + fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime); } - /* - * Now that we have all the fields, lets do it. - */ - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; - } + /* Vnode ops. */ + if ((error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + (nfsd->nd_flag & ND_KERBAUTH), TRUE)) != 0) + goto ereply; - /* - * vp now an active resource, pay careful attention to cleanup - */ - + vn_start_write(vp, &mp, V_WAIT); nqsrv_getl(vp, ND_WRITE); if (v3) { error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp); if (!error && gcheck && - (preat.va_ctime.tv_sec != guard.tv_sec || - preat.va_ctime.tv_nsec != guard.tv_nsec)) + (preat.va_ctime.tv_sec != guard.tv_sec || + preat.va_ctime.tv_nsec != guard.tv_nsec)) error = NFSERR_NOT_SYNC; - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; } /* - * If the size is being changed write acces is required, otherwise + * If the size is being changed write access is required, otherwise * just check for a read only file system. */ - if (vap->va_size == ((u_quad_t)((quad_t) -1))) { + if (va.va_size == ((u_quad_t)((quad_t) -1))) { if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { error = EROFS; - goto out; + goto ereply; } } else { if (vp->v_type == VDIR) { error = EISDIR; - goto out; + goto ereply; } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0)) != 0) - goto out; + goto ereply; } - error = VOP_SETATTR(vp, vap, cred, procp); - postat_ret = VOP_GETATTR(vp, vap, cred, procp); - if (!error) - error = postat_ret; -out: + error = VOP_SETATTR(vp, &va, cred, procp); + if (v3) + postat_ret = VOP_GETATTR(vp, &va, cred, procp); + if (error != 0) + goto ereply; + vput(vp); vp = NULL; - nfsm_reply(NFSX_WCCORFATTR(v3)); + vn_finished_write(mp); + + /* Construct the reply. */ + nfsm_reply(&repc, nfsd, slp, error, NFSX_WCCORFATTR(v3), errout); if (v3) { - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; + nfs_srvwcc(preat_ret, &preat, postat_ret, &va, &repc); } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); + nfsm_build(&repc, fp, struct nfs_fattr *, NFSX_V2FATTR, + eerrout); + nfs_srvfillattr(&va, fp); } - /* fall through */ + nfsd->nd_rep = repc; + return (0); -nfsmout: - if (vp) +ereply: + if (vp) { vput(vp); - vn_finished_write(mp); + vn_finished_write(mp); + vp = NULL; + } + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3) + nfs_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, &repc); + error = 0; +errout: + nfsd->nd_rep = repc; + KASSERT(vp == NULL, ("vref leak")); return(error); } @@ -456,64 +474,50 @@ * nfs lookup rpc */ int -nfsrv_lookup(nfsd, slp, procp, mrq) +nfsrv_lookup(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct nfs_fattr *fp; struct nameidata nd, ind, *ndp = &nd; struct vnode *vp, *dirp = NULL; nfsfh_t nfh; fhandle_t *fhp; - register caddr_t cp; register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; int error = 0, cache, len, dirattr_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vattr va, dirattr, *vap = &va; + struct vattr va, dirattr; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); ndclear(&nd); + /* Break down request. */ fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_srvnamesiz(len); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); + nfsm_srvnamesiz(&reqc, len, errout, ereply); pubflag = nfs_ispublicfh(fhp); + /* Vnode ops. XXX phase mixing occurs in nfs_namei. */ nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag); - - /* - * namei failure, only dirp to cleanup. Clear out garbarge from - * structure in case macros jump to nfsmout. - */ + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), pubflag); if (error) { - if (dirp) { - if (v3) - dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, - procp); - vrele(dirp); - dirp = NULL; - } - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; + /* namei failure, let the exit code do the cleanup */ + if (error == EBADRPC || error == ENOBUFS) + goto errout; + if (dirp && v3) + dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, procp); + goto ereply; } /* @@ -579,8 +583,7 @@ if (dirp) { if (v3) - dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, - procp); + dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, procp); vrele(dirp); dirp = NULL; } @@ -591,12 +594,8 @@ * */ - if (error) { - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; nqsrv_getl(ndp->ni_startdir, ND_READ); @@ -610,34 +609,41 @@ NDFREE(&nd, NDF_ONLY_PNBUF); /* - * Get underlying attribute, then release remaining resources ( for - * the same potential blocking reason ) and reply. + * Get underlying attribute, then release remaining resources (for + * the same potential blocking reason) and reply. */ vp = ndp->ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(vp, vap, cred, procp); - + if ((error = VFS_VPTOFH(vp, &fhp->fh_fid)) != 0) + goto ereply; + if ((error = VOP_GETATTR(vp, &va, cred, procp)) != 0) + goto ereply; + vput(vp); - ndp->ni_vp = NULL; - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); - if (error) { - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; - } - nfsm_srvfhtom(fhp, v3); + vp = NULL; + + /* Construct the reply. */ + nfsm_reply(&repc, nfsd, slp, error, NFSX_SRVFH(v3) + + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3), errout); + nfs_srvfhtom(&repc, fhp, v3, errout); if (v3) { - nfsm_srvpostop_attr(0, vap); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); + nfs_srvpostop_attr(nfsd, 0, &va, &repc); + nfs_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &repc); } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); + nfsm_build(&repc, fp, struct nfs_fattr *, NFSX_V2FATTR, + errout); + nfs_srvfillattr(&va, fp); } + nd->nd_rep = repc; + return (0); -nfsmout: +ereply: + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3 && NFS_DOERRSTATUSV3(error)) + nfs_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &repc); + error = 0; +errout: if (dirp) vrele(dirp); NDFREE(&nd, NDF_ONLY_PNBUF); @@ -645,6 +651,7 @@ vrele(ndp->ni_startdir); if (ndp->ni_vp) vput(ndp->ni_vp); + nd->nd_rep = repc; return (error); } @@ -652,112 +659,89 @@ * nfs readlink service */ int -nfsrv_readlink(nfsd, slp, procp, mrq) +nfsrv_readlink(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nd->nd_req, repc, pathc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; - register struct iovec *ivp = iv; - register struct mbuf *mp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, i, tlen, len, getret; + struct iovec *ivp = iv; + u_int32_t *tl; + int error = 0, rdonly, cache, i, tlen, len, getret = 0; int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; struct vnode *vp = NULL; struct vattr attr; nfsfh_t nfh; fhandle_t *fhp; - struct uio io, *uiop = &io; + struct uio io; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - mp2 = (struct mbuf *)0; -#endif - mp3 = NULL; + NFSCHAIN_INIT(&repc); + NFSCHAIN_INIT(&pathc); + + /* Break down request. */ fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - len = 0; - i = 0; - while (len < NFS_MAXPATHLEN) { - MGET(mp, M_TRYWAIT, MT_DATA); - MCLGET(mp, M_TRYWAIT); - mp->m_len = NFSMSIZ(mp); - if (len == 0) - mp3 = mp2 = mp; - else { - mp2->m_next = mp; - mp2 = mp; - } - if ((len+mp->m_len) > NFS_MAXPATHLEN) { - mp->m_len = NFS_MAXPATHLEN-len; - len = NFS_MAXPATHLEN; - } else - len += mp->m_len; - ivp->iov_base = mtod(mp, caddr_t); - ivp->iov_len = mp->m_len; - i++; - ivp++; - } - uiop->uio_iov = iv; - uiop->uio_iovcnt = i; - uiop->uio_offset = 0; - uiop->uio_resid = len; - uiop->uio_rw = UIO_READ; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_procp = (struct proc *)0; - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } - if (vp->v_type != VLNK) { - if (v3) - error = EINVAL; - else - error = ENXIO; - goto out; - } - nqsrv_getl(vp, ND_READ); - error = VOP_READLINK(vp, uiop, cred); -out: + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); + + /* Allocate mbuf space for link contents. */ + io.uio_iov = iv; + io.uio_iovcnt = sizeof(iv) / sizeof(iv[0]); + if ((error = nfs_getmuio(&pathc, &io, NFS_MAXPATHLEN, NULL)) != 0) + goto errout; + io.uio_offset = 0; + io.uio_procp = NULL; + + /* Vnode ops. */ + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + (nfsd->nd_flag & ND_KERBAUTH), TRUE); + if (error) + goto ereply; + if (vp->v_type == VLNK) { + nqsrv_getl(vp, ND_READ); + error = VOP_READLINK(vp, uiop, cred); + } else + error = v3 ? EINVAL : ENXIO; getret = VOP_GETATTR(vp, &attr, cred, procp); + if (error) + goto ereply; vput(vp); vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); - if (v3) { - nfsm_srvpostop_attr(getret, &attr); - if (error) { - error = 0; - goto nfsmout; - } - } + + /* Construct the reply. */ + nfsm_reply(&repc, nfsd, slp, error, + NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED, errout); + if (v3) + nfs_srvpostop_attr(nfsd, getret, &attr, &repc); + if (uiop->uio_resid > 0) { len -= uiop->uio_resid; tlen = nfsm_rndup(len); - nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); + nfs_adj(pathc.nc_mhead, NFS_MAXPATHLEN - tlen, tlen - len); } - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, NFSX_UNSIGNED, errout); *tl = txdr_unsigned(len); - mb->m_next = mp3; - mp3 = NULL; -nfsmout: - if (mp3) - m_freem(mp3); - if (vp) + NFSCHAIN_APPENDCHAIN(&repc, &pathc); + + nd->nd_rep = repc; + return (0); + +ereply: + if (vp) { vput(vp); + vp = NULL; + } + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3) + nfs_srvpostop_attr(nfsd, getret, &attr, &repc); + error = 0; +errout: + NFSCHAIN_FREE(&pathc); + nd->nd_rep = repc; + KASSERT(vp == NULL, ("vref leak")); return(error); } @@ -765,114 +749,85 @@ * nfs read service */ int -nfsrv_read(nfsd, slp, procp, mrq) +nfsrv_read(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; - register struct iovec *iv; - struct iovec *iv2; + struct iovec *iovp; register struct mbuf *m; register struct nfs_fattr *fp; register u_int32_t *tl; - register int32_t t1; register int i; - caddr_t bpos; - int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret; + int error = 0, rdonly, cache, cnt, len, siz, tlen, getret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct mbuf *m2; struct vnode *vp = NULL; nfsfh_t nfh; fhandle_t *fhp; - struct uio io, *uiop = &io; - struct vattr va, *vap = &va; - struct nfsheur *nh; + struct uio io; + struct vattr va; + struct nfsheur *nh = NULL; off_t off; int ioflag = 0; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); + + /* Break down request. */ fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if (v3) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, errout); off = fxdr_hyper(tl); } else { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); off = (off_t)fxdr_unsigned(u_int32_t, *tl); } - nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); - - /* - * Reference vp. If an error occurs, vp will be invalid, but we - * have to NULL it just in case. The macros might goto nfsmout - * as well. - */ + nfsm_srvstrsiz(&reqc, reqlen, NFS_SRVMAXDATA(nfsd), errout); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - vp = NULL; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } + /* Vnode ops. XXX phase mixing. */ + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + (nfsd->nd_flag & ND_KERBAUTH), TRUE); + if (error) + goto ereply; if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; + error = v3 ? EINVAL : (vp->v_type == VDIR) ? EISDIR : EACCES; + goto ereply; } - if (!error) { - nqsrv_getl(vp, ND_READ); - if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0) + nqsrv_getl(vp, ND_READ); + if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0) error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1); - } - getret = VOP_GETATTR(vp, vap, cred, procp); + getret = VOP_GETATTR(vp, &va, cred, procp); if (!error) error = getret; - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, vap); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; /* * Calculate byte count to read */ - - if (off >= vap->va_size) + if (off >= va.va_size) cnt = 0; - else if ((off + reqlen) > vap->va_size) - cnt = vap->va_size - off; + else if ((off + reqlen) > va.va_size) + cnt = va.va_size - off; else cnt = reqlen; - /* - * Calculate seqcount for heuristic - */ - - { + /* Use heuristic to calculate seqcount (if enabled). */ + if (nfs_server_readahead) { int hi; int try = 4; /* * Locate best candidate */ - - hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) & (NUM_HEURISTIC - 1); + hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) & + (NUM_HEURISTIC - 1); nh = &nfsheur[hi]; while (try--) { @@ -900,7 +855,6 @@ /* * Calculate heuristic */ - if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) { if (++nh->nh_seqcount > 127) nh->nh_seqcount = 127; @@ -915,89 +869,50 @@ ioflag |= nh->nh_seqcount << 16; } - nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); + /* Construct the reply. XXX phase mixing. */ + nfsm_reply(&repc, nfsd, slp, error, NFSX_POSTOPORFATTR(v3) + + 3 * NFSX_UNSIGNED + nfsm_rndup(cnt), errout); if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, + NFSX_V3FATTR + 4 * NFSX_UNSIGNED, errout); *tl++ = nfs_true; fp = (struct nfs_fattr *)tl; tl += (NFSX_V3FATTR / sizeof (u_int32_t)); } else { - nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED, + errout); fp = (struct nfs_fattr *)tl; tl += (NFSX_V2FATTR / sizeof (u_int32_t)); } - len = left = nfsm_rndup(cnt); + len = nfsm_rndup(cnt); if (cnt > 0) { - /* - * Generate the mbuf list with the uio_iov ref. to it. - */ - i = 0; - m = m2 = mb; - while (left > 0) { - siz = min(M_TRAILINGSPACE(m), left); - if (siz > 0) { - left -= siz; - i++; - } - if (left > 0) { - MGET(m, M_TRYWAIT, MT_DATA); - MCLGET(m, M_TRYWAIT); - m->m_len = 0; - m2->m_next = m; - m2 = m; - } - } - MALLOC(iv, struct iovec *, i * sizeof (struct iovec), - M_TEMP, M_WAITOK); - uiop->uio_iov = iv2 = iv; - m = mb; - left = len; - i = 0; - while (left > 0) { - if (m == NULL) - panic("nfsrv_read iov"); - siz = min(M_TRAILINGSPACE(m), left); - if (siz > 0) { - iv->iov_base = mtod(m, caddr_t) + m->m_len; - iv->iov_len = siz; - m->m_len += siz; - left -= siz; - iv++; - i++; - } - m = m->m_next; - } - uiop->uio_iovcnt = i; + if ((error = nfs_getmuio(&repc, &io, len, &iovp)) != 0) + goto errout; + uiop->uio_offset = off; - uiop->uio_resid = len; - uiop->uio_rw = UIO_READ; - uiop->uio_segflg = UIO_SYSSPACE; + uiop->uio_procp = NULL; error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); off = uiop->uio_offset; - nh->nh_nextr = off; - FREE((caddr_t)iv2, M_TEMP); - if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) { - if (!error) - error = getret; - m_freem(mreq); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, vap); - error = 0; - goto nfsmout; - } + if (nh != NULL) + nh->nh_nextr = off; + FREE(iovp, M_TEMP); + getret = VOP_GETATTR(vp, &va, cred, procp); + if (!error) + error = getret; + if (error) + goto ereply; } else { uiop->uio_resid = 0; } + vput(vp); vp = NULL; - nfsm_srvfillattr(vap, fp); + nfs_srvfillattr(&va, fp); tlen = len - uiop->uio_resid; cnt = cnt < tlen ? cnt : tlen; tlen = nfsm_rndup(cnt); if (len != tlen || tlen != cnt) - nfsm_adj(mb, len - tlen, tlen - cnt); + nfs_adj(repc.nc_m, len - tlen, tlen - cnt); if (v3) { *tl++ = txdr_unsigned(cnt); if (len < reqlen) @@ -1006,9 +921,22 @@ *tl++ = nfs_false; } *tl = txdr_unsigned(cnt); -nfsmout: + nd->nd_rep = repc; + return (0); + +ereply: + if (vp) { + vput(vp); + vp = NULL; + } + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3) + nfs_srvpostop_attr(&repc, getrep, &attr); + error = 0; +errout: if (vp) vput(vp); + nd->nd_rep = repc; return(error); } @@ -1016,33 +944,26 @@ * nfs write service */ int -nfsrv_write(nfsd, slp, procp, mrq) +nfsrv_write(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct iovec *ivp; register int i, cnt; - register struct mbuf *mp; register struct nfs_fattr *fp; struct iovec *iv; struct vattr va, forat; - register struct vattr *vap = &va; register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; int error = 0, rdonly, cache, len, forat_ret = 1; int ioflags, aftat_ret = 1, retlen, zeroing, adjust; int stable = NFSV3WRITE_FILESYNC; int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mreq; struct vnode *vp = NULL; + struct mbuf *mp; nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; @@ -1051,13 +972,9 @@ struct mount *mntp = NULL; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - if (mrep == NULL) { - *mrq = NULL; - error = 0; - goto nfsmout; - } + NFSCHAIN_INIT(&repc); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mntp, &fhp->fh_fid, &vp)) != NULL) @@ -1066,12 +983,12 @@ vput(vp); vp = NULL; if (v3) { - nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 5 * NFSX_UNSIGNED, errout); off = fxdr_hyper(tl); tl += 3; stable = fxdr_unsigned(int, *tl++); } else { - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 4 * NFSX_UNSIGNED, errout); off = (off_t)fxdr_unsigned(u_int32_t, *++tl); tl += 2; if (nfs_async) @@ -1087,11 +1004,11 @@ */ if (len > 0) { zeroing = 1; - mp = mrep; + mp = reqc.nc_m; while (mp) { - if (mp == md) { + if (mp == reqc.nc_m) { zeroing = 0; - adjust = dpos - mtod(mp, caddr_t); + adjust = reqc.nc_pos - mtod(mp, caddr_t); mp->m_len -= adjust; if (mp->m_len > 0 && adjust > 0) NFSMADV(mp, adjust); @@ -1112,47 +1029,29 @@ } if (len > NFS_MAXDATA || len < 0 || i < len) { error = EIO; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; + goto ereply; } error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - vp = NULL; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; if (v3) forat_ret = VOP_GETATTR(vp, &forat, cred, procp); if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - if (!error) { - nqsrv_getl(vp, ND_WRITE); - error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); - } - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; + error = v3 ? EINVAL : (vp->v_type == VDIR) ? EISDIR : EACCES; + goto ereply; } + nqsrv_getl(vp, ND_WRITE); + error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); + if (error) + goto ereply; if (len > 0) { MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, M_WAITOK); uiop->uio_iov = iv = ivp; uiop->uio_iovcnt = cnt; - mp = mrep; + mp = reqc.nc_mhead; while (mp) { if (mp->m_len > 0) { ivp->iov_base = mtod(mp, caddr_t); @@ -1184,44 +1083,54 @@ nfsstats.srvvop_writes++; FREE((caddr_t)iv, M_TEMP); } - aftat_ret = VOP_GETATTR(vp, vap, cred, procp); + aftat_ret = VOP_GETATTR(vp, &va, cred, procp); vput(vp); vp = NULL; if (!error) error = aftat_ret; - nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + - 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3)); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(retlen); - /* - * If nfs_async is set, then pretend the write was FILESYNC. - */ - if (stable == NFSV3WRITE_UNSTABLE && !nfs_async) - *tl++ = txdr_unsigned(stable); - else - *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); - /* - * Actually, there is no need to txdr these fields, - * but it may make the values more human readable, - * for debugging purposes. - */ - if (nfsver.tv_sec == 0) - nfsver = boottime; - *tl++ = txdr_unsigned(nfsver.tv_sec); - *tl = txdr_unsigned(nfsver.tv_usec); - } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } + if (!error) { + nfsm_reply(&repc, nfsd, slp, error, NFSX_PREOPATTR(v3) + + NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + + NFSX_WRITEVERF(v3), errout); + if (v3) { + nfs_srvwcc(forat_ret, &forat, aftat_ret, &va, &repc); + nfsm_build(&repc, tl, u_int32_t *, 4 * NFSX_UNSIGNED, + errout); + *tl++ = txdr_unsigned(retlen); + /* + * If nfs_async is set, then pretend the write was + * FILESYNC. + */ + if (stable == NFSV3WRITE_UNSTABLE && !nfs_async) + *tl++ = txdr_unsigned(stable); + else + *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); + /* + * Actually, there is no need to txdr these fields, + * but it may make the values more human readable, + * for debugging purposes. + */ + if (nfsver.tv_sec == 0) + nfsver = boottime; + *tl++ = txdr_unsigned(nfsver.tv_sec); + *tl = txdr_unsigned(nfsver.tv_usec); + } else { + nfsm_build(&repc, fp, struct nfs_fattr *, NFSX_V2FATTR, + errout); + nfs_srvfillattr(nfsd, &va, fp); + } + goto done; + } +ereply: + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3 && NFS_DOERRSTATUSV3(error)) + nfs_srvwcc(forat_ret, &forat, aftat_ret, &va, &repc); + error = 0; nfsmout: if (vp) vput(vp); +done: + nfsd->nd_rep = repc; vn_finished_write(mntp); return(error); } @@ -1234,28 +1143,27 @@ * Jan. 1994. */ int -nfsrv_writegather(ndp, slp, procp, mrq) +nfsrv_writegather(ndp, slp, procp) struct nfsrv_descript **ndp; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { register struct iovec *ivp; register struct mbuf *mp; register struct nfsrv_descript *wp, *nfsd, *owp, *swp; register struct nfs_fattr *fp; register int i; + struct nfs_chain reqc, repc; struct iovec *iov; struct nfsrvw_delayhash *wpp; struct ucred *cred; struct vattr va, forat; register u_int32_t *tl; register int32_t t1; - caddr_t bpos, dpos; + caddr_t bpos; int error = 0, rdonly, cache, len, forat_ret = 1; int ioflags, aftat_ret = 1, s, adjust, v3, zeroing; char *cp2; - struct mbuf *mb, *mb2, *mreq, *mrep, *md; struct vnode *vp = NULL; struct uio io, *uiop = &io; u_quad_t frev, cur_usec; @@ -1270,13 +1178,11 @@ if (*ndp) { nfsd = *ndp; *ndp = NULL; - mrep = nfsd->nd_mrep; - md = nfsd->nd_md; - dpos = nfsd->nd_dpos; + reqc = nfsd->nd_req; + repc.nc_headm = NULL; cred = &nfsd->nd_cr; v3 = (nfsd->nd_flag & ND_NFSV3); LIST_INIT(&nfsd->nd_coalesce); - nfsd->nd_mreq = NULL; nfsd->nd_stable = NFSV3WRITE_FILESYNC; cur_usec = nfs_curusec(); nfsd->nd_time = cur_usec + @@ -1285,14 +1191,14 @@ /* * Now, get the write header.. */ - nfsm_srvmtofh(&nfsd->nd_fh); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout1); if (v3) { - nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 5 * NFSX_UNSIGNED, errout1); nfsd->nd_off = fxdr_hyper(tl); tl += 3; nfsd->nd_stable = fxdr_unsigned(int, *tl++); } else { - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 4 * NFSX_UNSIGNED, errout1); nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl); tl += 2; if (nfs_async) @@ -1308,11 +1214,11 @@ */ zeroing = 1; i = 0; - mp = mrep; + mp = reqc.nc_mhead; while (mp) { - if (mp == md) { + if (mp == reqc.nc_m) { zeroing = 0; - adjust = dpos - mtod(mp, caddr_t); + adjust = reqc.nc_pos - mtod(mp, caddr_t); mp->m_len -= adjust; if (mp->m_len > 0 && adjust > 0) NFSMADV(mp, adjust); @@ -1329,15 +1235,15 @@ mp = mp->m_next; } if (len > NFS_MAXDATA || len < 0 || i < len) { -nfsmout: - m_freem(mrep); +errout1: error = EIO; - nfsm_writereply(2 * NFSX_UNSIGNED, v3); + nfsm_replyerror(&repc, nfsd, slp, error, errout); if (v3) - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - nfsd->nd_mreq = mreq; - nfsd->nd_mrep = NULL; + nfs_srvwcc(forat_ret, &forat, aftat_ret, &va, &repc); + nfsd->nd_rep = repc; nfsd->nd_time = 0; + m_freem(&nfsd->nd_reqc); + nfsd->nd_reqc = NULL; } /* @@ -1356,7 +1262,7 @@ } else { LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); } - if (nfsd->nd_mrep) { + if (nfsd->nd_req.nc_mhead) { wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); owp = NULL; wp = wpp->lh_first; @@ -1400,35 +1306,31 @@ owp = nfsd->nd_tq.le_next; if (nfsd->nd_time > cur_usec) break; - if (nfsd->nd_mreq) + if (nfsd->nd_mrep.nc_mhead) continue; NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff)); LIST_REMOVE(nfsd, nd_tq); LIST_REMOVE(nfsd, nd_hash); splx(s); - mrep = nfsd->nd_mrep; - nfsd->nd_mrep = NULL; + reqc = nfsd->nd_req; cred = &nfsd->nd_cr; v3 = (nfsd->nd_flag & ND_NFSV3); forat_ret = aftat_ret = 1; error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (!error) { - if (v3) + if (error) + goto ereply; + if (v3) forat_ret = VOP_GETATTR(vp, &forat, cred, procp); - if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - } else { - vp = NULL; - } - if (!error) { - nqsrv_getl(vp, ND_WRITE); - error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); + if (vp->v_type != VREG) { + error = v3 ? EINVAL : + (vp->v_type == VDIR) ? EISDIR : EACCES; + goto ereply; } + nqsrv_getl(vp, ND_WRITE); + error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); + if (error) + goto ereply; if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) ioflags = IO_NODELOCKED; @@ -1442,7 +1344,7 @@ uiop->uio_offset = nfsd->nd_off; uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; if (uiop->uio_resid > 0) { - mp = mrep; + mp = reqc.nc_mhead; i = 0; while (mp) { if (mp->m_len > 0) @@ -1453,7 +1355,7 @@ MALLOC(iov, struct iovec *, i * sizeof (struct iovec), M_TEMP, M_WAITOK); uiop->uio_iov = ivp = iov; - mp = mrep; + mp = reqc.nc_mhead; while (mp) { if (mp->m_len > 0) { ivp->iov_base = mtod(mp, caddr_t); @@ -1476,7 +1378,10 @@ } FREE((caddr_t)iov, M_TEMP); } - m_freem(mrep); +ereply: + /* Free the request to save it sitting around for a while */ + NFSCHAIN_FREE(&reqc); + if (vp) { aftat_ret = VOP_GETATTR(vp, &va, cred, procp); vput(vp); @@ -1491,17 +1396,17 @@ do { NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff)); if (error) { - nfsm_writereply(NFSX_WCCDATA(v3), v3); - if (v3) { + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3) nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - } } else { - nfsm_writereply(NFSX_PREOPATTR(v3) + - NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + - NFSX_WRITEVERF(v3), v3); + nfsm_reply(&repc, nfsd, slp, error, + NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + + 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3), errout); if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + nfs_srvwcc(forat_ret, &forat, aftat_ret, &va, &repc); + nfsm_build(&repc, tl, u_int32_t *, + 4 * NFSX_UNSIGNED,); *tl++ = txdr_unsigned(nfsd->nd_len); *tl++ = txdr_unsigned(swp->nd_stable); /* @@ -1514,13 +1419,12 @@ *tl++ = txdr_unsigned(nfsver.tv_sec); *tl = txdr_unsigned(nfsver.tv_usec); } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(&va, fp); + nfsm_build(&repc, fp, struct nfs_fattr *, + NFSX_V2FATTR,); + nfs_srvfillattr(nfsd, &va, fp); } } - nfsd->nd_mreq = mreq; - if (nfsd->nd_mrep) - panic("nfsrv_write: nd_mrep not free"); + nfsd->nd_rep = repc; /* * Done. Put it at the head of the timer queue so that @@ -1550,10 +1454,9 @@ */ s = splsoftclock(); for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) - if (nfsd->nd_mreq) { + if (nfsd->nd_rep.nc_mhead != NULL) { NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff)); LIST_REMOVE(nfsd, nd_tq); - *mrq = nfsd->nd_mreq; *ndp = nfsd; break; } @@ -1564,7 +1467,7 @@ /* * Coalesce the write request nfsd into owp. To do this we must: * - remove nfsd from the queues - * - merge nfsd->nd_mrep into owp->nd_mrep + * - merge nfsd->nd_req into owp->nd_req * - update the nd_eoff and nd_stable for owp * - put nfsd on owp's nd_coalesce list * NB: Must be called at splsoftclock(). @@ -1587,15 +1490,15 @@ if (overlap < 0) panic("nfsrv_coalesce: bad off"); if (overlap > 0) - m_adj(nfsd->nd_mrep, overlap); - mp = owp->nd_mrep; + m_adj(nfsd->nd_req.nc_mhead, overlap); + mp = owp->nd_req.nc_mhead; while (mp->m_next) mp = mp->m_next; - mp->m_next = nfsd->nd_mrep; + mp->m_next = nfsd->nd_req.nc_mhead; owp->nd_eoff = nfsd->nd_eoff; + NFSCHAIN_INIT(&nfsd->nd_req); } else - m_freem(nfsd->nd_mrep); - nfsd->nd_mrep = NULL; + NFSCHAIN_FREE(&nfsd->nd_req); if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) owp->nd_stable = NFSV3WRITE_FILESYNC; else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && @@ -1619,29 +1522,22 @@ * now does a truncate to 0 length via. setattr if it already exists */ int -nfsrv_create(nfsd, slp, procp, mrq) +nfsrv_create(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct nfs_fattr *fp; struct vattr va, dirfor, diraft; - register struct vattr *vap = &va; register struct nfsv2_sattr *sp; register u_int32_t *tl; struct nameidata nd; register int32_t t1; - caddr_t bpos; int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0; - caddr_t cp; - char *cp2; - struct mbuf *mb, *mb2, *mreq; struct vnode *dirp = (struct vnode *)0; nfsfh_t nfh; fhandle_t *fhp; @@ -1651,20 +1547,21 @@ struct vnode *vp; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); #ifndef nolint rdev = 0; #endif ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) return (error); (void) vn_start_write(vp, &mp, V_WAIT); vput(vp); - nfsm_srvnamesiz(len); + nfsm_srvnamesiz(&reqc, len, errout, errret); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; @@ -1679,23 +1576,18 @@ * be valid at all if an error occurs so we have to invalidate it * prior to calling nfsm_reply ( which might goto nfsmout ). */ - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - procp); + dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); } else { vrele(dirp); dirp = NULL; } - } - if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; } + if (error) + goto ereply; /* * No error. Continue. State: @@ -1710,9 +1602,9 @@ * NFS I/O. The cleanup at the end is a catch-all */ - VATTR_NULL(vap); + VATTR_NULL(&va); if (v3) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); how = fxdr_unsigned(int, *tl); switch (how) { case NFSV3CREATE_GUARDED: @@ -1722,28 +1614,30 @@ } /* fall through */ case NFSV3CREATE_UNCHECKED: - nfsm_srvsattr(vap); + nfsm_srvsattr(&repq, &va); break; case NFSV3CREATE_EXCLUSIVE: - nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF); + nfsm_dissect(&reqc, cp, caddr_t, NFSX_V3CREATEVERF, + errout); bcopy(cp, cverf, NFSX_V3CREATEVERF); exclusive_flag = 1; if (nd.ni_vp == NULL) - vap->va_mode = 0; + va.va_mode = 0; break; }; - vap->va_type = VREG; + va.va_type = VREG; } else { - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); - if (vap->va_type == VNON) - vap->va_type = VREG; - vap->va_mode = nfstov_mode(sp->sa_mode); - switch (vap->va_type) { + nfsm_dissect(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); + va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); + if (va.va_type == VNON) + va.va_type = VREG; + va.va_mode = nfstov_mode(sp->sa_mode); + switch (va.va_type) { case VREG: tsize = fxdr_unsigned(int32_t, sp->sa_size); if (tsize != -1) - vap->va_size = (u_quad_t)tsize; + va.va_size = (u_quad_t)tsize; break; case VCHR: case VBLK: @@ -1764,44 +1658,43 @@ * nd.ni_vp will also be non-NULL in that case. */ if (nd.ni_vp == NULL) { - if (vap->va_type == VREG || vap->va_type == VSOCK) { + if (va.va_type == VREG || va.va_type == VSOCK) { nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) + error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, + &va); + if (error) { NDFREE(&nd, NDF_ONLY_PNBUF); - else { + } else { nfsrv_object_create(nd.ni_vp); if (exclusive_flag) { exclusive_flag = 0; - VATTR_NULL(vap); - bcopy(cverf, (caddr_t)&vap->va_atime, + VATTR_NULL(&va); + bcopy(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF); - error = VOP_SETATTR(nd.ni_vp, vap, cred, + error = VOP_SETATTR(nd.ni_vp, &va, cred, procp); } } - } else if ( - vap->va_type == VCHR || - vap->va_type == VBLK || - vap->va_type == VFIFO - ) { + } else if (va.va_type == VCHR || va.va_type == VBLK || + va.va_type == VFIFO) { /* * Handle SysV FIFO node special cases. All other * devices require super user to access. */ - if (vap->va_type == VCHR && rdev == 0xffffffff) - vap->va_type = VFIFO; - if (vap->va_type != VFIFO && + if (va.va_type == VCHR && rdev == 0xffffffff) + va.va_type = VFIFO; + if (va.va_type != VFIFO && (error = suser_xxx(cred, 0, 0))) { - goto nfsmreply0; + goto ereply; } - vap->va_rdev = rdev; + va.va_rdev = rdev; nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, + &va); if (error) { NDFREE(&nd, NDF_ONLY_PNBUF); - goto nfsmreply0; + goto ereply; } vput(nd.ni_vp); nd.ni_vp = NULL; @@ -1827,7 +1720,7 @@ nd.ni_dvp = NULL; if (error != 0) { - nfsm_reply(0); + /* XXX nfsm_reply(&repc, nfsd, slp, error, 0); */ /* fall through on certain errors */ } nfsrv_object_create(nd.ni_vp); @@ -1839,15 +1732,15 @@ error = ENXIO; } } else { - if (vap->va_size != -1) { + if (va.va_size != -1) { error = nfsrv_access(nd.ni_vp, VWRITE, cred, (nd.ni_cnd.cn_flags & RDONLY), procp, 0); if (!error) { nqsrv_getl(nd.ni_vp, ND_WRITE); - tempsize = vap->va_size; - VATTR_NULL(vap); - vap->va_size = tempsize; - error = VOP_SETATTR(nd.ni_vp, vap, cred, + tempsize = va.va_size; + VATTR_NULL(&va); + va.va_size = tempsize; + error = VOP_SETATTR(nd.ni_vp, &va, cred, procp); } } @@ -1858,37 +1751,38 @@ fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, cred, procp); + error = VOP_GETATTR(nd.ni_vp, &va, cred, procp); } if (v3) { if (exclusive_flag && !error && - bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF)) + bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF)) error = EEXIST; diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); vrele(dirp); dirp = NULL; } - nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); + if (error) + goto errret; + nfsm_reply(&repc, nfsd, slp, error, NFSX_SRVFH(v3) + NFSX_FATTR(v3) + + NFSX_WCCDATA(v3), errout); if (v3) { - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } + nfsm_srvpostop_fh(&repc, fhp, errout); + nfsm_srvpostop_attr(&repc, 0, &va, errout); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; } else { - nfsm_srvfhtom(fhp, v3); - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } - goto nfsmout; - -nfsmreply0: - nfsm_reply(0); + nfs_srvfhtom(&repc, fhp, v3, errout); + nfsm_build(&repc, fp, struct nfs_fattr *, NFSX_V2FATTR, errout); + nfs_srvfillattr(nfsd, &va, fp); + } + goto done; + +errret: + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3 && NFS_DOERRSTATUSV3(error)) + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); error = 0; - /* fall through */ - -nfsmout: +errout: +done: /* XXX much of these are already free in the done case */ if (nd.ni_startdir) { vrele(nd.ni_startdir); nd.ni_startdir = NULL; @@ -1906,24 +1800,22 @@ vput(nd.ni_vp); vn_finished_write(mp); return (error); + nfsd->nd_rep = repc; } /* * nfs v3 mknod service */ int -nfsrv_mknod(nfsd, slp, procp, mrq) +nfsrv_mknod(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr va, dirfor, diraft; - register struct vattr *vap = &va; register u_int32_t *tl; struct nameidata nd; register int32_t t1; @@ -1931,8 +1823,6 @@ int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; u_int32_t major, minor; enum vtype vtyp; - char *cp2; - struct mbuf *mb, *mb2, *mreq; struct vnode *vp, *dirp = (struct vnode *)0; nfsfh_t nfh; fhandle_t *fhp; @@ -1940,10 +1830,11 @@ struct mount *mp = NULL; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -1951,7 +1842,7 @@ (void) vn_start_write(vp, &mp, V_WAIT); vput(vp); vp = NULL; - nfsm_srvnamesiz(len); + nfsm_srvnamesiz(&reqc, len, errout, ereply); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; @@ -1963,17 +1854,13 @@ * nfsmout. */ - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); - if (error) { - nfsm_reply(NFSX_WCCDATA(1)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + if (error) + goto errret; + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); vtyp = nfsv3tov_type(*tl); if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { error = NFSERR_BADTYPE; @@ -1985,7 +1872,7 @@ nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); major = fxdr_unsigned(u_int32_t, *tl++); minor = fxdr_unsigned(u_int32_t, *tl); - vap->va_rdev = makeudev(major, minor); + va.>va_rdev = makeudev(major, minor); } /* @@ -1993,7 +1880,7 @@ */ if (nd.ni_vp) { error = EEXIST; - goto out; + goto ereply; } vap->va_type = vtyp; if (vtyp == VSOCK) { @@ -2001,17 +1888,18 @@ nd.ni_startdir = NULL; nqsrv_getl(nd.ni_dvp, ND_WRITE); error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) + if (error) { NDFREE(&nd, NDF_ONLY_PNBUF); + goto ereply; + } } else { if (vtyp != VFIFO && (error = suser_xxx(cred, 0, 0))) - goto out; + goto ereply; nqsrv_getl(nd.ni_dvp, ND_WRITE); error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); if (error) { NDFREE(&nd, NDF_ONLY_PNBUF); - goto out; } vput(nd.ni_vp); nd.ni_vp = NULL; @@ -2029,58 +1917,50 @@ error = lookup(&nd); nd.ni_dvp = NULL; - if (error) - goto out; - if (nd.ni_cnd.cn_flags & ISSYMLINK) + goto ereply; + + if (nd.ni_cnd.cn_flags & ISSYMLINK) { error = EINVAL; + goto ereply; + } } /* * send response, cleanup, return. */ -out: - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - } vp = nd.ni_vp; - if (!error) { - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(vp, vap, cred, procp); - vput(vp); - vp = NULL; - nd.ni_vp = NULL; - } + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(nd.ni_vpv &fhp->fh_fid); + if (error) + goto ereply; + error = VOP_GETATTR(nd.ni_vp, &va, cred, procp); + if (error) + goto ereply; + vput(nd.ni_vp); + nd.ni_vp = NULL; diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); - if (dirp) { - vrele(dirp); - dirp = NULL; - } - nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - vn_finished_write(mp); - return (0); -nfsmout: + vrele(dirp); + dirp = NULL; + nfsm_reply(&repc, nfsd, slp, error, NFSX_SRVFH(1) + + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1), errout); + nfsm_srvpostop_fh(&repc, fhp, errout); + nfsm_srvpostop_attr(&repc, 0, &va, errout); + nfs_srvwcc(dirfor_ret, &dirfor, diraft_ret, &diraft, &repc); + goto done; + +ereply: + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (NFS_DOERRSTATUS(error, nfsd)) + nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); + error = 0; +errout: if (dirp) vrele(dirp); if (nd.ni_startdir) vrele(nd.ni_startdir); +done: NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_dvp) { if (nd.ni_dvp == nd.ni_vp) @@ -2090,6 +1970,7 @@ } if (nd.ni_vp) vput(nd.ni_vp); + nfsd->nd_rep = repc; vn_finished_write(mp); return (error); } @@ -2098,24 +1979,18 @@ * nfs remove service */ int -nfsrv_remove(nfsd, slp, procp, mrq) +nfsrv_remove(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct nameidata nd; register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; struct vnode *dirp; struct vattr dirfor, diraft; nfsfh_t nfh; @@ -2125,10 +2000,11 @@ struct vnode *vp; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -2136,13 +2012,13 @@ (void) vn_start_write(vp, &mp, V_WAIT); vput(vp); vp = NULL; - nfsm_srvnamesiz(len); + nfsm_srvnamesiz(&reqc, len, errout, ereply); nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2152,37 +2028,45 @@ dirp = NULL; } } - if (error == 0) { - if (nd.ni_vp->v_type == VDIR) { - error = EPERM; /* POSIX */ - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (nd.ni_vp->v_flag & VROOT) { - error = EBUSY; - goto out; - } -out: - if (!error) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - nqsrv_getl(nd.ni_vp, ND_WRITE); - error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); - NDFREE(&nd, NDF_ONLY_PNBUF); - } + if (error) + goto errret; + + if (nd.ni_vp->v_type == VDIR) { + error = EPERM; /* POSIX */ + goto ereply; } + /* + * The root of a mounted filesystem cannot be deleted. + */ + if (nd.ni_vp->v_flag & VROOT) { + error = EBUSY; + goto ereply; + } + nqsrv_getl(nd.ni_dvp, ND_WRITE); + nqsrv_getl(nd.ni_vp, ND_WRITE); + error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + if (dirp && v3) { diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); vrele(dirp); dirp = NULL; - } - nfsm_reply(NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; } -nfsmout: + if (!error) { + nfsm_reply(&repc, nfsd, slp, error, NFSX_WCCDATA(v3), errout); + if (v3) + nfs_srvwcc(dirfor_ret, &dirfor, diraft_ret, &diraft, + &repc); + goto done; + } +ereply: + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3 && NFS_DOERRSTATUS(error)) + nfs_srvwcc(dirfor_ret, &dirfor, diraft_ret, &diraft, &repc); + error = 0; +errout: + if (dirp) + vrele(dirp); +done: NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_dvp) { if (nd.ni_dvp == nd.ni_vp) @@ -2192,6 +2076,7 @@ } if (nd.ni_vp) vput(nd.ni_vp); + nfsd->nd_rep = repc; vn_finished_write(mp); return(error); } @@ -2200,24 +2085,18 @@ * nfs rename service */ int -nfsrv_rename(nfsd, slp, procp, mrq) +nfsrv_rename(nfsd, slp, procp) struct nfsrv_descript *nfsd; struct nfssvc_sock *slp; struct proc *procp; - struct mbuf **mrq; { - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; + struct nfs_chain reqc = nfsd->nd_req, repc; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; int tdirfor_ret = 1, tdiraft_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; struct nameidata fromnd, tond; struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; struct vnode *tdirp = (struct vnode *)0; @@ -2230,6 +2109,7 @@ struct vnode *vp; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); + NFSCHAIN_INIT(&repc); #ifndef nolint fvp = (struct vnode *)0; #endif @@ -2243,7 +2123,7 @@ ndclear(&fromnd); ndclear(&tond); - nfsm_srvmtofh(ffhp); + nfsm_srvmtofh(&reqc, ffhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &ffhp->fh_fid, &vp)) != NULL) @@ -2251,7 +2131,7 @@ (void) vn_start_write(vp, &mp, V_WAIT); vput(vp); vp = NULL; - nfsm_srvnamesiz(len); + nfsm_srvnamesiz(&reqc, len, errout, ereply); /* * Remember our original uid so that we can reset cr_uid before * the second nfs_namei() call, in case it is remapped. @@ -2260,8 +2140,8 @@ fromnd.ni_cnd.cn_cred = cred; fromnd.ni_cnd.cn_nameiop = DELETE; fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; - error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, - &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&fromnd, ffhp, len, slp, nam, &reqc, &fdirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (fdirp) { if (v3) { fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, @@ -2271,22 +2151,18 @@ fdirp = NULL; } } - if (error) { - nfsm_reply(2 * NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); - nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); - error = 0; - goto nfsmout; - } + if (error) + goto ereply; + fvp = fromnd.ni_vp; - nfsm_srvmtofh(tfhp); - nfsm_strsiz(len2, NFS_MAXNAMLEN); + nfsm_srvmtofh(&reqc, tfhp, nfsd->nd_flag & ND_NFSV3, errout); + nfsm_strnamesiz(&reqc, len2, errout, ereply); cred->cr_uid = saved_uid; tond.ni_cnd.cn_cred = cred; tond.ni_cnd.cn_nameiop = RENAME; tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; - error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, - &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&tond, tfhp, len2, slp, nam, &reqc, &tdirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (tdirp) { if (v3) { tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, @@ -2297,52 +2173,33 @@ } } if (error) - goto out1; + goto ereply; tdvp = tond.ni_dvp; tvp = tond.ni_vp; if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { - if (v3) - error = EEXIST; - else - error = EISDIR; - goto out; + error = v3 ? EEXIST : EISDIR; + goto ereply; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { - if (v3) - error = EEXIST; - else - error = ENOTDIR; - goto out; + error = v3 ? EEXIST : ENOTDIR; + goto ereply; } if (tvp->v_type == VDIR && tvp->v_mountedhere) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; + error = v3 ? EXDEV : ENOTEMPTY; + goto ereply; } } if (fvp->v_type == VDIR && fvp->v_mountedhere) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; + error = v3 ? EXDEV : ENOTEMPTY; + goto ereply; } if (fvp->v_mount != tdvp->v_mount) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; - } - if (fvp == tdvp) { - if (v3) - error = EINVAL; - else - error = ENOTEMPTY; + error = v3 ? EXDEV : ENOTEMPTY; + goto ereply; } + if (fvp == tdvp) + error = v3 ? EINVAL : ENOTEMPTY; /* * If source is the same as the destination (that is the * same vnode with the same name in the same directory), @@ -2351,9 +2208,10 @@ if (fvp == tvp && fromnd.ni_dvp == tdvp && fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, - fromnd.ni_cnd.cn_namelen)) - error = -1; -out: + fromnd.ni_cnd.cn_namelen)) { + error = 0; + goto ereply; + } if (!error) { /* * The VOP_RENAME function releases all vnode references & @@ -2374,27 +2232,37 @@ if (error) { fromnd.ni_cnd.cn_flags &= ~HASBUF; tond.ni_cnd.cn_flags &= ~HASBUF; + goto ereply; } - } else { - if (error == -1) - error = 0; + if (fdirp) + fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); + if (tdirp) + tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); + nfsm_reply(&repc, nfsd, slp, error, 2 * NFSX_WCCDATA(v3), + errout); + if (v3) { + nfs_srvwcc(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, + &repc); + nfs_srvwcc(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, + &repc); + } + + goto done; } - /* fall through */ -out1: +ereply: if (fdirp) fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); if (tdirp) tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); - nfsm_reply(2 * NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); - nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); + nfsm_replyerror(&repc, nfsd, slp, error, errout); + if (v3 && NFS_DOERRSTATUS(error)) { + nfs_srvwcc(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, &repc); + nfs_srvwcc(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, &repc); } error = 0; - /* fall through */ - nfsmout: +done: /* * Clear out tond related fields */ @@ -2425,6 +2293,7 @@ if (fromnd.ni_vp) vrele(fromnd.ni_vp); + nfsd->nd_rep = repc; vn_finished_write(mp); return (error); } @@ -2441,7 +2310,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct nameidata nd; register u_int32_t *tl; @@ -2463,7 +2331,7 @@ fhp = &nfh.fh_generic; dfhp = &dnfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -2471,13 +2339,14 @@ (void) vn_start_write(vp, &mp, V_WAIT); vput(vp); vp = NULL; - nfsm_srvmtofh(dfhp); + nfsm_srvmtofh(&reqc, dfhp, nfsd->nd_flag & ND_NFSV3, errout); nfsm_srvnamesiz(len); error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) { - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_POSTOPATTR(v3) + + NFSX_WCCDATA(v3), errout); nfsm_srvpostop_attr(getret, &at); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); vp = NULL; @@ -2491,8 +2360,8 @@ nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; - error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, dfhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2527,7 +2396,8 @@ getret = VOP_GETATTR(vp, &at, cred, procp); if (dirp) diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_POSTOPATTR(v3) + + NFSX_WCCDATA(v3), errout); if (v3) { nfsm_srvpostop_attr(getret, &at); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); @@ -2565,7 +2435,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr va, dirfor, diraft; struct nameidata nd; @@ -2590,7 +2459,7 @@ ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -2602,8 +2471,8 @@ nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2707,7 +2576,8 @@ vrele(nd.ni_startdir); nd.ni_startdir = NULL; } - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_SRVFH(v3) + + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3), errout); if (v3) { if (!error) { nfsm_srvpostop_fh(fhp); @@ -2751,7 +2621,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr va, dirfor, diraft; register struct vattr *vap = &va; @@ -2777,7 +2646,7 @@ ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -2790,8 +2659,8 @@ nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2802,7 +2671,8 @@ } } if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_WCCDATA(v3), + errout); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); error = 0; goto nfsmout; @@ -2850,7 +2720,8 @@ out: if (dirp) diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_SRVFH(v3) + + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3), errout); if (v3) { if (!error) { nfsm_srvpostop_fh(fhp); @@ -2858,7 +2729,7 @@ } nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); } else { - nfsm_srvfhtom(fhp, v3); + nfs_srvfhtom(fhp, v3); nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); nfsm_srvfillattr(vap, fp); } @@ -2897,11 +2768,9 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register u_int32_t *tl; register int32_t t1; - caddr_t bpos; int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; @@ -2918,7 +2787,7 @@ ndclear(&nd); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -2930,8 +2799,8 @@ nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, fhp, len, slp, nam, &reqc, &dirp, procp, + (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2942,7 +2811,7 @@ } } if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_WCCDATA(v3), errout); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); error = 0; goto nfsmout; @@ -2978,7 +2847,7 @@ if (dirp) diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); - nfsm_reply(NFSX_WCCDATA(v3)); + nfsm_reply(&repc, nfsd, slp, error, NFSX_WCCDATA(v3), errout); if (v3) { nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); error = 0; @@ -3049,7 +2918,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register char *bp, *be; register struct mbuf *mp; @@ -3057,7 +2925,6 @@ register caddr_t cp; register u_int32_t *tl; register int32_t t1; - caddr_t bpos; struct mbuf *mb, *mb2, *mreq, *mp2; char *cpos, *cend, *cp2, *rbuf; struct vnode *vp = NULL; @@ -3074,7 +2941,7 @@ nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if (v3) { nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); toff = fxdr_hyper(tl); @@ -3240,7 +3107,7 @@ txdr_hyper(at.va_filerev, tl); } mp = mp2 = mb; - bp = bpos; + bp = reqc.nc_pos; be = bp + M_TRAILINGSPACE(mp); /* Loop through the records and build reply */ @@ -3342,7 +3209,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register char *bp, *be; register struct mbuf *mp; @@ -3368,7 +3234,7 @@ nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); toff = fxdr_hyper(tl); tl += 2; @@ -3679,7 +3545,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr bfor, aft; struct vnode *vp = NULL; @@ -3699,7 +3564,7 @@ cache = 0; #endif fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL) @@ -3825,7 +3690,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct statfs *sf; register struct nfs_statfs *sfp; @@ -3848,7 +3712,7 @@ cache = 0; #endif fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) { @@ -3912,7 +3776,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register u_int32_t *tl; register struct nfsv3_fsinfo *sip; @@ -3933,7 +3796,7 @@ cache = 0; #endif fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) { @@ -3994,7 +3857,6 @@ { struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register u_int32_t *tl; register struct nfsv3_pathconf *pc; @@ -4015,7 +3877,7 @@ cache = 0; #endif fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); + nfsm_srvmtofh(&reqc, fhp, nfsd->nd_flag & ND_NFSV3, errout); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) { @@ -4103,9 +3965,6 @@ u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif if (nfsd->nd_repstat) error = nfsd->nd_repstat; else Index: nfs_socket.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_socket.c,v retrieving revision 1.63 diff -u -r1.63 nfs_socket.c --- nfs_socket.c 2000/12/21 21:44:24 1.63 +++ nfs_socket.c 2001/01/29 01:10:35 @@ -576,7 +576,7 @@ * attempt that has essentially shut down this * mount point. */ - if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { + if (rep->r_rep.nc_mhead || (rep->r_flags & R_SOFTTERM)) { nfs_sndunlock(rep); return (EINTR); } @@ -764,10 +764,10 @@ register struct nfsreq *rep; register struct nfsmount *nmp = myrep->r_nmp; register int32_t t1; - struct mbuf *mrep, *md; + struct nfs_chain repc; struct sockaddr *nam; u_int32_t rxid, *tl; - caddr_t dpos, cp2; + caddr_t cp2; int error; /* @@ -793,7 +793,7 @@ /* * Get the next Rpc reply off the socket */ - error = nfs_receive(myrep, &nam, &mrep); + error = nfs_receive(myrep, &nam, &repc.nc_mhead); nfs_rcvunlock(myrep); if (error) { @@ -814,24 +814,25 @@ /* * Get the xid and check that it is an rpc reply */ - md = mrep; - dpos = mtod(md, caddr_t); - nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED); + repc.nc_m = repc.nc_mhead; + repc.nc_pos = mtod(md, caddr_t); + nfsm_dissect(&repc, tl, u_int32_t *, 2*NFSX_UNSIGNED, errout); rxid = *tl++; if (*tl != rpc_reply) { #ifndef NFS_NOSERVER if (nmp->nm_flag & NFSMNT_NQNFS) { - if (nqnfs_callback(nmp, mrep, md, dpos)) + if (nqnfs_callback(nmp, &repc)) nfsstats.rpcinvalid++; } else { +errout: nfsstats.rpcinvalid++; - m_freem(mrep); + NFSCHAIN_FREE(&repc); } #else +errout: nfsstats.rpcinvalid++; - m_freem(mrep); + NFSCHAIN_FREE(&repc); #endif -nfsmout: if (myrep->r_flags & R_GETONEREP) return (0); continue; @@ -843,11 +844,9 @@ */ for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) { - if (rep->r_mrep == NULL && rxid == rep->r_xid) { + if (rep->r_rep.nc_mhead == NULL && rxid == rep->r_xid) { /* Found it.. */ - rep->r_mrep = mrep; - rep->r_md = md; - rep->r_dpos = dpos; + rep->r_rep = repc; if (nfsrtton) { struct rttl *rt; @@ -913,9 +912,9 @@ */ if (rep == 0) { nfsstats.rpcunexpected++; - m_freem(mrep); + NFSCHAIN_FREE(&repc); } else if (rep == myrep) { - if (rep->r_mrep == NULL) + if (rep->r_rep.nc_mhead == NULL) panic("nfsreply nil"); return (0); } @@ -932,18 +931,18 @@ * - calls nfs_receive() to get reply * - break down rpc header and return with nfs reply pointed to * by mrep or error - * nb: always frees up mreq mbuf list + * nb: always frees up mreq mbuf chain. + * On error, frees reply, except when returning with (error & NFSERR_RETERR). + * repcp->cp_mhead is guaranteed to be NULL if no reply returned. */ int -nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp) +nfs_request(vp, mreq, procnum, procp, cred, repc) struct vnode *vp; - struct mbuf *mrest; + struct mbuf *mreq; int procnum; struct proc *procp; struct ucred *cred; - struct mbuf **mrp; - struct mbuf **mdp; - caddr_t *dposp; + struct nfs_chain *repc; { register struct mbuf *mrep, *m2; register struct nfsreq *rep; @@ -955,71 +954,74 @@ char nickv[RPCX_NICKVERF]; time_t reqtime, waituntil; caddr_t dpos, cp2; - int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; + int t1, nqlflag, cachable, s, error = 0, mreq_len, auth_len, auth_type; int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; int verf_len, verf_type; - u_int32_t xid; u_quad_t frev; char *auth_str, *verf_str; NFSKERBKEY_T key; /* save session key */ + NFSCHAIN_INIT(repc); + nmp = VFSTONFS(vp->v_mount); MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); rep->r_nmp = nmp; rep->r_vp = vp; rep->r_procp = procp; rep->r_procnum = procnum; - i = 0; - m = mrest; - while (m) { - i += m->m_len; - m = m->m_next; - } - mrest_len = i; + rep->r_mreq = NULL; + NFSCHAIN_INIT(&rep->r_rep); + mreq_len = 0; + for (m = mreq; m != NULL; m = m->next) + mreq_len += m->m_len; /* * Get the RPC header with authorization. */ kerbauth: - verf_str = auth_str = (char *)0; + verf_str = auth_str = NULL; if (nmp->nm_flag & NFSMNT_KERB) { verf_str = nickv; - verf_len = sizeof (nickv); + verf_len = sizeof(nickv); auth_type = RPCAUTH_KERB4; - bzero((caddr_t)key, sizeof (key)); + bzero(&key[0], sizeof(key)); if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str, - &auth_len, verf_str, verf_len)) { + &auth_len, verf_str, verf_len)) { error = nfs_getauth(nmp, rep, cred, &auth_str, - &auth_len, verf_str, &verf_len, key); - if (error) { - free((caddr_t)rep, M_NFSREQ); - m_freem(mrest); - return (error); - } + &auth_len, verf_str, &verf_len, key); + if (error) + goto errout; } } else { auth_type = RPCAUTH_UNIX; if (cred->cr_ngroups < 1) panic("nfsreq nogrps"); auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? - nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + - 5 * NFSX_UNSIGNED; + nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + + 5 * NFSX_UNSIGNED; } m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, - auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); - if (auth_str) + auth_str, verf_len, verf_str, mreq, mreq_len, &mheadend, + &rep->r_xid); + mreq = NULL; + if (auth_str) { free(auth_str, M_TEMP); + auth_str = NULL; + } /* * For stream protocols, insert a Sun RPC Record Mark. */ if (nmp->nm_sotype == SOCK_STREAM) { M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); + if (m == NULL) { + error = ENOBUFS; + goto errout; + } *mtod(m, u_int32_t *) = htonl(0x80000000 | - (m->m_pkthdr.len - NFSX_UNSIGNED)); + (m->m_pkthdr.len - NFSX_UNSIGNED)); } rep->r_mreq = m; - rep->r_xid = xid; tryagain: if (nmp->nm_flag & NFSMNT_SOFT) rep->r_retry = nmp->nm_retry; @@ -1030,7 +1032,7 @@ rep->r_flags = R_TIMING; else rep->r_flags = 0; - rep->r_mrep = NULL; + NFSCHAIN_FREE(&rep->r_rep); /* * Do the client side RPC. @@ -1052,8 +1054,7 @@ * do it now. */ if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM || - (nmp->nm_flag & NFSMNT_DUMBTIMR) || - nmp->nm_sent < nmp->nm_cwnd)) { + (nmp->nm_flag & NFSMNT_DUMBTIMR) || nmp->nm_sent < nmp->nm_cwnd)) { splx(s); if (nmp->nm_soflags & PR_CONNREQUIRED) error = nfs_sndlock(rep); @@ -1100,37 +1101,35 @@ if (!error && (rep->r_flags & R_TPRINTFMSG)) nfs_msg(rep->r_procp, nmp->nm_mountp->mnt_stat.f_mntfromname, "is alive again"); - mrep = rep->r_mrep; - md = rep->r_md; - dpos = rep->r_dpos; - if (error) { - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); - } + if (error) + goto errout; /* * break down the rpc header and check if ok */ - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + if ((error = nfs_dissect(&rep->r_rep, 3 * NFSX_UNSIGNED, &tl)) != 0) + goto errout; if (*tl++ == rpc_msgdenied) { - if (*tl == rpc_mismatch) + if (*tl == rpc_mismatch) { error = EOPNOTSUPP; - else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { - if (!failed_auth) { - failed_auth++; - mheadend->m_next = (struct mbuf *)0; - m_freem(mrep); - m_freem(rep->r_mreq); - goto kerbauth; - } else - error = EAUTH; - } else + goto errout; + } else if ((nmp->nm_flag & NFSMNT_KERB) == 0 || + *tl++ != rpc_autherr) { error = EACCES; - m_freem(mrep); + goto errout; + } else if (failed_auth) { + error = EAUTH; + goto errout; + } + + failed_auth++; + /* Split out original request for retry. */ + mreq = mheadend->m_next; + mheadend->m_next = NULL; + NFSCHAIN_FREE(&rep->r_rep); m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); + rep->r_mreq = NULL: + goto kerbauth; } /* @@ -1139,118 +1138,134 @@ verf_type = fxdr_unsigned(int, *tl++); i = fxdr_unsigned(int32_t, *tl); if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) { - error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep); + error = nfs_savenickauth(nmp, cred, i, key, &repc); if (error) - goto nfsmout; + goto errout; } else if (i > 0) - nfsm_adv(nfsm_rndup(i)); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_adv(&rep->r_rep, nfsm_rndup(i), errout); + if ((error = nfs_dissect(&rep->r_rep, NFSX_UNSIGNED, &tl)) != 0) + goto errout; /* 0 == ok */ - if (*tl == 0) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - if (*tl != 0) { - error = fxdr_unsigned(int, *tl); - if ((nmp->nm_flag & NFSMNT_NFSV3) && - error == NFSERR_TRYLATER) { - m_freem(mrep); - error = 0; - waituntil = time_second + trylater_delay; - while (time_second < waituntil) - (void) tsleep((caddr_t)&lbolt, - PSOCK, "nqnfstry", 0); - trylater_delay *= nfs_backoff[trylater_cnt]; - if (trylater_cnt < 7) - trylater_cnt++; - goto tryagain; - } - - /* - * If the File Handle was stale, invalidate the - * lookup cache, just in case. - */ - if (error == ESTALE) - cache_purge(vp); - if (nmp->nm_flag & NFSMNT_NFSV3) { - *mrp = mrep; - *mdp = md; - *dposp = dpos; - error |= NFSERR_RETERR; - } else - m_freem(mrep); - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); + if (*tl != 0) { + error = EPROTONOSUPPORT; + goto errout; + } + + if ((error = nfs_dissect(&rep->r_rep, NFSX_UNSIGNED, &tl)) != 0) + goto errout; + if (*tl != 0) { + error = fxdr_unsigned(int, *tl); + if ((nmp->nm_flag & NFSMNT_NFSV3) && error == NFSERR_TRYLATER) { + NFSCHAIN_INIT(&rep->r_rep); + error = 0; + waituntil = time_second + trylater_delay; + while (time_second < waituntil) + tsleep(&lbolt, PSOCK, "nqnfstry", 0); + trylater_delay *= nfs_backoff[trylater_cnt]; + if (trylater_cnt < 7) + trylater_cnt++; + goto tryagain; } /* - * For nqnfs, get any lease in reply + * If the File Handle was stale, invalidate the + * lookup cache, just in case. */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - if (*tl) { - np = VTONFS(vp); - nqlflag = fxdr_unsigned(int, *tl); - nfsm_dissect(tl, u_int32_t *, 4*NFSX_UNSIGNED); - cachable = fxdr_unsigned(int, *tl++); - reqtime += fxdr_unsigned(int, *tl++); - if (reqtime > time_second) { - frev = fxdr_hyper(tl); - nqnfs_clientlease(nmp, np, nqlflag, - cachable, reqtime, frev); - } + if (error == ESTALE) + cache_purge(vp); + if (nmp->nm_flag & NFSMNT_NFSV3) { + *repc = rep->r_rep; + NFSCHAIN_INIT(&rep->r_rep); + error |= NFSERR_RETERR; + } + goto errout; + } + + /* + * For nqnfs, get any lease in reply + */ + if (nmp->nm_flag & NFSMNT_NQNFS) { + if ((error = nfs_dissect(&rep->r_rep, NFSX_UNSIGNED, &tl)) != 0) + goto errout; + if (*tl) { + np = VTONFS(vp); + nqlflag = fxdr_unsigned(int, *tl); + if ((error = nfs_dissect(&rep->r_rep, + 4 * NFSX_UNSIGNED, &tl)) != 0) + goto errout; + cachable = fxdr_unsigned(int, *tl++); + reqtime += fxdr_unsigned(int, *tl++); + if (reqtime > time_second) { + frev = fxdr_hyper(tl); + nqnfs_clientlease(nmp, np, nqlflag, cachable, + reqtime, frev); } } - *mrp = mrep; - *mdp = md; - *dposp = dpos; - m_freem(rep->r_mreq); - FREE((caddr_t)rep, M_NFSREQ); - return (0); } - m_freem(mrep); - error = EPROTONOSUPPORT; -nfsmout: + *repc = rep->r_rep; m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); + FREE(rep, M_NFSREQ); + return (0); + +errout: + NFSCHAIN_FREE(&rep->r_rep); + if (auth_str != NULL) + free(auth_str, M_TEMP); + if (mreq != NULL) + m_freem(mreq); + if (rep->r_mreq != NULL) + m_freem(rep->r_mreq); + free(rep, M_NFSREQ); return (error); } #ifndef NFS_NOSERVER /* * Generate the rpc reply header - * siz arg. is used to decide if adding a cluster is worthwhile + * sizehint arg. is used to decide if adding a cluster is worthwhile. + * Returns 0 on success, or: + * + * ENOBUFS An mbuf alllocation failed. */ int -nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp) - int siz; +nfs_rephead(ncp, nd, slp, err, sizehint, cache, frev) + struct nfs_chain *ncp; struct nfsrv_descript *nd; struct nfssvc_sock *slp; int err; + int sizehint; int cache; u_quad_t *frev; - struct mbuf **mrq; - struct mbuf **mbp; - caddr_t *bposp; { + struct nfs_chain repc; register u_int32_t *tl; - register struct mbuf *mreq; - caddr_t bpos; - struct mbuf *mb, *mb2; + struct mbuf *m; + int error; + + /* If the error was lack of mbufs, claim that the reply failed */ + if (err == ENOBUFS) + return (ENOBUFS); - MGETHDR(mreq, M_TRYWAIT, MT_DATA); - mb = mreq; + MGETHDR(m, M_TRYWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS) /* * If this is a big reply, use a cluster else * try and leave leading space for the lower level headers. */ - siz += RPC_REPLYSIZ; - if ((max_hdr + siz) >= MINCLSIZE) { - MCLGET(mreq, M_TRYWAIT); + sizehint += RPC_REPLYSIZ; + if ((max_hdr + sizehint) >= MINCLSIZE) { + MCLGET(m, M_TRYWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + return (ENOBUFS); + } } else - mreq->m_data += max_hdr; - tl = mtod(mreq, u_int32_t *); - mreq->m_len = 6 * NFSX_UNSIGNED; - bpos = ((caddr_t)tl) + mreq->m_len; + m->m_data += max_hdr; + repc.nc_mhead = repc.nc_m = m; + repc.nc_pos = mtod(mreq, caddr_t); + + nfsm_build(&repc, tl, u_int32_t *, 6 * NFSX_UNSIGNED, errout); *tl++ = txdr_unsigned(nd->nd_retxid); *tl++ = rpc_reply; if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { @@ -1258,8 +1273,8 @@ if (err & NFSERR_AUTHERR) { *tl++ = rpc_autherr; *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); - mreq->m_len -= NFSX_UNSIGNED; - bpos -= NFSX_UNSIGNED; + repc.nc_m->m_len -= NFSX_UNSIGNED; + repc.nc_pos -= NFSX_UNSIGNED; } else { *tl++ = rpc_mismatch; *tl++ = txdr_unsigned(RPC_VER2); @@ -1273,40 +1288,42 @@ * verifier back, otherwise just RPCAUTH_NULL. */ if (nd->nd_flag & ND_KERBFULL) { - register struct nfsuid *nuidp; - struct timeval ktvin, ktvout; + struct nfsuid *nuidp; + struct timeval ktvin, ktvout; - for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; - nuidp != 0; nuidp = nuidp->nu_hash.le_next) { - if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && - (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp), - &nuidp->nu_haddr, nd->nd_nam2))) - break; - } - if (nuidp) { - ktvin.tv_sec = - txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1); - ktvin.tv_usec = - txdr_unsigned(nuidp->nu_timestamp.tv_usec); + LIST_FOREACH(nuidp, &NUIDHASH(slp, nd->nd_cr.cr_uid), + nu_hash) { + if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && + (!nd->nd_nam2 || + netaddr_match(NU_NETFAM(nuidp), + &nuidp->nu_haddr, nd->nd_nam2))) + break; + } + if (nuidp) { + ktvin.tv_sec = txdr_unsigned( + nuidp->nu_timestamp.tv_sec - 1); + ktvin.tv_usec = txdr_unsigned( + nuidp->nu_timestamp.tv_usec); - /* - * Encrypt the timestamp in ecb mode using the - * session key. - */ + /* + * Encrypt the timestamp in ecb mode using the + * session key. + */ #ifdef NFSKERB - XXX + XXX #endif - *tl++ = rpc_auth_kerb; - *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); - *tl = ktvout.tv_sec; - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - *tl++ = ktvout.tv_usec; - *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); - } else { - *tl++ = 0; - *tl++ = 0; - } + *tl++ = rpc_auth_kerb; + *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); + *tl = ktvout.tv_sec; + nfsm_build(&repc, tl, u_int32_t *, + 3 * NFSX_UNSIGNED, errout); + *tl++ = ktvout.tv_usec; + *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); + } else { + *tl++ = 0; + *tl++ = 0; + } } else { *tl++ = 0; *tl++ = 0; @@ -1317,7 +1334,8 @@ break; case EPROGMISMATCH: *tl = txdr_unsigned(RPC_PROGMISMATCH); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); if (nd->nd_flag & ND_NQNFS) { *tl++ = txdr_unsigned(3); *tl = txdr_unsigned(3); @@ -1335,14 +1353,15 @@ default: *tl = 0; if (err != NFSERR_RETVOID) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, + NFSX_UNSIGNED, errout); if (err) *tl = txdr_unsigned(nfsrv_errmap(nd, err)); else *tl = 0; } break; - }; + } } /* @@ -1350,23 +1369,25 @@ */ if ((nd->nd_flag & ND_NQNFS) && err == 0) { if (nd->nd_flag & ND_LEASE) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, 5 * NFSX_UNSIGNED, + errout); *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE); *tl++ = txdr_unsigned(cache); *tl++ = txdr_unsigned(nd->nd_duration); txdr_hyper(*frev, tl); } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); *tl = 0; } } - if (mrq != NULL) - *mrq = mreq; - *mbp = mb; - *bposp = bpos; + *repcp = repc; if (err != 0 && err != NFSERR_RETVOID) nfsstats.srvrpc_errs++; return (0); +errout: + NFSCHAIN_FREE(&repc); + return (error); } @@ -1725,40 +1746,34 @@ struct nfsd *nfsd; int has_header; { + struct nfs_chain reqc; register int len, i; - register u_int32_t *tl; - register int32_t t1; struct uio uio; struct iovec iov; - caddr_t dpos, cp2, cp; + u_int32_t tl; u_int32_t nfsvers, auth_type; uid_t nickuid; int error = 0, nqnfs = 0, ticklen; - struct mbuf *mrep, *md; register struct nfsuid *nuidp; struct timeval tvin, tvout; #if 0 /* until encrypted keys are implemented */ NFSKERBKEYSCHED_T keys; /* stores key schedule */ #endif - mrep = nd->nd_mrep; - md = nd->nd_md; - dpos = nd->nd_dpos; + reqc = nd->nd_req; if (has_header) { - nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 10 * NFSX_UNSIGNED, errout) nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++); - if (*tl++ != rpc_call) { - m_freem(mrep); - return (EBADRPC); - } + if (*tl++ != rpc_call) + return EBADRPC; } else - nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 8 * NFSX_UNSIGNED, errout); nd->nd_repstat = 0; nd->nd_flag = 0; if (*tl++ != rpc_vers) { nd->nd_repstat = ERPCMISMATCH; nd->nd_procnum = NFSPROC_NOOP; - return (0); + return 0; } if (*tl != nfs_prog) { if (*tl == nqnfs_prog) @@ -1766,7 +1781,7 @@ else { nd->nd_repstat = EPROGUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; - return (0); + return 0; } } tl++; @@ -1775,7 +1790,7 @@ (nfsvers != NQNFS_VER3 && nqnfs)) { nd->nd_repstat = EPROGMISMATCH; nd->nd_procnum = NFSPROC_NOOP; - return (0); + return 0; } if (nqnfs) nd->nd_flag = (ND_NFSV3 | ND_NQNFS); @@ -1783,22 +1798,20 @@ nd->nd_flag = ND_NFSV3; nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++); if (nd->nd_procnum == NFSPROC_NULL) - return (0); + return 0; if (nd->nd_procnum >= NFS_NPROCS || (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) || (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { nd->nd_repstat = EPROCUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; - return (0); + return 0; } if ((nd->nd_flag & ND_NFSV3) == 0) nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; auth_type = *tl++; len = fxdr_unsigned(int, *tl++); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } + if (len < 0 || len > RPCAUTH_MAXSIZ) + return EBADRPC; nd->nd_flag &= ~ND_KERBAUTH; /* @@ -1806,22 +1819,19 @@ */ if (auth_type == rpc_auth_unix) { len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > NFS_MAXNAMLEN) { - m_freem(mrep); - return (EBADRPC); - } + if (len < 0 || len > NFS_MAXNAMLEN) + return EBADRPC; nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 3 * NFSX_UNSIGNED, errout); bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred)); nd->nd_cr.cr_ref = 1; nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); len = fxdr_unsigned(int, *tl); - if (len < 0 || len > RPCAUTH_UNIXGIDS) { - m_freem(mrep); - return (EBADRPC); - } - nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED); + if (len < 0 || len > RPCAUTH_UNIXGIDS) + return EBADRPC; + nfsm_dissect(&reqc, tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED, + errout); for (i = 1; i <= len; i++) if (i < NGROUPS) nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); @@ -1831,23 +1841,20 @@ if (nd->nd_cr.cr_ngroups > 1) nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups); len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } + if (len < 0 || len > RPCAUTH_MAXSIZ) + return EBADRPC; if (len > 0) - nfsm_adv(nfsm_rndup(len)); + nfsm_adv(&reqc, nfsm_rndup(len), errout); } else if (auth_type == rpc_auth_kerb) { + caddr_t cp; switch (fxdr_unsigned(int, *tl++)) { case RPCAKN_FULLNAME: ticklen = fxdr_unsigned(int, *tl); *((u_int32_t *)nfsd->nfsd_authstr) = *tl; uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; - if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { - m_freem(mrep); + if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) return (EBADRPC); - } uio.uio_offset = 0; uio.uio_iov = &iov; uio.uio_iovcnt = 1; @@ -1855,7 +1862,8 @@ iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4]; iov.iov_len = RPCAUTH_MAXSIZ - 4; nfsm_mtouio(&uio, uio.uio_resid); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); if (*tl++ != rpc_auth_kerb || fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { printf("Bad kerb verifier\n"); @@ -1863,7 +1871,8 @@ nd->nd_procnum = NFSPROC_NOOP; return (0); } - nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, cp, caddr_t, 4 * NFSX_UNSIGNED, + errout); tl = (u_int32_t *)cp; if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { printf("Not fullname kerb verifier\n"); @@ -1885,7 +1894,8 @@ return (0); } nickuid = fxdr_unsigned(uid_t, *tl); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); if (*tl++ != rpc_auth_kerb || fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { printf("Kerb nick verifier bad\n"); @@ -1945,7 +1955,7 @@ * For nqnfs, get piggybacked lease request. */ if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); nd->nd_flag |= fxdr_unsigned(int, *tl); if (nd->nd_flag & ND_LEASE) { nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); @@ -1954,10 +1964,11 @@ nd->nd_duration = NQ_MINLEASE; } else nd->nd_duration = NQ_MINLEASE; - nd->nd_md = md; - nd->nd_dpos = dpos; + + nd->nd_req.nc_m = req.nc_m; + nd->nd_req.nc_pos = req.nc_pos; return (0); -nfsmout: +errout: return (error); } @@ -2245,15 +2256,13 @@ free(rec, M_NFSRVDESC); MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript), M_NFSRVDESC, M_WAITOK); - nd->nd_md = nd->nd_mrep = m; + nd->nd_req.nm_mhead = nd->nd_req.nm_m = m; + nd->nd_req.nm_pos = mtod(m, caddr_t); + nd->nd_rep.nm_mhead = NULL; nd->nd_nam2 = nam; - nd->nd_dpos = mtod(m, caddr_t); error = nfs_getreq(nd, nfsd, TRUE); if (error) { - if (nam) { - FREE(nam, M_SONAME); - } - free((caddr_t)nd, M_NFSRVDESC); + nfssrv_ndfree(nd); return (error); } *ndp = nd; Index: nfs_srvcache.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_srvcache.c,v retrieving revision 1.27 diff -u -r1.27 nfs_srvcache.c --- nfs_srvcache.c 2000/12/21 21:44:24 1.27 +++ nfs_srvcache.c 2001/01/27 17:18:50 @@ -154,10 +154,9 @@ * Update/add new request at end of lru list */ int -nfsrv_getcache(nd, slp, repp) +nfsrv_getcache(nd, slp) register struct nfsrv_descript *nd; struct nfssvc_sock *slp; - struct mbuf **repp; { register struct nfsrvcache *rp; struct mbuf *mb; @@ -196,12 +195,12 @@ } else if (rp->rc_flag & RC_REPSTATUS) { nfsstats.srvcache_nonidemdonehits++; nfs_rephead(0, nd, slp, rp->rc_status, - 0, (u_quad_t *)0, repp, &mb, &bpos); + 0, (u_quad_t *)0, &nd->nd_rep); ret = RC_REPLY; } else if (rp->rc_flag & RC_REPMBUF) { nfsstats.srvcache_nonidemdonehits++; - *repp = m_copym(rp->rc_reply, 0, M_COPYALL, - M_TRYWAIT); + nd->nd_rep.nc_mhead = m_copym(rp->rc_reply, 0, + M_COPYALL, M_TRYWAIT); ret = RC_REPLY; } else { nfsstats.srvcache_idemdonehits++; @@ -268,10 +267,9 @@ * Update a request cache entry after the rpc has been done */ void -nfsrv_updatecache(nd, repvalid, repmbuf) +nfsrv_updatecache(nd, repvalid) register struct nfsrv_descript *nd; int repvalid; - struct mbuf *repmbuf; { register struct nfsrvcache *rp; @@ -312,8 +310,9 @@ rp->rc_status = nd->nd_repstat; rp->rc_flag |= RC_REPSTATUS; } else { - rp->rc_reply = m_copym(repmbuf, - 0, M_COPYALL, M_TRYWAIT); + rp->rc_reply = m_copym( + nd->nd_rep.nc_mhead, 0, M_COPYALL, + M_TRYWAIT); rp->rc_flag |= RC_REPMBUF; } } Index: nfs_subs.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_subs.c,v retrieving revision 1.98 diff -u -r1.98 nfs_subs.c --- nfs_subs.c 2000/12/21 21:44:24 1.98 +++ nfs_subs.c 2001/02/05 01:22:05 @@ -574,25 +574,32 @@ * The hsiz is the size of the rest of the nfs request header. * (just used to decide if a cluster is a good idea) */ -struct mbuf * -nfsm_reqh(vp, procid, hsiz, bposp) +int +nfs_reqhead(req, vp, procid, hsiz) + struct nfs_chain *req; struct vnode *vp; u_long procid; int hsiz; - caddr_t *bposp; { - register struct mbuf *mb; register u_int32_t *tl; - register caddr_t bpos; - struct mbuf *mb2; + struct mbuf *m; struct nfsmount *nmp; - int nqflag; + int nqflag, error; - MGET(mb, M_TRYWAIT, MT_DATA); - if (hsiz >= MINCLSIZE) - MCLGET(mb, M_TRYWAIT); - mb->m_len = 0; - bpos = mtod(mb, caddr_t); + NFSCHAIN_INIT(req); + MGET(m, M_TRYWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + if (hsiz >= MINCLSIZE) { + MCLGET(m, M_TRYWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + return (ENOBUFS); + } + } + m->m_len = 0; + req->nc_m = req->nc_mhead = m; + req->nc_pos = mtod(m, caddr_t); /* * For NQNFS, add lease request. @@ -602,29 +609,36 @@ if (nmp->nm_flag & NFSMNT_NQNFS) { nqflag = NQNFS_NEEDLEASE(vp, procid); if (nqflag) { - nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); + nfsm_build(req, tl, u_int32_t *, + 2 * NFSX_UNSIGNED, errout); *tl++ = txdr_unsigned(nqflag); *tl = txdr_unsigned(nmp->nm_leaseterm); } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(req,tl, u_int32_t *, NFSX_UNSIGNED, + errout); *tl = 0; } } } - /* Finally, return values */ - *bposp = bpos; - return (mb); + + return (0); + +errout: + NFSCHAIN_FREE(&reqc); + return (error); } /* * Build the RPC header and fill in the authorization info. + * Appends 'mrest' to the header. If mheadendp is non-null, it is set to + * point to the last mbuf in the header (the one before mrest). * The authorization string argument is only used when the credentials * come from outside of the kernel. * Returns the head of the mbuf list. */ struct mbuf * -nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, - verf_str, mrest, mrest_len, mbp, xidp) +nfs_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, + verf_str, mrest, mrest_len, mheadendp, xidp) register struct ucred *cr; int nmflag; int procid; @@ -635,9 +649,10 @@ char *verf_str; struct mbuf *mrest; int mrest_len; - struct mbuf **mbp; + struct mbuf **mheadendp; u_int32_t *xidp; { + struct nfs_chain repc; register struct mbuf *mb; register u_int32_t *tl; register caddr_t bpos; @@ -646,22 +661,22 @@ int siz, grpsiz, authsiz; authsiz = nfsm_rndup(auth_len); - MGETHDR(mb, M_TRYWAIT, MT_DATA); + MGETHDR(repc.nc_mhead, M_TRYWAIT, MT_DATA); if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { - MCLGET(mb, M_TRYWAIT); + MCLGET(repc.nc_mhead, M_TRYWAIT); } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { - MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); + MH_ALIGN(repc.nc_mhead, authsiz + 10 * NFSX_UNSIGNED); } else { - MH_ALIGN(mb, 8 * NFSX_UNSIGNED); + MH_ALIGN(repc.nc_mhead, 8 * NFSX_UNSIGNED); } - mb->m_len = 0; - mreq = mb; - bpos = mtod(mb, caddr_t); + repc.nc_mhead->m_len = 0; + repc.nc_m = repc.nc_mhead; + repc.nc_pos = mtod(repc.nc_m, caddr_t); /* * First the RPC header. */ - nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, 8 * NFSX_UNSIGNED,); /* Get a pretty random xid to start with */ if (!nfs_xid) @@ -697,7 +712,7 @@ *tl = txdr_unsigned(authsiz); switch (auth_type) { case RPCAUTH_UNIX: - nfsm_build(tl, u_int32_t *, auth_len); + nfsm_build(repc, tl, u_int32_t *, auth_len,); *tl++ = 0; /* stamp ?? */ *tl++ = 0; /* NULL hostname */ *tl++ = txdr_unsigned(cr->cr_uid); @@ -714,22 +729,22 @@ MGET(mb2, M_TRYWAIT, MT_DATA); if (siz >= MINCLSIZE) MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); + m2->m_len = 0; + repc.nc_m->m_next = mb2; + repc.nc_m = mb2; + repc.nc_pos = mtod(repc.nc_m, caddr_t); } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(auth_str, bpos, i); - mb->m_len += i; + i = min(siz, M_TRAILINGSPACE(repc.nc_m)); + bcopy(auth_str, repc.nc_pos, i); + repc.nc_m->m_len += i; auth_str += i; - bpos += i; + repc.nc_pos += i; siz -= i; } if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; + *repc.nc_pos++ = '\0'; + repc.nc_m->m_len += siz; } break; }; @@ -737,64 +752,64 @@ /* * And the verifier... */ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, 2 * NFSX_UNSIGNED,); if (verf_str) { *tl++ = txdr_unsigned(RPCAUTH_KERB4); *tl = txdr_unsigned(verf_len); siz = verf_len; while (siz > 0) { - if (M_TRAILINGSPACE(mb) == 0) { + if (M_TRAILINGSPACE(repc.nc_m) == 0) { MGET(mb2, M_TRYWAIT, MT_DATA); if (siz >= MINCLSIZE) MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); + mb2->m_len = 0; + repc.nc_m->m_next = mb2; + repc.nc_m = mb2; + repc.nc_pos = mtod(repc.nc_m, caddr_t); } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(verf_str, bpos, i); - mb->m_len += i; + i = min(siz, M_TRAILINGSPACE(repc.nc_m)); + bcopy(verf_str, repc.nc_pos, i); + repc.nc_m->m_len += i; verf_str += i; - bpos += i; + repc.nc_pos += i; siz -= i; } if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; + *repc.nc_pos++ = '\0'; + repc.nc_m->m_len += siz; } } else { *tl++ = txdr_unsigned(RPCAUTH_NULL); *tl = 0; } - mb->m_next = mrest; - mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; - mreq->m_pkthdr.rcvif = (struct ifnet *)0; - *mbp = mb; - return (mreq); + repc.nc_m->m_next = mrest; + repc.nc_m->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; + repc.nc_m->m_pkthdr.rcvif = (struct ifnet *)0; + if (mheadendp != NULL) + *mheadendp = repc.nc_m; + return (repc.nc_mhead); } /* * copies mbuf chain to the uio scatter/gather list */ int -nfsm_mbuftouio(mrep, uiop, siz, dpos) - struct mbuf **mrep; +nfs_mbuftouio(repcp, uiop, siz) + struct nfs_chain *repcp; register struct uio *uiop; int siz; - caddr_t *dpos; { + struct nfs_chain repc; register char *mbufcp, *uiocp; register int xfer, left, len; register struct mbuf *mp; long uiosiz, rem; int error = 0; - mp = *mrep; - mbufcp = *dpos; - len = mtod(mp, caddr_t)+mp->m_len-mbufcp; - rem = nfsm_rndup(siz)-siz; + repc = *repcp; + len = mtod(repc.nc_m, caddr_t) + repc.nc_m->m_len - repc.nc_pos; + rem = nfsm_rndup(siz) - siz; while (siz > 0) { if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) return (EFBIG); @@ -805,27 +820,27 @@ uiosiz = left; while (left > 0) { while (len == 0) { - mp = mp->m_next; - if (mp == NULL) + repc.nc_m = repc.nc_m->m_next; + if (repc.nc_m == NULL) return (EBADRPC); - mbufcp = mtod(mp, caddr_t); - len = mp->m_len; + repc.nc_pos = mtod(repc.nc_m, caddr_t); + len = repc.nc_m->m_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); + (repc.nc_pos, uiocp, xfer); else #endif if (uiop->uio_segflg == UIO_SYSSPACE) - bcopy(mbufcp, uiocp, xfer); + bcopy(repc.nc_pos, uiocp, xfer); else - copyout(mbufcp, uiocp, xfer); + copyout(repc.nc_pos, uiocp, xfer); left -= xfer; len -= xfer; - mbufcp += xfer; + repc.nc_pos += xfer; uiocp += xfer; uiop->uio_offset += xfer; uiop->uio_resid -= xfer; @@ -839,14 +854,13 @@ } siz -= uiosiz; } - *dpos = mbufcp; - *mrep = mp; if (rem > 0) { if (len < rem) - error = nfs_adv(mrep, dpos, rem, len); + error = nfs_adv(&repc, rem, len); else - *dpos += rem; + repc.nc_pos += rem; } + *repcp = repc; return (error); } @@ -855,14 +869,14 @@ * NOTE: can ony handle iovcnt == 1 */ int -nfsm_uiotombuf(uiop, mq, siz, bpos) +nfs_uiotombuf(uiop, reqcp, siz) register struct uio *uiop; - struct mbuf **mq; + struct nfs_chain *reqcp; int siz; - caddr_t *bpos; { + struct nfs_chain reqc; + struct mbuf *m; register char *uiocp; - register struct mbuf *mp, *mp2; register int xfer, left, mlen; int uiosiz, clflg, rem; char *cp; @@ -877,7 +891,7 @@ else clflg = 0; rem = nfsm_rndup(siz)-siz; - mp = mp2 = *mq; + reqc = *reqcp; while (siz > 0) { left = uiop->uio_iov->iov_len; uiocp = uiop->uio_iov->iov_base; @@ -885,29 +899,31 @@ left = siz; uiosiz = left; while (left > 0) { - mlen = M_TRAILINGSPACE(mp); + mlen = M_TRAILINGSPACE(reqc.nc_m); if (mlen == 0) { - MGET(mp, M_TRYWAIT, MT_DATA); + MGET(m, M_TRYWAIT, MT_DATA); if (clflg) - MCLGET(mp, M_TRYWAIT); - mp->m_len = 0; - mp2->m_next = mp; - mp2 = mp; - mlen = M_TRAILINGSPACE(mp); + MCLGET(m, M_TRYWAIT); + m->m_len = 0; + reqc.nc_m->m_next = m; + reqc.nc_m = m; + reqc.nc_pos = mtod(reqc.nc_m, caddr_t); + mlen = M_TRAILINGSPACE(reqc.nc_m); } xfer = (left > mlen) ? mlen : left; #ifdef notdef /* Not Yet.. */ if (uiop->uio_iov->iov_op != NULL) (*(uiop->uio_iov->iov_op)) - (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); + (uiocp, reqc.nc_pos, xfer); else #endif if (uiop->uio_segflg == UIO_SYSSPACE) - bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); + bcopy(uiocp, reqc.nc_pos, xfer); else - copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - mp->m_len += xfer; + copyin(uiocp, reqc.nc_pos, xfer); + reqc.nc_m->m_len += xfer; + reqc.nc_pos += xfer; left -= xfer; uiocp += xfer; uiop->uio_offset += xfer; @@ -918,122 +934,282 @@ siz -= uiosiz; } if (rem > 0) { - if (rem > M_TRAILINGSPACE(mp)) { - MGET(mp, M_TRYWAIT, MT_DATA); - mp->m_len = 0; - mp2->m_next = mp; - } - cp = mtod(mp, caddr_t)+mp->m_len; + caddr_t cp; + nfsm_build(&reqc, cp, caddr_t, rem,); for (left = 0; left < rem; left++) *cp++ = '\0'; - mp->m_len += rem; - *bpos = cp; - } else - *bpos = mtod(mp, caddr_t)+mp->m_len; - *mq = mp; + } + *reqcp = reqc; return (0); } /* - * Help break down an mbuf chain by setting the first siz bytes contiguous - * pointed to by returned val. - * This is used by the macros nfsm_dissect and nfsm_dissecton for tough - * cases. (The macros use the vars. dpos and dpos2) + * Add mbufs/clusters to the chain until there is room for 'size' + * bytes. Set up uiop to be ready for a read to this space. + * + * If iovp is NULL, the caller is assumed to have made available + * a fixed-size iov array with a start and size specified in uio_iov + * and uio_iovcnt. + * + * Otherwise, this routine ignores uio_iov and uio_iovcnt. Instead it + * malloc's a sufficiently large region, and stores the start of this + * region in *iovp. The caller should free this space (type M_TEMP) + * after use. *iovp is guaranteed to be set to NULL if no iovec + * allocation was performed. + * + * Returns 0 on success or: + * ENOBUFS The operation failed due to a shortage of mbufs. Note + * that some mbufs may have been added to the chain. + * + * This routine sets up all fields of uiop except uio_offset, and + * uio_procp; these should be initialised by the caller. */ int -nfsm_disct(mdp, dposp, siz, left, cp2) - struct mbuf **mdp; - caddr_t *dposp; - int siz; - int left; - caddr_t *cp2; +nfs_getmuio(ncp, uiop, size, iovp) + struct nfs_chain *ncp; + struct uio *uiop; + int size; + struct iovec **iovp; +{ + struct mbuf *m, *mhead; + struct iovec *iv; + int left, n, i; + + uiop->uio_iov = NULL; + if (iovp != NULL) + *iovp = NULL; + + m = mhead = ncp->nc_m; + left = size; + i = 0; + while (left > 0) { + if (m != NULL) { + n = min(M_TRAILINGSPACE(m), left); + if (n > 0) { + left -= size; + i++; + } + } + if (left > 0) { + MGET(m, M_TRYWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + if (left >= MINCLSIZE) { + MCLGET(m, M_TRYWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + return (ENOBUFS); + } + } + m->m_len = 0; + NFSCHAIN_APPENDM(ncp, m); + } + } + if (iovp != NULL) { + MALLOC(iv, struct iovec *, i * sizeof(struct iovec), M_TEMP, + M_WAITOK); + *iovp = iv; + } else { + if (i > uiop->uio_iovcnt) + panic("nfs_getmuio iovcnt"); + iv = uiop->uio_iov; + } + + m = (mhead == NULL) ? ncp->nc_mhead : mhead; + left = len; + i = 0; + while (left > 0) { + if (m == NULL) + panic("nfs_getmuio iov"); + n = min(M_TRAILINGSPACE(m), left); + if (n > 0) { + iv->iov_base = mtod(m, char *) + m->m_len; + iv->iov_len = n; + m->len += n; + ncp->nc_m = iv->iov_base + n; + left -= n; + iv++; + i++; + } + m = m->next; + } + ncp->nc_pos = mtod(ncp->nc_m, char *) + ncp->nc_m->m_len; + uiop->uio_iov = iv; + uiop->uio_iovcnt = i; + uiop->uio_resid = size; + uiop->uio_rw = UIO_READ; + uiop->uio_segflg = UIO_SYSSPACE; + + return (0); +} + +/* + * Help break down an mbuf chain by setting the first 'size' bytes + * contiguous. *startp is set to point to the first byte, and the + * current position in the chain is advanced by 'size'. Returns 0 + * on success, or: + * + * EBADRPC 'size' bytes were not found in the chain. + * ENOBUFS An attempt to allocate mbufs failed. + */ +int +nfs_dissect(struct nfs_chain *ncp, int size, void *startp) { - register struct mbuf *mp, *mp2; - register int siz2, xfer; - register caddr_t p; + struct nfs_chain nc; + struct mbuf *m; + int siz2, xfer; + u_char *p, *start; + int left; - mp = *mdp; + left = mtod(ncp->nc_m, u_char *) + ncp->nc_m->m_len - ncp->nc_pos; + /* Optimise the simple case. */ + if (left > size) { + *(void **)startp = ncp->nc_pos; + ncp->nc_pos += size; + return (0); + } + + nc = *ncp; while (left == 0) { - *mdp = mp = mp->m_next; - if (mp == NULL) + nc.nc_m = nc.nc_m->m_next; + if (nc.nc_m == NULL) return (EBADRPC); - left = mp->m_len; - *dposp = mtod(mp, caddr_t); + left = nc.nc_m->m_len; + nc.nc_pos = mtod(nc.nc_m, caddr_t); } if (left >= siz) { - *cp2 = *dposp; - *dposp += siz; + start = nc.nc_pos; + nc.nc_pos += siz; } else if (mp->m_next == NULL) { return (EBADRPC); } else if (siz > MHLEN) { - panic("nfs S too big"); + panic("nfs dissect size too big"); } else { - MGET(mp2, M_TRYWAIT, MT_DATA); - mp2->m_next = mp->m_next; - mp->m_next = mp2; - mp->m_len -= left; - mp = mp2; - *cp2 = p = mtod(mp, caddr_t); - bcopy(*dposp, p, left); /* Copy what was left */ - siz2 = siz-left; + mget(m, M_TRYWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + m->m_next = nc.nc_m->m_next; + nc.nc_m->m_next = m; + nc.nc_m->m_len -= left; + nc.nc_m = m; + start = p = mtod(nc.nc_m, caddr_t); + bcopy(nc.nc_pos, p, left); /* Copy what was left */ + siz2 = siz - left; p += left; - mp2 = mp->m_next; + m = m->m_next; /* Loop around copying up the siz2 bytes */ while (siz2 > 0) { - if (mp2 == NULL) + if (m == NULL) return (EBADRPC); - xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; + xfer = (siz2 > m->m_len) ? m->m_len : siz2; if (xfer > 0) { - bcopy(mtod(mp2, caddr_t), p, xfer); - NFSMADV(mp2, xfer); - mp2->m_len -= xfer; + bcopy(mtod(m, caddr_t), p, xfer); + NFSMADV(m, xfer); + m->m_len -= xfer; p += xfer; siz2 -= xfer; } if (siz2 > 0) - mp2 = mp2->m_next; + m = m->m_next; } - mp->m_len = siz; - *mdp = mp2; - *dposp = mtod(mp2, caddr_t); + nc.nc_m->m_len = siz; + nc.nc_m = m; + nc.nc_pos = mtod(m, caddr_t); } + *ncp = nc; + *(void **)startp = start; return (0); } +int +nfs_fhtom(struct nfs_chain *ncp, struct vnode *vp, int isv3) { + int error = 0; + if (isv3) { + int32_t fhlen; + u_int32_t *tl; + fhlen = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED; + if (fhlen <= M_TRAILINGSPACE(nc->nc_m)) { + if ((error = nfs_build(ncp, fhlen, &tl)) != 0) + goto errout; + *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize); + *(tl + ((fhlen >> 2) - 2)) = 0; + bcopy(VTONFS(vp)->n_fhp, tl, VTONFS(vp)->n_fhsize); + } else if ((error = nfsm_strtmbuf(ncp, + (caddr_t)VTONFS(vp)->n_fhp, VTONFS(vp)->n_fhsize)) != 0) + goto errout; + } else { + caddr_t cp; + if ((error = nfs_build(ncp, NFSX_V2FH, &cp)) != 0) + goto errout; + bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH); + } +errout: + return (error); +} + /* - * Advance the position in the mbuf chain. + * Advance the position in the mbuf chain by 'size' bytes. Returns 0 + * on success, or: + * + * EBADRPC Less than 'size' bytes were in the chain. */ int -nfs_adv(mdp, dposp, offs, left) - struct mbuf **mdp; - caddr_t *dposp; - int offs; - int left; +nfs_adv(struct nfs_chain *ncp, int size) { - register struct mbuf *m; - register int s; + struct mbuf *m; + int s; - m = *mdp; - s = left; + m = ncp->nc_m; + s = mtod(m, u_char *) + m->m_len - ncp->nc_pos; while (s < offs) { offs -= s; m = m->m_next; if (m == NULL) return (EBADRPC); s = m->m_len; + } + ncp->nc_m = m; + ncp->nc_pos = mtod(m, u_char *) + offs; + return (0); +} + +/* + * Allocate 'size' contiguous bytes at the current position in the chain, + * adding more mbufs as needed. Stores a pointer to this space in *spacep, + * and advances the current chain pointer. Returns 0 on success, or: + * + * ENOBUFS An mbuf allocation failed. + */ +int +nfs_build(struct nfs_chain *ncp, int size, void *spacep) +{ + struct mbuf *m; + + if (size > M_TRAILINGSPACE(ncp->nc_m)) { + MGET(m, M_TRYWAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + if (size > MLEN) + panic("nfs_build: > MLEN"); + ncp->nc_m->m_next = m; + ncp->nc_m = m; + m->m_len = 0; + ncp->nc_pos = mtod(m, u_char *); } - *mdp = m; - *dposp = mtod(m, caddr_t)+offs; + *(void **)spacep = ncp->nc_pos; + ncp->nc_pos += size; + ncp->nc_m->m_len += size; + return (0); } + /* * Copy a string into mbufs for the hard cases... */ int -nfsm_strtmbuf(mb, bpos, cp, siz) - struct mbuf **mb; - char **bpos; +nfs_strtmbuf(ncp, cp, siz) + struct nfs_chain *ncp; const char *cp; long siz; { @@ -1043,10 +1219,10 @@ int putsize; putsize = 1; - m2 = *mb; + m2 = ncp->nc_m; left = M_TRAILINGSPACE(m2); if (left > 0) { - tl = ((u_int32_t *)(*bpos)); + tl = ((u_int32_t *)(ncp->nc_pos)); *tl++ = txdr_unsigned(siz); putsize = 0; left -= NFSX_UNSIGNED; @@ -1088,8 +1264,8 @@ siz -= xfer; cp += xfer; } - *mb = m1; - *bpos = mtod(m1, caddr_t)+m1->m_len; + ncp->nc_m = m1; + ncp->nc_pos = mtod(m1, caddr_t)+m1->m_len; return (0); } @@ -1203,10 +1379,9 @@ * copy the attributes to *vaper */ int -nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink) +nfs_loadattrcache(vpp, ncp, vaper, dontshrink) struct vnode **vpp; - struct mbuf **mdp; - caddr_t *dposp; + struct nfs_chain *ncp; struct vattr *vaper; int dontshrink; { @@ -1223,9 +1398,9 @@ struct timespec mtime; int v3 = NFS_ISV3(vp); - md = *mdp; - t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; - if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) + md = ncp->nc_m; + t1 = (mtod(md, caddr_t) + md->m_len) - ncp->nc_pos; + if ((error = nfsm_disct(ncp, NFSX_FATTR(v3), t1, &cp2)) != 0) return (error); fp = (struct nfs_fattr *)cp2; if (v3) { @@ -1464,14 +1639,13 @@ * released by the caller. */ int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) +nfs_namei(ndp, fhp, len, slp, nam, reqcp, retdirp, p, kerbflag, pubflag) register struct nameidata *ndp; fhandle_t *fhp; int len; struct nfssvc_sock *slp; struct sockaddr *nam; - struct mbuf **mdp; - caddr_t *dposp; + struct nfs_chain *reqcp; struct vnode **retdirp; struct proc *p; int kerbflag, pubflag; @@ -1492,9 +1666,9 @@ * Copy the name from the mbuf list to ndp->ni_pnbuf * and set the various ndp fields appropriately. */ - fromcp = *dposp; + fromcp = reqcp->nc_pos; tocp = cnp->cn_pnbuf; - md = *mdp; + md = reqcp->nc_m; rem = mtod(md, caddr_t) + md->m_len - fromcp; for (i = 0; i < len; i++) { while (rem == 0) { @@ -1514,13 +1688,13 @@ rem--; } *tocp = '\0'; - *mdp = md; - *dposp = fromcp; + reqcp->nc_m = md; + reqcp->nc_pos = fromcp; len = nfsm_rndup(len)-len; if (len > 0) { if (rem >= len) - *dposp += len; - else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) + reqc.nc_pos += len; + else if ((error = nfs_adv(reqcp, len, rem)) != 0) goto out; } @@ -1745,7 +1919,7 @@ * boundary and only trims off the back end */ void -nfsm_adj(mp, len, nul) +nfs_adj(mp, len, nul) struct mbuf *mp; register int len; int nul; @@ -1807,24 +1981,24 @@ * doesn't get too big... */ void -nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) +nfs_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, repcp) struct nfsrv_descript *nfsd; int before_ret; register struct vattr *before_vap; int after_ret; struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; + struct nfs_chain *repcp; { - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; + struct nfs_chain repc; register u_int32_t *tl; + + repc = *repcp; if (before_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, NFSX_UNSIGNED,); *tl = nfs_false; } else { - nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, 7 * NFSX_UNSIGNED,); *tl++ = nfs_true; txdr_hyper(before_vap->va_size, tl); tl += 2; @@ -1832,39 +2006,38 @@ tl += 2; txdr_nfsv3time(&(before_vap->va_ctime), tl); } - *bposp = bpos; - *mbp = mb; - nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); + + *repcp = repc; + nfsm_srvpostopattr(nfsd, after_ret, after_vap, repcp); } void -nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) +nfs_srvpostopattr(nfsd, after_ret, after_vap, repcp) struct nfsrv_descript *nfsd; int after_ret; struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; + struct nfs_chain *repcp; { - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; + struct nfs_chain *repc; register u_int32_t *tl; register struct nfs_fattr *fp; + repc = *repcp; if (after_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&repc, tl, u_int32_t *, NFSX_UNSIGNED,); *tl = nfs_false; } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); + nfsm_build(&repc, tl, u_int32_t *, + NFSX_UNSIGNED + NFSX_V3FATTR,); *tl++ = nfs_true; fp = (struct nfs_fattr *)tl; - nfsm_srvfattr(nfsd, after_vap, fp); + nfs_srvfattr(nfsd, after_vap, fp); } - *mbp = mb; - *bposp = bpos; + *repcp = repc; } void -nfsm_srvfattr(nfsd, vap, fp) +nfs_srvfillattr(nfsd, vap, fp) register struct nfsrv_descript *nfsd; register struct vattr *vap; register struct nfs_fattr *fp; @@ -1905,12 +2078,76 @@ } } +int +nfs_srvsattr(struct nfs_chain *ncp, struct vattr *vap) +{ + int error; + u_int32_t tl; + + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + if (*tl == nfs_true) { + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + vap->va_mode = nfstov_mode(*tl); + } + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + if (*tl == nfs_true) { + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + vap->va_uid = fxdr_unsigned(uid_t, *tl); + } + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + if (*tl == nfs_true) { + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + vap->va_gid = fxdr_unsigned(gid_t, *tl); + } + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + if (*tl == nfs_true) { + if ((error = nfs_dissect(ncp, 2 * NFSX_UNSIGNED, &tl)) != 0) + return (error); + vap->va_size = fxdr_hyper(tl); + } + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + switch (fxdr_unsigned(int, *tl)) { + case NFSV3SATTRTIME_TOCLIENT: + if ((error = nfs_dissect(ncp, 2 * NFSX_UNSIGNED, &tl)) != 0) + return (error); + fxdr_nfsv3time(tl, &vap->va_atime); + break; + + case NFSV3SATTRTIME_TOSERVER: + getnanotime(&vap->va_atime); + break; + }; + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + switch (fxdr_unsigned(int, *tl)) { + case NFSV3SATTRTIME_TOCLIENT: + if ((error = nfs_dissect(ncp, 2 * NFSX_UNSIGNED, &tl)) != 0) + return (error); + fxdr_nfsv3time(tl, vap->va_mtime); + break; + case NFSV3SATTRTIME_TOSERVER: + getnanotime(&vap->va_mtime); + break; + } + + return (0); +} + /* * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) * - look up fsid in mount list (if not found ret error) * - get vp and export rights by calling VFS_FHTOVP() * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon * - if not lockflag unlock it with VOP_UNLOCK() + * - *vpp is set to NULL on failure */ int nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) @@ -1928,6 +2165,7 @@ register struct mount *mp; register int i; struct ucred *credanon; + struct vnode *vp; int error, exflags; #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ struct sockaddr_int *saddr; @@ -1947,7 +2185,7 @@ error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); if (error) return (error); - error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); + error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp); if (error) return (error); #ifdef MNT_EXNORESPORT @@ -1955,8 +2193,7 @@ saddr = (struct sockaddr_in *)nam; if (saddr->sin_family == AF_INET && ntohs(saddr->sin_port) >= IPPORT_RESERVED) { - vput(*vpp); - *vpp = NULL; + vput(vp); return (NFSERR_AUTHERR | AUTH_TOOWEAK); } } @@ -1966,13 +2203,11 @@ */ if (exflags & MNT_EXKERB) { if (!kerbflag) { - vput(*vpp); - *vpp = NULL; + vput(vp); return (NFSERR_AUTHERR | AUTH_TOOWEAK); } } else if (kerbflag) { - vput(*vpp); - *vpp = NULL; + vput(vp); return (NFSERR_AUTHERR | AUTH_TOOWEAK); } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { cred->cr_uid = credanon->cr_uid; @@ -1985,10 +2220,11 @@ else *rdonlyp = 0; - nfsrv_object_create(*vpp); + nfsrv_object_create(vp); if (!lockflag) - VOP_UNLOCK(*vpp, 0, p); + VOP_UNLOCK(vp, 0, p); + *vpp = vp; return (0); } @@ -2236,4 +2472,71 @@ outcred->cr_groups[i] = incred->cr_groups[i]; nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); } + +/* + * Append NFS file handle 'fhp' to the chain. 'isv3' indicates whether NFSV3 + * format is used. + */ +void +nfs_srvfhtom(struct nfs_chain *ncp, fhandle_t *fhp, int isv3) { + if (v3) { + u_int32_t *tl; + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FH,); + *tl++ = txdr_unsigned(NFSX_V3FH); + bcopy(fhp, tl, NFSX_V3FH); + } else { + u_char *cp; + nfsm_build(ncp, cp, u_char *, NFSX_V2FH,); + bcopy(fhp, cp, NFSX_V2FH); + } +} + +/* + * Extract a NFS file handle from the chain. 'isv3' indicates whether + * a NFSV3 handle is expected. Returns 0 on success, or: + * + * EBADRPC The filehandle was truncated or had an unexpected length. + * ENOBUFS A mbuf allocation failed (in nfs_dissect). + */ +int +nfs_srvmtofh(struct nfs_chain *ncp, fhandle_t *fhp, int isv3) { + int fhlen; + u_int32_t tl; + int error; + + if (isv3) { + if ((error = nfs_dissect(ncp, NFSX_UNSIGNED, &tl)) != 0) + return (error); + fhlen = fxdr_unsigned(int, *tl); + if (fhlen != 0 && fhlen != NFSX_V3FH) + return (EBADRPC); + } else { + fhlen = NFSX_V2FH; + } + if (fhlen != 0) { + if ((error = nfs_dissect(ncp, fhlen, &tl)) != 0) + return (error); + bcopy(tl, fhp, fhlen); + } else { + bzero(fhp, NFSX_V3FH); + } + return (0); +} + +/* + * Free a nfs_descript structure + */ +void +nfssrv_ndfree(nd) + struct nfs_descript *nd; +{ + if (nd->nd_req.nc_mhead != NULL) + m_freem(nd->nd_req.nc_mhead); + if (nd->nd_rep.nc_mhead != NULL) /* XXX Shouldn't happen */ + m_freem(nd->nd_rep.nc_mhead); + if (nd->nd_nam2 != NULL) + free(nd->nd_nam2, M_SONAME); + free(nd, M_NFSRVDESC); +} + #endif /* NFS_NOSERVER */ Index: nfs_syscalls.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_syscalls.c,v retrieving revision 1.64 diff -u -r1.64 nfs_syscalls.c --- nfs_syscalls.c 2000/12/21 21:44:24 1.64 +++ nfs_syscalls.c 2001/01/27 17:18:51 @@ -392,6 +392,7 @@ M_WAITOK | M_ZERO); STAILQ_INIT(&slp->ns_rec); TAILQ_INIT(&slp->ns_uidlruhead); + LIST_INIT(&slp->ns_tq); TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); slp->ns_so = so; @@ -422,7 +423,6 @@ register struct nfssvc_sock *slp; struct nfsd *nfsd = nsd->nsd_nfsd; struct nfsrv_descript *nd = NULL; - struct mbuf *m, *mreq; int error = 0, cacherep, s, sotype, writes_todo; int procrastinate; u_quad_t cur_usec; @@ -500,6 +500,10 @@ } if (error || (slp->ns_flag & SLP_VALID) == 0) { if (nd) { + if (nd->nd_req.nc_mhead != NULL) + m_freem(nd->nd_req.nc_mhead); + if (nd->nd_nam2 != NULL) + free(nd->nd_nam2, M_SONAME); free((caddr_t)nd, M_NFSRVDESC); nd = NULL; } @@ -535,7 +539,7 @@ return (ENEEDAUTH); cacherep = RC_DROPIT; } else - cacherep = nfsrv_getcache(nd, slp, &mreq); + cacherep = nfsrv_getcache(nd, slp); /* * Check for just starting up for NQNFS and send @@ -583,8 +587,10 @@ } /* - * Loop to get all the write rpc relies that have been + * Loop to get all the write rpc replies that have been * gathered together. + * At this point, either nd will point to a valid request + * descriptor, or writes_todo will be true (or both). */ do { switch (cacherep) { @@ -594,27 +600,30 @@ else procrastinate = nfsrvw_procrastinate; if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && - procrastinate > 0 && !notstarted)) + procrastinate > 0 && !notstarted)) { + /* + * nfsrv_writegather will change nd to whatever + * descriptor it wants us to complete, or NULL. + */ error = nfsrv_writegather(&nd, slp, - nfsd->nfsd_procp, &mreq); - else + nfsd->nfsd_procp); + } else { error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, - slp, nfsd->nfsd_procp, &mreq); - if (mreq == NULL) + slp, nfsd->nfsd_proc); + } + if (nd == NULL || nd->nd_rep.nc_mhead == NULL) break; if (error != 0 && error != NFSERR_RETVOID) { if (nd->nd_procnum != NQNFSPROC_VACATED) nfsstats.srv_errs++; - nfsrv_updatecache(nd, FALSE, mreq); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); + nfsrv_updatecache(nd, FALSE); break; } nfsstats.srvrpccnt[nd->nd_procnum]++; - nfsrv_updatecache(nd, TRUE, mreq); - nd->nd_mrep = (struct mbuf *)0; + nfsrv_updatecache(nd, TRUE); + /* FALLTHROUGH */ case RC_REPLY: - m = mreq; + m = nd->nd_rep.nc_mhead; siz = 0; while (m) { siz += m->m_len; @@ -624,7 +633,8 @@ printf("mbuf siz=%d\n",siz); panic("Bad nfs svc reply"); } - m = mreq; + m = nd->nd_rep.nc_mhead; + nd->nd_rep.nc_mhead = NULL; m->m_pkthdr.len = siz; m->m_pkthdr.rcvif = (struct ifnet *)0; /* @@ -645,16 +655,12 @@ } if (nfsrtton) nfsd_rt(sotype, nd, cacherep); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); - if (nd->nd_mrep) - m_freem(nd->nd_mrep); if (error == EPIPE) nfsrv_zapsock(slp); if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) nfs_slpunlock(slp); if (error == EINTR || error == ERESTART) { - free((caddr_t)nd, M_NFSRVDESC); + nfssrv_ndfree(nd); nfsrv_slpderef(slp); s = splnet(); goto done; @@ -663,13 +669,10 @@ case RC_DROPIT: if (nfsrtton) nfsd_rt(sotype, nd, cacherep); - m_freem(nd->nd_mrep); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); break; }; if (nd) { - FREE((caddr_t)nd, M_NFSRVDESC); + nfssrv_ndfree(nd); nd = NULL; } @@ -755,7 +758,7 @@ for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { nnwp = nwp->nd_tq.le_next; LIST_REMOVE(nwp, nd_tq); - free((caddr_t)nwp, M_NFSRVDESC); + nfssrv_ndfree(nwp); } LIST_INIT(&slp->ns_tq); splx(s); @@ -849,20 +852,6 @@ TAILQ_INIT(&nfsd_head); nfsd_head_flag &= ~NFSD_CHECKSLP; - -#if 0 - nfs_udpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_udpsock->ns_rec); - TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); - TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); - - nfs_cltpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_cltpsock->ns_rec); - TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); - TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); -#endif } /* @@ -1117,14 +1106,12 @@ * Save the current nickname in a hash list entry on the mount point. */ int -nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) +nfs_savenickauth(nmp, cred, len, key, repcp) register struct nfsmount *nmp; struct ucred *cred; int len; NFSKERBKEY_T key; - struct mbuf **mdp; - char **dposp; - struct mbuf *mrep; + struct nfs_chain *repcp; { register struct nfsuid *nuidp; register u_int32_t *tl; @@ -1136,7 +1123,7 @@ int deltasec, error = 0; if (len == (3 * NFSX_UNSIGNED)) { - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + nfsm_dissect(repcp, tl, u_int32_t *, 3 * NFSX_UNSIGNED, errout); ktvin.tv_sec = *tl++; ktvin.tv_usec = *tl++; nick = fxdr_unsigned(u_int32_t, *tl); @@ -1179,9 +1166,7 @@ nuidp, nu_hash); } } else - nfsm_adv(nfsm_rndup(len)); -nfsmout: - *mdp = md; - *dposp = dpos; + nfsm_adv(repcp, nfsm_rndup(len), errout); +errout: return (error); } Index: nfs_vfsops.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_vfsops.c,v retrieving revision 1.93 diff -u -r1.93 nfs_vfsops.c --- nfs_vfsops.c 2000/11/14 08:00:39 1.93 +++ nfs_vfsops.c 2001/01/27 17:18:51 @@ -245,15 +245,12 @@ register struct statfs *sbp; struct proc *p; { + struct nfs_chain repc, reqc; register struct vnode *vp; register struct nfs_statfs *sfp; - register caddr_t cp; register u_int32_t *tl; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; struct nfsmount *nmp = VFSTONFS(mp); int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct ucred *cred; struct nfsnode *np; u_quad_t tquad; @@ -270,17 +267,15 @@ if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) (void)nfs_fsinfo(nmp, vp, cred, p); nfsstats.rpccnt[NFSPROC_FSSTAT]++; - nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_FSSTAT, p, cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_FSSTAT, NFSX_FH(v3), errout); + nfsm_fhtom(&reqc, vp, v3, errout); + nfsm_request(&reqc, &repc, vp, NFSPROC_FSSTAT, p, cred, errout); if (v3) - nfsm_postop_attr(vp, retattr); - if (error) { - if (mrep != NULL) - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); + nfs_postop_attr(nfsd, vp, retattr, &repc); + if (error) + goto errout; + nfsm_dissect(&repc, sfp, struct nfs_statfs *, NFSX_STATFS(v3), errout); sbp->f_flags = nmp->nm_flag; sbp->f_iosize = nfs_iosize(nmp); if (v3) { @@ -308,7 +303,9 @@ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); vput(vp); crfree(cred); return (error); @@ -324,22 +321,21 @@ struct ucred *cred; struct proc *p; { + struct nfs_chain repc, reqc; register struct nfsv3_fsinfo *fsp; - register caddr_t cp; - register int32_t t1, t2; register u_int32_t *tl, pref, max; - caddr_t bpos, dpos, cp2; int error = 0, retattr; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; u_int64_t maxfsize; nfsstats.rpccnt[NFSPROC_FSINFO]++; - nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - nfsm_request(vp, NFSPROC_FSINFO, p, cred); - nfsm_postop_attr(vp, retattr); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_FSINFO, NFSX_FH(1), errout); + nfsm_fhtom(&reqc, vp, 1, errout); + nfsm_request(&reqc, &repc, vp, NFSPROC_FSINFO, p, cred, errout); + nfs_postop_attr(nfsd, vp, retattr, &repc); if (!error) { - nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO); + nfsm_dissect(&repc, fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO, + errout); pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref); if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE) nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & @@ -374,7 +370,9 @@ nmp->nm_maxfilesize = maxfsize; nmp->nm_state |= NFSSTA_GOTFSINFO; } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } Index: nfs_vnops.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfs_vnops.c,v retrieving revision 1.163 diff -u -r1.163 nfs_vnops.c --- nfs_vnops.c 2001/01/04 22:45:19 1.163 +++ nfs_vnops.c 2001/01/27 17:18:51 @@ -40,6 +40,35 @@ /* * vnode op calls for Sun NFS version 2 and 3 + * + * RPC functions take the general form + * struct nfs_chain reqc, repc; * Request and reply mbuf chains * + * repc.nc_mhead = NULL; * In case an error happens early * + * + * nfsm_reqhead(&reqc, ..., errout); * Create the request * + * nfsm_build(...) * Add bits to it * + * + * nfsm_request(&reqc, &repc, ...) * Send the RPC * + * + * nfsm_dissect(...) * Get bits from the reply * + *errout: + * NFSCHAIN_FREE(&reqc); * In case of early errors, free req * + * NFSCHAIN_FREE(&repc); * Free the reply * + * return error; + * + * Notes: + * 1) If there is no possibility that errors can occur before the + * nfsm_request() call, then both the initialisation of + * repc.nc_mhead and the NFSCHAIN_FREE(&reqc) call may be + * omitted. Currently nfsm_reqhead(), nfsm_build() and + * nfsm_fhtom() can't fail. + * + * 2) With NFSV2, nfsm_request() will goto the error label if + * any kind of error occurs. With V3, however, nfsm_request() + * will return with 'error' containing the server error code, + * and repc will contain the error reply, so 'error == 0' does + * _not_ indicate that there is no reply to be freed. Protocol + * errors still goto the error label. */ #include "opt_inet.h" @@ -277,29 +306,29 @@ const int v3 = 1; u_int32_t *tl; int error = 0, attrflag; - - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - caddr_t bpos, dpos, cp2; - register int32_t t1, t2; - register caddr_t cp; + struct nfs_chain reqc, repc; u_int32_t rmode; struct nfsnode *np = VTONFS(vp); nfsstats.rpccnt[NFSPROC_ACCESS]++; - nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED); - nfsm_fhtom(vp, v3); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED, + errout); + nfsm_fhtom(&reqc, vp, v3, errout); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); *tl = txdr_unsigned(wmode); - nfsm_request(vp, NFSPROC_ACCESS, p, cred); - nfsm_postop_attr(vp, attrflag); + nfsm_request(&reqc, &repc, vp, NFSPROC_ACCESS, p, cred, errout); + nfsm_postop_attr(&repc, &vp, attrflag, errout); if (!error) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, errout); rmode = fxdr_unsigned(u_int32_t, *tl); np->n_mode = rmode; np->n_modeuid = cred->cr_uid; np->n_modestamp = time_second; } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return error; } @@ -613,9 +642,8 @@ register caddr_t cp; register u_int32_t *tl; register int32_t t1, t2; - caddr_t bpos, dpos; + struct nfs_chain reqc, repc; int error = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(vp); /* @@ -637,14 +665,18 @@ } nfsstats.rpccnt[NFSPROC_GETATTR]++; - nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_GETATTR, NFSX_FH(v3), errout); + nfsm_fhtom(&reqc, vp, v3, errout); + nfsm_request(&reqc, &repc, vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred, + errout); if (!error) { - nfsm_loadattr(vp, ap->a_vap); + nfsm_loadattr(&repc, vp, ap->a_vap, errout); } - nfsm_reqdone; - return (error); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); + return error; } /* @@ -748,23 +780,23 @@ struct proc *procp; { register struct nfsv2_sattr *sp; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; + struct nfs_chain reqc, repc; u_int32_t *tl; int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(vp); nfsstats.rpccnt[NFSPROC_SETATTR]++; - nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3)); - nfsm_fhtom(vp, v3); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3), + errout); + nfsm_fhtom(&reqc, vp, v3, errout); if (v3) { - nfsm_v3attrbuild(vap, TRUE); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_v3attrbuild(&reqc, vap, TRUE, errout); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); *tl = nfs_false; } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_build(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); if (vap->va_mode == (mode_t)VNOVAL) sp->sa_mode = nfs_xdrneg1; else @@ -781,13 +813,16 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(vp, NFSPROC_SETATTR, procp, cred); + nfsm_request(&reqc, &repc, vp, NFSPROC_SETATTR, procp, cred, errout); if (v3) { - nfsm_wcc_data(vp, wccflag); + /* XXX supposed to do this on errors too? */ + nfsm_wcc_data(&repc, vp, wccflag, errout); } else - nfsm_loadattr(vp, (struct vattr *)0); - nfsm_reqdone; - return (error); + nfsm_loadattr(&repc, vp, (struct vattr *)0, errout); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); + return error; } /* @@ -804,6 +839,7 @@ struct componentname *a_cnp; } */ *ap; { + struct nfs_chain reqc, repc; struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; @@ -887,7 +923,7 @@ *vpp = NULLVP; if (error) { cnp->cn_flags |= PDIRUNLOCK; - return (error); + goto out1; } cnp->cn_flags &= ~PDIRUNLOCK; } @@ -895,46 +931,44 @@ newvp = NULLVP; nfsstats.lookupcache_misses++; nfsstats.rpccnt[NFSPROC_LOOKUP]++; + NFSCHAIN_INIT(&repc); len = cnp->cn_namelen; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred); + nfsm_reqhead(&reqc, dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, len, NFS_MAXNAMLEN, errout); + nfsm_request(&reqc, &repc, dvp, NFSPROC_LOOKUP, cnp->cn_proc, + cnp->cn_cred, errout); if (error) { - nfsm_postop_attr(dvp, attrflag); - m_freem(mrep); - goto nfsmout; + nfsm_postop_attr(&repc, dvp, attrflag, errout); + goto errout; } - nfsm_getfh(fhp, fhsize, v3); + nfsm_getfh(&repc, fhp, fhsize, v3, errout); /* * Handle RENAME case... */ if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { if (NFS_CMPFH(np, fhp, fhsize)) { - m_freem(mrep); - return (EISDIR); + error = EISDIR; + goto out1; } error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - if (error) { - m_freem(mrep); - return (error); - } + if (error) + goto out1; newvp = NFSTOV(np); if (v3) { - nfsm_postop_attr(newvp, attrflag); - nfsm_postop_attr(dvp, attrflag); + nfsm_postop_attr(&repc, newvp, attrflag, errout); + nfsm_postop_attr(&repc, dvp, attrflag, errout); } else - nfsm_loadattr(newvp, (struct vattr *)0); + nfsm_loadattr(&repc, newvp, (struct vattr *)0, errout); *vpp = newvp; m_freem(mrep); cnp->cn_flags |= SAVENAME; - if (!lockparent) { + if (!lockparent) VOP_UNLOCK(dvp, 0, p); - cnp->cn_flags |= PDIRUNLOCK; - } - return (0); + cnp->cn_flags |= PDIRUNLOCK; + goto out1; } if (flags & ISDOTDOT) { @@ -942,7 +976,7 @@ error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); if (error) { vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); - return (error); + goto out1; } newvp = NFSTOV(np); if (lockparent && (flags & ISLASTCN)) { @@ -950,7 +984,7 @@ if (error) { cnp->cn_flags |= PDIRUNLOCK; vput(newvp); - return (error); + goto out1; } } else cnp->cn_flags |= PDIRUNLOCK; @@ -959,10 +993,8 @@ newvp = dvp; } else { error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - if (error) { - m_freem(mrep); - return (error); - } + if (error) + goto out1; if (!lockparent || !(flags & ISLASTCN)) { cnp->cn_flags |= PDIRUNLOCK; VOP_UNLOCK(dvp, 0, p); @@ -970,10 +1002,10 @@ newvp = NFSTOV(np); } if (v3) { - nfsm_postop_attr(newvp, attrflag); - nfsm_postop_attr(dvp, attrflag); + nfsm_postop_attr(&repc, newvp, attrflag, errout); + nfsm_postop_attr(&repc, dvp, attrflag, errout); } else - nfsm_loadattr(newvp, (struct vattr *)0); + nfsm_loadattr(&repc, newvp, (struct vattr *)0, errout); if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME; if ((cnp->cn_flags & MAKEENTRY) && @@ -982,7 +1014,7 @@ cache_enter(dvp, newvp, cnp); } *vpp = newvp; - nfsm_reqdone; +errout: if (error) { if (newvp != NULLVP) { vrele(newvp); @@ -1002,6 +1034,9 @@ if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME; } +out1: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } @@ -1053,30 +1088,30 @@ struct uio *uiop; struct ucred *cred; { - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; + struct nfs_chain reqc, repc; int error = 0, len, attrflag; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(vp); nfsstats.rpccnt[NFSPROC_READLINK]++; - nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&repc, vp, NFSPROC_READLINK, NFSX_FH(v3), errout); + nfsm_fhtom(&repc, vp, v3, errout); + nfsm_request(&repc, &repc, vp, NFSPROC_READLINK, uiop->uio_procp, cred, + errout); if (v3) - nfsm_postop_attr(vp, attrflag); + nfsm_postop_attr(&repc, vp, attrflag, errout); if (!error) { - nfsm_strsiz(len, NFS_MAXPATHLEN); + nfsm_strsiz(&repc, len, NFS_MAXPATHLEN, errout); if (len == NFS_MAXPATHLEN) { struct nfsnode *np = VTONFS(vp); if (np->n_size && np->n_size < NFS_MAXPATHLEN) len = np->n_size; } - nfsm_mtouio(uiop, len); + nfsm_mtouio(&repc, uiop, len, errout); } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } @@ -1090,11 +1125,8 @@ struct uio *uiop; struct ucred *cred; { - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; + struct nfs_chain reqc, repc; + u_int32_t tl; struct nfsmount *nmp; int error = 0, len, retlen, tsiz, eof, attrflag; int v3 = NFS_ISV3(vp); @@ -1108,10 +1140,12 @@ return (EFBIG); while (tsiz > 0) { nfsstats.rpccnt[NFSPROC_READ]++; + NFSCHAIN_INIT(&repc); len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; - nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3); - nfsm_fhtom(vp, v3); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3); + nfsm_reqhead(&reqc, vp, NFSPROC_READ, + NFSX_FH(v3) + NFSX_UNSIGNED * 3, errout); + nfsm_fhtom(&reqc, vp, v3, errout); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_UNSIGNED * 3, errout); if (v3) { txdr_hyper(uiop->uio_offset, tl); *(tl + 2) = txdr_unsigned(len); @@ -1120,29 +1154,33 @@ *tl++ = txdr_unsigned(len); *tl = 0; } - nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred); + nfsm_request(&reqc, &repc, vp, NFSPROC_READ, uiop->uio_procp, + cred, errout); if (v3) { - nfsm_postop_attr(vp, attrflag); - if (error) { - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_postop_attr(&repc, vp, attrflag, errout); + if (error) + goto errout; + nfsm_dissect(&repc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); eof = fxdr_unsigned(int, *(tl + 1)); } else - nfsm_loadattr(vp, (struct vattr *)0); - nfsm_strsiz(retlen, nmp->nm_rsize); - nfsm_mtouio(uiop, retlen); - m_freem(mrep); + nfsm_loadattr(&repc, vp, (struct vattr *)0, errout); + nfsm_strsiz(&repc, retlen, nmp->nm_rsize, errout); + nfsm_mtouio(&repc, uiop, retlen, errout); tsiz -= retlen; if (v3) { if (eof || retlen == 0) tsiz = 0; } else if (retlen < len) tsiz = 0; + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); } -nfsmout: - return (error); + return error; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); + return error; } /* @@ -1155,11 +1193,8 @@ struct ucred *cred; int *iomode, *must_commit; { + struct nfs_chain reqc, repc; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2, backup; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct nfsmount *nmp = VFSTONFS(vp->v_mount); int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit; int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC; @@ -1174,12 +1209,14 @@ return (EFBIG); while (tsiz > 0) { nfsstats.rpccnt[NFSPROC_WRITE]++; + NFSCHAIN_INIT(&repc); len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; - nfsm_reqhead(vp, NFSPROC_WRITE, - NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(vp, v3); + nfsm_reqhead(&reqc, vp, NFSPROC_WRITE, + NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len), errout); + nfsm_fhtom(&reqc, vp, v3, errout); if (v3) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, 5 * NFSX_UNSIGNED, + errout); txdr_hyper(uiop->uio_offset, tl); tl += 2; *tl++ = txdr_unsigned(len); @@ -1188,7 +1225,8 @@ } else { register u_int32_t x; - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, 4 * NFSX_UNSIGNED, + errout); /* Set both "begin" and "current" to non-garbage. */ x = txdr_unsigned((u_int32_t)uiop->uio_offset); *tl++ = x; /* "begin offset" */ @@ -1197,18 +1235,19 @@ *tl++ = x; /* total to this offset */ *tl = x; /* size of this write */ } - nfsm_uiotom(uiop, len); - nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred); + nfsm_uiotom(&reqc, uiop, len, errout); + nfsm_request(&reqc, &repc, vp, NFSPROC_WRITE, uiop->uio_procp, + cred, errout); if (v3) { wccflag = NFSV3_WCCCHK; - nfsm_wcc_data(vp, wccflag); + nfsm_wcc_data(&repc, vp, wccflag, errout); if (!error) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED - + NFSX_V3WRITEVERF); + nfsm_dissect(&repc, tl, u_int32_t *, + 2 * NFSX_UNSIGNED + NFSX_V3WRITEVERF, + errout); rlen = fxdr_unsigned(int, *tl++); if (rlen == 0) { error = NFSERR_IO; - m_freem(mrep); break; } else if (rlen < len) { backup = len - rlen; @@ -1241,20 +1280,23 @@ } } } else - nfsm_loadattr(vp, (struct vattr *)0); + nfsm_loadattr(&repc, vp, (struct vattr *)0, errout); if (wccflag) VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec; - m_freem(mrep); if (error) break; tsiz -= len; + NFSCHAIN_FREE(&mreq); + NFSCHAIN_FREE(&mrep); } -nfsmout: +errout: if (vp->v_mount->mnt_flag & MNT_ASYNC) committed = NFSV3WRITE_FILESYNC; *iomode = committed; if (error) uiop->uio_resid = tsiz; + NFSCHAIN_FREE(&mreq); + NFSCHAIN_FREE(&mreq); return (error); } @@ -1270,17 +1312,15 @@ register struct componentname *cnp; register struct vattr *vap; { + struct nfs_chain reqc, repc; register struct nfsv2_sattr *sp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; struct vnode *newvp = (struct vnode *)0; struct nfsnode *np = (struct nfsnode *)0; struct vattr vattr; char *cp2; caddr_t bpos, dpos; int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; u_int32_t rdev; int v3 = NFS_ISV3(dvp); @@ -1295,21 +1335,26 @@ return (error); } nfsstats.rpccnt[NFSPROC_MKNOD]++; - nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + - + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, dvp, NFSPROC_MKNOD, NFSX_FH(v3) + + 4 * NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3), + errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, + errout); if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); *tl++ = vtonfsv3_type(vap->va_type); - nfsm_v3attrbuild(vap, FALSE); + nfsm_v3attrbuild(&reqc, vap, FALSE, errout); if (vap->va_type == VCHR || vap->va_type == VBLK) { - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); *tl++ = txdr_unsigned(umajor(vap->va_rdev)); *tl = txdr_unsigned(uminor(vap->va_rdev)); } } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_build(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); sp->sa_uid = nfs_xdrneg1; sp->sa_gid = nfs_xdrneg1; @@ -1317,9 +1362,10 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred); + nfsm_request(&reqc, &repc, dvp, NFSPROC_MKNOD, cnp->cn_proc, + cnp->cn_cred, errout); if (!error) { - nfsm_mtofh(dvp, newvp, v3, gotvp); + nfsm_mtofh(&repc, dvp, newvp, v3, gotvp, errout); if (!gotvp) { if (newvp) { vput(newvp); @@ -1332,8 +1378,10 @@ } } if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; + nfsm_wcc_data(&repc, dvp, wccflag, errout); +errout: + NFSCHAIN_FREE(&req); + NFSCHAIN_FREE(&rep); if (error) { if (newvp) vput(newvp); @@ -1378,18 +1426,15 @@ struct vattr *a_vap; } */ *ap; { + struct nfs_chain reqc, repc; register struct vnode *dvp = ap->a_dvp; register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; struct nfsnode *np = (struct nfsnode *)0; struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct vattr vattr; int v3 = NFS_ISV3(dvp); @@ -1406,15 +1451,19 @@ fmode |= O_EXCL; again: nfsstats.rpccnt[NFSPROC_CREATE]++; - nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&repc, dvp, NFSPROC_CREATE, NFSX_FH(v3) + + 2 * NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3), + errout); + nfsm_fhtom(&repc, dvp, v3, errout); + nfsm_strtom(&repc, cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, + errout); if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_UNSIGNED, errout); if (fmode & O_EXCL) { *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE); - nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF); + nfsm_build(&reqc, tl, u_int32_t *, NFSX_V3CREATEVERF, + errout); #ifdef INET if (!TAILQ_EMPTY(&in_ifaddrhead)) *tl++ = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr; @@ -1424,10 +1473,11 @@ *tl = ++create_verf; } else { *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED); - nfsm_v3attrbuild(vap, FALSE); + nfsm_v3attrbuild(&reqc, vap, FALSE, errout); } } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_build(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); sp->sa_uid = nfs_xdrneg1; sp->sa_gid = nfs_xdrneg1; @@ -1435,9 +1485,10 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred); + nfsm_request(&reqc, &repc, dvp, NFSPROC_CREATE, cnp->cn_proc, + cnp->cn_cred, errout); if (!error) { - nfsm_mtofh(dvp, newvp, v3, gotvp); + nfsm_mtofh(&repc, dvp, newvp, v3, gotvp, errout); if (!gotvp) { if (newvp) { vput(newvp); @@ -1450,8 +1501,10 @@ } } if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; + nfsm_wcc_data(&repc, dvp, wccflag, errout); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); if (error) { if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) { fmode &= ~O_EXCL; @@ -1577,23 +1630,23 @@ struct ucred *cred; struct proc *proc; { + struct nfs_chain reqc, repc; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_REMOVE]++; - nfsm_reqhead(dvp, NFSPROC_REMOVE, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(name, namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_REMOVE, proc, cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, dvp, NFSPROC_REMOVE, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, name, namelen, NFS_MAXNAMLEN, errout); + nfsm_request(&reqc, &repc, dvp, NFSPROC_REMOVE, proc, cred, errout); if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; + nfsm_wcc_data(&repc, dvp, wccflag, errout); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); VTONFS(dvp)->n_flag |= NMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; @@ -1712,28 +1765,28 @@ struct ucred *cred; struct proc *proc; { + struct nfs_chain reqc, repc; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(fdvp); nfsstats.rpccnt[NFSPROC_RENAME]++; - nfsm_reqhead(fdvp, NFSPROC_RENAME, - (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + - nfsm_rndup(tnamelen)); - nfsm_fhtom(fdvp, v3); - nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); - nfsm_fhtom(tdvp, v3); - nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); - nfsm_request(fdvp, NFSPROC_RENAME, proc, cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, fdvp, NFSPROC_RENAME, + (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + + nfsm_rndup(tnamelen), errout); + nfsm_fhtom(&reqc, fdvp, v3, errout); + nfsm_strtom(&reqc, fnameptr, fnamelen, NFS_MAXNAMLEN, errout); + nfsm_fhtom(&reqc, tdvp, v3, errout); + nfsm_strtom(&reqc, tnameptr, tnamelen, NFS_MAXNAMLEN, errout); + nfsm_request(&reqc, &repc, fdvp, NFSPROC_RENAME, proc, cred, errout); if (v3) { - nfsm_wcc_data(fdvp, fwccflag); - nfsm_wcc_data(tdvp, twccflag); + nfsm_wcc_data(&repc, fdvp, fwccflag, errout); + nfsm_wcc_data(&repc, tdvp, twccflag, errout); } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); VTONFS(fdvp)->n_flag |= NMODIFIED; VTONFS(tdvp)->n_flag |= NMODIFIED; if (!fwccflag) @@ -1754,15 +1807,12 @@ struct componentname *a_cnp; } */ *ap; { + struct nfs_chain reqc, repc; register struct vnode *vp = ap->a_vp; register struct vnode *tdvp = ap->a_tdvp; register struct componentname *cnp = ap->a_cnp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3; if (vp->v_mount != tdvp->v_mount) { @@ -1778,17 +1828,22 @@ v3 = NFS_ISV3(vp); nfsstats.rpccnt[NFSPROC_LINK]++; - nfsm_reqhead(vp, NFSPROC_LINK, - NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(vp, v3); - nfsm_fhtom(tdvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_LINK, NFSX_FH(v3)*2 + NFSX_UNSIGNED + + nfsm_rndup(cnp->cn_namelen), errout); + nfsm_fhtom(&reqc, vp, v3, errout); + nfsm_fhtom(&reqc, tdvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, + errout); + nfsm_request(&reqc, &repc, vp, NFSPROC_LINK, cnp->cn_proc, + cnp->cn_cred, errout); if (v3) { - nfsm_postop_attr(vp, attrflag); - nfsm_wcc_data(tdvp, wccflag); + nfsm_postop_attr(&repc, vp, attrflag, errout); + nfsm_wcc_data(&repc, tdvp, wccflag, errout); } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); VTONFS(tdvp)->n_flag |= NMODIFIED; if (!attrflag) VTONFS(vp)->n_attrstamp = 0; @@ -1815,31 +1870,32 @@ char *a_target; } */ *ap; { + struct nfs_chain reqc, repc; register struct vnode *dvp = ap->a_dvp; register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct vnode *newvp = (struct vnode *)0; int v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_SYMLINK]++; + NFSCHAIN_INIT(&repc); slen = strlen(ap->a_target); - nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + nfsm_reqhead(&reqc, dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + + 2*NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + + NFSX_SATTR(v3), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, + errout); if (v3) { - nfsm_v3attrbuild(vap, FALSE); + nfsm_v3attrbuild(&reqc, vap, FALSE, errout); } - nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); + nfsm_strtom(&reqc, ap->a_target, slen, NFS_MAXPATHLEN, errout); if (!v3) { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_build(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode); sp->sa_uid = nfs_xdrneg1; sp->sa_gid = nfs_xdrneg1; @@ -1855,19 +1911,24 @@ * a file handle that can be converted into newvp without having * to do an extra lookup rpc. */ - nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred); + nfsm_request(&reqc, &repc, dvp, NFSPROC_SYMLINK, cnp->cn_proc, + cnp->cn_cred, errout); if (v3) { if (error == 0) - nfsm_mtofh(dvp, newvp, v3, gotvp); - nfsm_wcc_data(dvp, wccflag); + nfsm_mtofh(&repc, dvp, newvp, v3, gotvp, errout); + nfsm_wcc_data(&repc, dvp, wccflag, errout); } - - /* - * out code jumps -> here, mrep is also freed. - */ - - nfsm_reqdone; - +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); + if (error) { + if (newvp) + vput(newvp); + } else + *ap->a_vpp = newvp; + VTONFS(dvp)->n_flag |= NMODIFIED; + if (!wccflag) + VTONFS(dvp)->n_attrstamp = 0; /* * If we get an EEXIST error, silently convert it to no-error * in case of an NFS retry. @@ -1889,15 +1950,6 @@ if (!error) newvp = NFSTOV(np); } - if (error) { - if (newvp) - vput(newvp); - } else { - *ap->a_vpp = newvp; - } - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; return (error); } @@ -1913,20 +1965,17 @@ struct vattr *a_vap; } */ *ap; { + struct nfs_chain repc, reqc; register struct vnode *dvp = ap->a_dvp; register struct vattr *vap = ap->a_vap; register struct componentname *cnp = ap->a_cnp; register struct nfsv2_sattr *sp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; register int len; struct nfsnode *np = (struct nfsnode *)0; struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR; int gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; struct vattr vattr; int v3 = NFS_ISV3(dvp); @@ -1935,14 +1984,16 @@ } len = cnp->cn_namelen; nfsstats.rpccnt[NFSPROC_MKDIR]++; - nfsm_reqhead(dvp, NFSPROC_MKDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, dvp, NFSPROC_MKDIR, NFSX_FH(v3) + NFSX_UNSIGNED + + nfsm_rndup(len) + NFSX_SATTR(v3), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, len, NFS_MAXNAMLEN, errout); if (v3) { - nfsm_v3attrbuild(vap, FALSE); + nfsm_v3attrbuild(&reqc, vap, FALSE, errout); } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); + nfsm_build(&reqc, sp, struct nfsv2_sattr *, NFSX_V2SATTR, + errout); sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode); sp->sa_uid = nfs_xdrneg1; sp->sa_gid = nfs_xdrneg1; @@ -1950,12 +2001,15 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred); + nfsm_request(&reqc, &repc, dvp, NFSPROC_MKDIR, cnp->cn_proc, + cnp->cn_cred, errout); if (!error) - nfsm_mtofh(dvp, newvp, v3, gotvp); + nfsm_mtofh(&repc, dvp, newvp, v3, gotvp, errout); if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; + nfsm_wcc_data(&repc, dvp, wccflag, errout); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); VTONFS(dvp)->n_flag |= NMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; @@ -1995,28 +2049,30 @@ struct componentname *a_cnp; } */ *ap; { + struct nfs_chain reqc, repc; register struct vnode *vp = ap->a_vp; register struct vnode *dvp = ap->a_dvp; register struct componentname *cnp = ap->a_cnp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; int v3 = NFS_ISV3(dvp); if (dvp == vp) return (EINVAL); nfsstats.rpccnt[NFSPROC_RMDIR]++; - nfsm_reqhead(dvp, NFSPROC_RMDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, dvp, NFSPROC_RMDIR, NFSX_FH(v3) + NFSX_UNSIGNED + + nfsm_rndup(cnp->cn_namelen), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN, + errout); + nfsm_request(&reqc, &repc, dvp, NFSPROC_RMDIR, cnp->cn_proc, + cnp->cn_cred, errout); if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; + nfsm_wcc_data(&repc, dvp, wccflag, errout); +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); VTONFS(dvp)->n_flag |= NMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; @@ -2088,14 +2144,11 @@ struct ucred *cred; { + struct nfs_chain reqc, repc; register int len, left; register struct dirent *dp = NULL; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; register nfsuint64 *cookiep; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; nfsuint64 cookie; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *dnp = VTONFS(vp); @@ -2123,55 +2176,55 @@ * truncated to a multiple of DIRBLKSIZ. * The stopping criteria is EOF or buffer full. */ + NFSCHAIN_INIT(&repc); while (more_dirs && bigenough) { nfsstats.rpccnt[NFSPROC_READDIR]++; - nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) + - NFSX_READDIR(v3)); - nfsm_fhtom(vp, v3); + nfsm_reqhead(&reqc, vp, NFSPROC_READDIR, NFSX_FH(v3) + + NFSX_READDIR(v3), errout); + nfsm_fhtom(&reqc, vp, v3, errout); if (v3) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, 5 * NFSX_UNSIGNED, + errout); *tl++ = cookie.nfsuquad[0]; *tl++ = cookie.nfsuquad[1]; *tl++ = dnp->n_cookieverf.nfsuquad[0]; *tl++ = dnp->n_cookieverf.nfsuquad[1]; } else { - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + nfsm_build(&reqc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); *tl++ = cookie.nfsuquad[0]; } *tl = txdr_unsigned(nmp->nm_readdirsize); - nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred); + nfsm_request(&reqc, &repc, vp, NFSPROC_READDIR, + uiop->uio_procp, cred, errout); if (v3) { - nfsm_postop_attr(vp, attrflag); - if (!error) { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); - dnp->n_cookieverf.nfsuquad[0] = *tl++; - dnp->n_cookieverf.nfsuquad[1] = *tl; - } else { - m_freem(mrep); - goto nfsmout; - } + nfsm_postop_attr(&repc, vp, attrflag, errout); + if (error) + goto errout; + nfsm_dissect(&repc, tl, u_int32_t *, 2 * NFSX_UNSIGNED, + errout); + dnp->n_cookieverf.nfsuquad[0] = *tl++; + dnp->n_cookieverf.nfsuquad[1] = *tl; } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, errout); more_dirs = fxdr_unsigned(int, *tl); /* loop thru the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { if (v3) { - nfsm_dissect(tl, u_int32_t *, - 3 * NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, + 3 * NFSX_UNSIGNED, errout); fileno = fxdr_hyper(tl); len = fxdr_unsigned(int, *(tl + 2)); } else { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, + 2 * NFSX_UNSIGNED, errout); fileno = fxdr_unsigned(u_quad_t, *tl++); len = fxdr_unsigned(int, *tl); } if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; - m_freem(mrep); - goto nfsmout; + goto errout; } tlen = nfsm_rndup(len); if (tlen == len) @@ -2200,7 +2253,7 @@ uiop->uio_resid -= DIRHDSIZ; uiop->uio_iov->iov_base += DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; - nfsm_mtouio(uiop, len); + nfsm_mtouio(&repc, uiop, len, errout); cp = uiop->uio_iov->iov_base; tlen -= len; *cp = '\0'; /* null terminate */ @@ -2209,13 +2262,13 @@ uiop->uio_offset += tlen; uiop->uio_resid -= tlen; } else - nfsm_adv(nfsm_rndup(len)); + nfsm_adv(&repc, nfsm_rndup(len), errout); if (v3) { - nfsm_dissect(tl, u_int32_t *, - 3 * NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, + 3 * NFSX_UNSIGNED, errout); } else { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, + 2 * NFSX_UNSIGNED, errout); } if (bigenough) { cookie.nfsuquad[0] = *tl++; @@ -2231,10 +2284,12 @@ * If at end of rpc data, get the eof boolean */ if (!more_dirs) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); more_dirs = (fxdr_unsigned(int, *tl) == 0); } - m_freem(mrep); + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); } /* * Fill last record, iff any, out to a multiple of DIRBLKSIZ @@ -2261,7 +2316,9 @@ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); *cookiep = cookie; } -nfsmout: +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } @@ -2274,15 +2331,12 @@ register struct uio *uiop; struct ucred *cred; { + struct nfs_chain reqc, repc, attrc; register int len, left; register struct dirent *dp; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; register struct vnode *newvp; register nfsuint64 *cookiep; - caddr_t bpos, dpos, cp2, dpossav1, dpossav2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2; struct nameidata nami, *ndp = &nami; struct componentname *cnp = &ndp->ni_cnd; nfsuint64 cookie; @@ -2317,38 +2371,38 @@ * truncated to a multiple of DIRBLKSIZ. * The stopping criteria is EOF or buffer full. */ + NFSCHAIN_INIT(&repc); while (more_dirs && bigenough) { nfsstats.rpccnt[NFSPROC_READDIRPLUS]++; - nfsm_reqhead(vp, NFSPROC_READDIRPLUS, - NFSX_FH(1) + 6 * NFSX_UNSIGNED); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED); + nfsm_reqhead(&reqc, vp, NFSPROC_READDIRPLUS, + NFSX_FH(1) + 6 * NFSX_UNSIGNED, errout); + nfsm_fhtom(&reqc, vp, 1, errout); + nfsm_build(&reqc, tl, u_int32_t *, 6 * NFSX_UNSIGNED, errout); *tl++ = cookie.nfsuquad[0]; *tl++ = cookie.nfsuquad[1]; *tl++ = dnp->n_cookieverf.nfsuquad[0]; *tl++ = dnp->n_cookieverf.nfsuquad[1]; *tl++ = txdr_unsigned(nmp->nm_readdirsize); *tl = txdr_unsigned(nmp->nm_rsize); - nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred); - nfsm_postop_attr(vp, attrflag); - if (error) { - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + nfsm_request(&reqc, &repc, vp, NFSPROC_READDIRPLUS, + uiop->uio_procp, cred, errout); + nfsm_postop_attr(&repc, vp, attrflag, errout); + if (error) + goto errout; + nfsm_dissect(&reqc, tl, u_int32_t *, 3 * NFSX_UNSIGNED, errout); dnp->n_cookieverf.nfsuquad[0] = *tl++; dnp->n_cookieverf.nfsuquad[1] = *tl++; more_dirs = fxdr_unsigned(int, *tl); /* loop thru the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + nfsm_dissect(&reqc, tl, u_int32_t *, 3 * NFSX_UNSIGNED, + errout); fileno = fxdr_hyper(tl); len = fxdr_unsigned(int, *(tl + 2)); if (len <= 0 || len > NFS_MAXNAMLEN) { error = EBADRPC; - m_freem(mrep); - goto nfsmout; + goto errout; } tlen = nfsm_rndup(len); if (tlen == len) @@ -2379,7 +2433,7 @@ uiop->uio_iov->iov_len -= DIRHDSIZ; cnp->cn_nameptr = uiop->uio_iov->iov_base; cnp->cn_namelen = len; - nfsm_mtouio(uiop, len); + nfsm_mtouio(&repc, uiop, len, errout); cp = uiop->uio_iov->iov_base; tlen -= len; *cp = '\0'; @@ -2388,8 +2442,9 @@ uiop->uio_offset += tlen; uiop->uio_resid -= tlen; } else - nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + nfsm_adv(&repc, nfsm_rndup(len), errout); + nfsm_dissect(&repc, tl, u_int32_t *, 3 * NFSX_UNSIGNED, + errout); if (bigenough) { cookie.nfsuquad[0] = *tl++; cookie.nfsuquad[1] = *tl++; @@ -2397,19 +2452,18 @@ tl += 2; /* - * Since the attributes are before the file handle - * (sigh), we must skip over the attributes and then - * come back and get them. + * Save the position of the attributes, so we can + * get them later. */ attrflag = fxdr_unsigned(int, *tl); if (attrflag) { - dpossav1 = dpos; - mdsav1 = md; - nfsm_adv(NFSX_V3FATTR); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + attrc = repc; + nfsm_adv(&repc, NFSX_V3FATTR, errout); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); doit = fxdr_unsigned(int, *tl); if (doit) { - nfsm_getfh(fhp, fhsize, 1); + nfsm_getfh(&repc, fhp, fhsize, 1, errout); if (NFS_CMPFH(dnp, fhp, fhsize)) { VREF(vp); newvp = vp; @@ -2424,13 +2478,8 @@ } } if (doit && bigenough) { - dpossav2 = dpos; - dpos = dpossav1; - mdsav2 = md; - md = mdsav1; - nfsm_loadattr(newvp, (struct vattr *)0); - dpos = dpossav2; - md = mdsav2; + nfsm_loadattr(&attrc, newvp, (struct vattr *)0, + errout); dp->d_type = IFTODT(VTTOIF(np->n_vattr.va_type)); ndp->ni_vp = newvp; @@ -2438,9 +2487,10 @@ } } else { /* Just skip over the file handle */ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); i = fxdr_unsigned(int, *tl); - nfsm_adv(nfsm_rndup(i)); + nfsm_adv(&repc, nfsm_rndup(i), errout); } if (newvp != NULLVP) { if (newvp == vp) @@ -2449,17 +2499,20 @@ vput(newvp); newvp = NULLVP; } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); more_dirs = fxdr_unsigned(int, *tl); } /* * If at end of rpc data, get the eof boolean */ if (!more_dirs) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_UNSIGNED, + errout); more_dirs = (fxdr_unsigned(int, *tl) == 0); } - m_freem(mrep); + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); } /* * Fill last record, iff any, out to a multiple of DIRBLKSIZ @@ -2486,7 +2539,9 @@ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); *cookiep = cookie; } -nfsmout: +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); if (newvp != NULLVP) { if (newvp == vp) vrele(newvp); @@ -2571,25 +2626,23 @@ struct proc *procp; struct nfsnode **npp; { + struct nfs_chain reqc, repc; register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; struct vnode *newvp = (struct vnode *)0; struct nfsnode *np, *dnp = VTONFS(dvp); - caddr_t bpos, dpos, cp2; int error = 0, fhlen, attrflag; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; nfsfh_t *nfhp; int v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_LOOKUP]++; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(name, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len), errout); + nfsm_fhtom(&reqc, dvp, v3, errout); + nfsm_strtom(&reqc, name, len, NFS_MAXNAMLEN, errout); + nfsm_request(&reqc, &repc, dvp, NFSPROC_LOOKUP, procp, cred, errout); if (npp && !error) { - nfsm_getfh(nfhp, fhlen, v3); + nfsm_getfh(&repc, nfhp, fhlen, v3, errout); if (*npp) { np = *npp; if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) { @@ -2605,28 +2658,24 @@ newvp = dvp; } else { error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); - if (error) { - m_freem(mrep); - return (error); - } + if (error) + goto out1; newvp = NFSTOV(np); } + /* XXX check errout1 logic */ if (v3) { - nfsm_postop_attr(newvp, attrflag); + nfsm_postop_attr(&repc, newvp, attrflag, errout1); if (!attrflag && *npp == NULL) { - m_freem(mrep); - if (newvp == dvp) - vrele(newvp); - else - vput(newvp); - return (ENOENT); + error = ENOENT; + goto errout1; } } else - nfsm_loadattr(newvp, (struct vattr *)0); + nfsm_loadattr(&repc, newvp, (struct vattr *)0, errout1); } - nfsm_reqdone; +errout: if (npp && *npp == NULL) { if (error) { +errout1: if (newvp) { if (newvp == dvp) vrele(newvp); @@ -2636,6 +2685,9 @@ } else *npp = np; } +out1: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } @@ -2650,27 +2702,26 @@ struct ucred *cred; struct proc *procp; { + struct nfs_chain register caddr_t cp; register u_int32_t *tl; - register int32_t t1, t2; register struct nfsmount *nmp = VFSTONFS(vp->v_mount); - caddr_t bpos, dpos, cp2; int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0) return (0); nfsstats.rpccnt[NFSPROC_COMMIT]++; - nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); + NFSCHAIN_INIT(&repc); + nfsm_reqhead(&reqc, vp, NFSPROC_COMMIT, NFSX_FH(1), errout); + nfsm_fhtom(&reqc, vp, 1, errout); + nfsm_build(&reqc, tl, u_int32_t *, 3 * NFSX_UNSIGNED, errout); txdr_hyper(offset, tl); tl += 2; *tl = txdr_unsigned(cnt); - nfsm_request(vp, NFSPROC_COMMIT, procp, cred); - nfsm_wcc_data(vp, wccflag); + nfsm_request(&reqc, &repc, vp, NFSPROC_COMMIT, procp, cred, errout); + nfsm_wcc_data(&repc, vp, wccflag, errout); if (!error) { - nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF); + nfsm_dissect(&repc, tl, u_int32_t *, NFSX_V3WRITEVERF, errout); if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl, NFSX_V3WRITEVERF)) { bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, @@ -2678,7 +2729,9 @@ error = NFSERR_STALEWRITEVERF; } } - nfsm_reqdone; +errout: + NFSCHAIN_FREE(&reqc); + NFSCHAIN_FREE(&repc); return (error); } Index: nfsm_subs.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nfsm_subs.h,v retrieving revision 1.29 diff -u -r1.29 nfsm_subs.h --- nfsm_subs.h 2000/12/21 21:44:24 1.29 +++ nfsm_subs.h 2001/02/05 01:01:12 @@ -53,8 +53,8 @@ /* * First define what the actual subs. return */ -struct mbuf *nfsm_reqh __P((struct vnode *vp, u_long procid, int hsiz, - caddr_t *bposp)); +int nfs_reqhead(struct nfs_chain *req, struct vnode *vp, u_long procid, + int hsiz); struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, int auth_type, int auth_len, char *auth_str, int verf_len, char *verf_str, @@ -91,146 +91,150 @@ * unions. */ -#define nfsm_build(a,c,s) \ - do { \ - if ((s) > M_TRAILINGSPACE(mb)) { \ - MGET(mb2, M_TRYWAIT, MT_DATA); \ - if ((s) > MLEN) \ - panic("build > MLEN"); \ - mb->m_next = mb2; \ - mb = mb2; \ - mb->m_len = 0; \ - bpos = mtod(mb, caddr_t); \ - } \ - (a) = (c)(bpos); \ - mb->m_len += (s); \ - bpos += (s); \ - } while (0) - -#define nfsm_dissect(a, c, s) \ - do { \ - t1 = mtod(md, caddr_t)+md->m_len-dpos; \ - if (t1 >= (s)) { \ - (a) = (c)(dpos); \ - dpos += (s); \ - } else if ((t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) != 0){ \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } else { \ - (a) = (c)cp2; \ - } \ - } while (0) +/* + * Allocate 's' contiguous bytes at the current position in the chain + * and set 'a' to be a pointer of type 'c' to this space. The current + * position and mbuf lengths are updated. Currently errl is not used. + */ +#define nfsm_build(ncp,a,c,s,errl) \ +do { \ + int _error; \ + void *_p; \ + if ((_error = nfs_build(ncp, s, &_p)) != 0) \ + goto errl; \ + (a) = (c)(_p); \ +} while (0) -#define nfsm_fhtom(v, v3) \ - do { \ - if (v3) { \ - t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \ - if (t2 <= M_TRAILINGSPACE(mb)) { \ - nfsm_build(tl, u_int32_t *, t2); \ - *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \ - *(tl + ((t2>>2) - 2)) = 0; \ - bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \ - VTONFS(v)->n_fhsize); \ - } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, \ - (caddr_t)VTONFS(v)->n_fhp, \ - VTONFS(v)->n_fhsize)) != 0) { \ - error = t2; \ - m_freem(mreq); \ - goto nfsmout; \ - } \ - } else { \ - nfsm_build(cp, caddr_t, NFSX_V2FH); \ - bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \ - } \ - } while (0) +/* + * Make the next 's' bytes in the chain contiguous, and set 'a' (type 'c') to + * point to them. Sets 'error' and does a 'goto errl' if an error occurs. + */ +#define nfsm_dissect(ncp, a, c, s, errl) do { \ + void *_p; \ + int _error; \ + if ((_error = nfs_dissect(ncp, s, &_p)) != 0) { \ + error = _error; \ + goto errl; \ + } \ + (a) = (c)_p; \ +} while (0) -#define nfsm_srvfhtom(f, v3) \ - do { \ - if (v3) { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FH);\ - *tl++ = txdr_unsigned(NFSX_V3FH); \ - bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ - } else { \ - nfsm_build(cp, caddr_t, NFSX_V2FH); \ - bcopy((caddr_t)(f), cp, NFSX_V2FH); \ - } \ - } while (0) +/* + * Append the filehandle for vnode 'v' to the mbuf chain. NFSV3 format is + * used if 'v3' is true. On error does a 'goto errl' with 'error' set. + */ +#define nfsm_fhtom(ncp, v, v3, errl) do { \ + int _error; \ + if ((_error = nfs_fhtom(ncp, v, v3)) != 0) { \ + error = _error; \ + goto errl; \ + } \ +} while (0) -#define nfsm_srvpostop_fh(f) \ +/* + * Append nfs_true followed by a V3 filehandle to the chain. + */ +#define nfsm_srvpostop_fh(ncp, f, errl) \ do { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \ + u_int32_t tl; \ + nfsm_build(ncp, tl, u_int32_t *, \ + 2 * NFSX_UNSIGNED + NFSX_V3FH, errl); \ *tl++ = nfs_true; \ *tl++ = txdr_unsigned(NFSX_V3FH); \ - bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ + bcopy(f, tl, NFSX_V3FH); \ } while (0) -#define nfsm_mtofh(d, v, v3, f) \ +/* + * Extract a filehandle from the mbuf chain, and attributes, if included. + * 'f' is set to 1 if attributes were included. Converts the filehandle to + * a vnode, and returns a pointer to that in 'v'. Goes to errl on error, + * with 'error' containing the error. + */ +#define nfsm_mtofh(ncp, d, v, v3, f, errl) \ do { \ struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \ + u_int32_t tl; \ if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ (f) = fxdr_unsigned(int, *tl); \ } else \ (f) = 1; \ if (f) { \ - nfsm_getfh(ttfhp, ttfhsize, (v3)); \ + int32_t t1; \ + nfsm_getfh(ncp, ttfhp, ttfhsize, (v3), errl); \ if ((t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \ - &ttnp)) != 0) { \ + &ttnp)) != 0) { \ error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ + goto errl; \ } \ (v) = NFSTOV(ttnp); \ } \ if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ if (f) \ (f) = fxdr_unsigned(int, *tl); \ else if (fxdr_unsigned(int, *tl)) \ - nfsm_adv(NFSX_V3FATTR); \ + nfsm_adv(ncp, NFSX_V3FATTR, errl); \ } \ if (f) \ - nfsm_loadattr((v), (struct vattr *)0); \ + nfsm_loadattr(ncp, (v), (struct vattr *)0, errl); \ } while (0) -#define nfsm_getfh(f, s, v3) \ +/* + * Get a filehandle from the mbuf chain and store it in 'f'. 's' is set to + * the length of the filehandle in bytes. On error, 'error' contains the + * error code, and does 'goto errl'. + */ +#define nfsm_getfh(ncp, f, s, v3, errl) \ do { \ if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ + u_int32_t tl; \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \ (s) > NFSX_V3FHMAX) { \ - m_freem(mrep); \ error = EBADRPC; \ - goto nfsmout; \ + goto errl; \ } \ } else \ (s) = NFSX_V2FH; \ - nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); \ + nfsm_dissect(ncp, (f), nfsfh_t *, nfsm_rndup(s), errl); \ } while (0) -#define nfsm_loadattr(v, a) \ +/* + * Loads attributes from the mbuf chain into vnode 'v'. If 'a' is non-null + * the vattr information is copied to it. On error sets 'error' and does + * a 'goto errl'. + */ +#define nfsm_loadattr(ncp, v, a, errl) \ do { \ + int32_t t1; \ struct vnode *ttvp = (v); \ - if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a), 0)) != 0) { \ + if ((t1 = nfs_loadattrcache(&ttvp, ncp, (a), 0)) != 0) { \ error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ + goto errl; \ } \ (v) = ttvp; \ } while (0) -#define nfsm_postop_attr(v, f) \ +/* + * Read attributes from the chain into vnode 'v' if they are there. 'f' is + * set to 1 if attributes were read. Sets 'error' and does 'goto errl' on + * error. + */ +#define nfsm_postop_attr(ncp, v, f, errl) \ do { \ + u_int32_t tl; \ struct vnode *ttvp = (v); \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, errl); \ if (((f) = fxdr_unsigned(int, *tl)) != 0) { \ - if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \ + if ((t1 = nfs_loadattrcache(&ttvp, ncp, \ (struct vattr *)0, 1)) != 0) { \ error = t1; \ (f) = 0; \ - m_freem(mrep); \ - goto nfsmout; \ + goto errl; \ } \ (v) = ttvp; \ } \ @@ -240,17 +244,19 @@ #define NFSV3_WCCRATTR 0 #define NFSV3_WCCCHK 1 -#define nfsm_wcc_data(v, f) \ +#define nfsm_wcc_data(ncp, v, f, errl) \ do { \ + u_int32_t tl; \ int ttattrf, ttretf = 0; \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, errl); \ if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); \ + nfsm_dissect(ncp, tl, u_int32_t *, 6 * NFSX_UNSIGNED, \ + errl); \ if (f) \ ttretf = (VTONFS(v)->n_mtime == \ fxdr_unsigned(u_int32_t, *(tl + 2))); \ } \ - nfsm_postop_attr((v), ttattrf); \ + nfsm_postop_attr(ncp, (v), ttattrf, errl); \ if (f) { \ (f) = ttretf; \ } else { \ @@ -259,188 +265,250 @@ } while (0) /* If full is true, set all fields, otherwise just set mode and time fields */ -#define nfsm_v3attrbuild(a, full) \ +#define nfsm_v3attrbuild(ncp, a, full, errl) \ do { \ + u_int32_t tl; \ if ((a)->va_mode != (mode_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, 2 * NFSX_UNSIGNED, \ + errl); \ *tl++ = nfs_true; \ *tl = txdr_unsigned((a)->va_mode); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = nfs_false; \ } \ if ((full) && (a)->va_uid != (uid_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, 2 * NFSX_UNSIGNED, \ + errl); \ *tl++ = nfs_true; \ *tl = txdr_unsigned((a)->va_uid); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = nfs_false; \ } \ if ((full) && (a)->va_gid != (gid_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, 2 * NFSX_UNSIGNED, \ + errl); \ *tl++ = nfs_true; \ *tl = txdr_unsigned((a)->va_gid); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = nfs_false; \ } \ if ((full) && (a)->va_size != VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, \ + 3 * NFSX_UNSIGNED, errl); \ *tl++ = nfs_true; \ txdr_hyper((a)->va_size, tl); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = nfs_false; \ } \ if ((a)->va_atime.tv_sec != VNOVAL) { \ if ((a)->va_atime.tv_sec != time_second) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ + nfsm_build(ncp, tl, u_int32_t *, \ + 3 * NFSX_UNSIGNED, errl); \ *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ txdr_nfsv3time(&(a)->va_atime, tl); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, \ + NFSX_UNSIGNED, errl); \ *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ } \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ } \ if ((a)->va_mtime.tv_sec != VNOVAL) { \ if ((a)->va_mtime.tv_sec != time_second) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ + nfsm_build(ncp, tl, u_int32_t *, \ + 3 * NFSX_UNSIGNED, errl); \ *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ txdr_nfsv3time(&(a)->va_mtime, tl); \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, \ + NFSX_UNSIGNED, errl); \ *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ } \ } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ + nfsm_build(ncp, tl, u_int32_t *, NFSX_UNSIGNED, \ + errl); \ *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ } \ } while (0) -#define nfsm_strsiz(s,m) \ +#define nfsm_strsiz(ncp, s, m, errl) \ do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ + u_int32_t tl; \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, errl); \ if (((s) = fxdr_unsigned(int32_t,*tl)) > (m)) { \ - m_freem(mrep); \ error = EBADRPC; \ - goto nfsmout; \ + goto errl; \ } \ } while (0) - -#define nfsm_srvstrsiz(s,m) \ +/* + * Extract a string size from the chain. Goes to label 'errl' if the + * length is invalid or missing. + */ +#define nfsm_srvstrsiz(ncp, s, m, errl) \ do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ + u_int32_t tl; \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, errl); \ if (((s) = fxdr_unsigned(int32_t,*tl)) > (m) || (s) <= 0) { \ error = EBADRPC; \ - nfsm_reply(0); \ + goto errl; \ } \ } while (0) -#define nfsm_srvnamesiz(s) \ - do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ - if (((s) = fxdr_unsigned(int32_t,*tl)) > NFS_MAXNAMLEN) \ +/* + * Extract a name size from the chain. Goes to the label 'badlenl' if the + * name length is too long. 'errl' is used for other failures. + */ +#define nfsm_srvnamesiz(ncp, s, errl, badlenl) \ + do { \ + u_int32_t tl; \ + nfsm_dissect(ncp, tl, u_int32_t *, NFSX_UNSIGNED, errl); \ + if (((s) = fxdr_unsigned(int32_t,*tl)) > NFS_MAXNAMLEN) { \ error = NFSERR_NAMETOL; \ - if ((s) <= 0) \ + goto badlenl; \ + } \ + if ((s) <= 0) { \ error = EBADRPC; \ - if (error) \ - nfsm_reply(0); \ + goto errl; \ + } } while (0) -#define nfsm_mtouio(p,s) \ +#define nfsm_mtouio(ncp, p, s, errl) \ do {\ + int32_t t1; \ if ((s) > 0 && \ - (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos)) != 0) { \ + (t1 = nfsm_mbuftouio(ncp, (p),(s))) != 0) { \ error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ + goto errl; \ } \ } while (0) -#define nfsm_uiotom(p,s) \ +#define nfsm_uiotom(ncp, p, s, errl) \ do { \ - if ((t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) != 0) { \ + int32_t t1; \ + if ((t1 = nfsm_uiotombuf((p), ncp, (s))) != 0) { \ error = t1; \ - m_freem(mreq); \ - goto nfsmout; \ + goto errl; \ } \ } while (0) -#define nfsm_reqhead(v,a,s) \ - do { \ - mb = mreq = nfsm_reqh((v),(a),(s),&bpos); \ - } while (0) - -#define nfsm_reqdone \ - do { \ - m_freem(mrep); \ - nfsmout: \ - } while (0) +#define nfsm_reqhead(ncp, v, a, s, errl) do { \ + int _error; \ + if ((_error = nfs_reqhead(ncp, v, a, s)) != 0) { \ + error = _error; \ + goto errl; \ + } \ +} while (0) #define nfsm_rndup(a) (((a)+3)&(~0x3)) -#define nfsm_request(v, t, p, c) \ +/* + * Send RPC request and wait for reply. + * v vnode + * t rpc proc number + * p struct proc pointer + * c credentials + * errl label to jump to on error + * Note with V3 mounts, a error reply from the server does not result + * in a 'goto errl'. Instead the reply is returned, with 'error' set to + * the error code. + * The request mbuf chain is always freed. + * rep_ncp.nc_mhead will be non-null if a reply was returned. + */ +#define nfsm_request(req_ncp, rep_ncp, v, t, p, c, errl) \ do { \ - if ((error = nfs_request((v), mreq, (t), (p), \ - (c), &mrep, &md, &dpos)) != 0) { \ + if ((error = nfs_request((v), (req_ncp)->nc_mhead, (t), (p), \ + (c), rep_ncp)) != 0) { \ if (error & NFSERR_RETERR) \ error &= ~NFSERR_RETERR; \ else \ - goto nfsmout; \ + goto errl; \ } \ } while (0) -#define nfsm_strtom(a,s,m) \ +#define nfsm_strtom(ncp, a, s, m, errl) \ do {\ + u_int32_t tl; \ + int32_t t2; \ if ((s) > (m)) { \ - m_freem(mreq); \ error = ENAMETOOLONG; \ - goto nfsmout; \ + goto errl; \ } \ t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \ - if (t2 <= M_TRAILINGSPACE(mb)) { \ - nfsm_build(tl,u_int32_t *,t2); \ + if (t2 <= M_TRAILINGSPACE((ncp)->nc_m)) { \ + nfsm_build(ncp, tl, u_int32_t *, t2, errl); \ *tl++ = txdr_unsigned(s); \ *(tl+((t2>>2)-2)) = 0; \ - bcopy((const char *)(a), (caddr_t)tl, (s)); \ - } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) != 0) { \ + bcopy(a, tl, (s)); \ + } else if ((t2 = nfsm_strtmbuf(ncp, (a), (s))) != 0) { \ error = t2; \ - m_freem(mreq); \ - goto nfsmout; \ + goto errl; \ } \ } while (0) -#define nfsm_srvdone \ - do { \ - nfsmout: \ - return (error); \ - } while (0) +#define NFSCHAIN_INIT(ncp) do { \ + (ncp)->nc_mhead = NULL; \ +} while (0) + +#define NFSCHAIN_FREE(ncp) do { \ + if ((ncp)->nc_mhead != NULL) \ + m_freem((ncp)->nc_mhead); \ + (ncp)->nc_mhead = NULL; \ +} while (0) + +/* Append a single mbuf to a chain. */ +#define NFSCHAIN_APPENDM(ncp, m) do { \ + if ((ncp)->nc_mhead == NULL) \ + (ncp)->nc_mhead = (m); \ + (ncp)->nc_m = (m); \ + (ncp)->nc_pos = mtod(m, char *) + (m)->m_len; \ +} + +/* Append non-empty chain 'ncp2' to (possibly empty) chain 'ncp'. */ +#define NFSCHAIN_APPENDCHAIN(ncp, ncp2) do { \ + if ((ncp)->nc_mhead == NULL) \ + (ncp)->nc_mhead = (ncp2)->nc_mhead; \ + else \ + (ncp)->nc_m->m_next = (ncp2)->nc_mhead; \ + (ncp)->nc_m = (ncp2)->nc_m; \ + (ncp)->nc_pos = (ncp2)->nc_pos; \ +} -#define nfsm_reply(s) \ - do { \ - nfsd->nd_repstat = error; \ - if (error && !(nfsd->nd_flag & ND_NFSV3)) \ - (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ - mrq, &mb, &bpos); \ - else \ - (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ - mrq, &mb, &bpos); \ - if (mrep != NULL) { \ - m_freem(mrep); \ - mrep = NULL; \ - } \ - mreq = *mrq; \ - if (error && (!(nfsd->nd_flag & ND_NFSV3) || \ - error == EBADRPC)) { \ - error = 0; \ - goto nfsmout; \ - } \ - } while (0) +/* + * Create a reply header for a message. 's' is a hinted message size, used + * to determine whether a cluster is allocated. The value of 'error' is + * used as an error code for the message. + */ +#define nfsm_reply(ncp, nd, slp, error, s, errl) do { \ + int _error; \ + if ((_error = nfs_rephead(ncp, nd, slp, error, s, 0, NULL)) != 0) {; \ + error = _error; \ + goto errl; \ + } \ +} while (0) + +/* + * Create an error reply header, and set nd->nd_repstat to the current + * value of 'error'. Frees any mbuf chain already in ncp first. + */ +#define nfsm_replyerror(ncp, nd, slp, error, errl) do { \ + nd->nd_repstat = error; \ + if ((ncp)->nc_mhead != NULL) \ + m_freem((ncp)->nc_mhead); \ + (ncp)->nc_mhead = NULL; \ + nfsm_reply(ncp, nd, slp, error, 0, errl); \ +} while (0) #define nfsm_writereply(s, v3) \ do { \ @@ -453,38 +521,29 @@ &mreq, &mb, &bpos); \ } while (0) -#define nfsm_adv(s) \ +#define nfsm_adv(ncp, s, errl) \ do { \ - t1 = mtod(md, caddr_t)+md->m_len-dpos; \ + int32_t t1; \ + t1 = mtod((ncp)->nc_m, char *) + (ncp)->nc_m->m_len - \ + (ncp)->nc_pos; \ if (t1 >= (s)) { \ - dpos += (s); \ - } else if ((t1 = nfs_adv(&md, &dpos, (s), t1)) != 0) { \ + (ncp)->nc_pos += (s); \ + } else if ((t1 = nfs_adv(ncp, (s), t1)) != 0) { \ error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ + goto errl; \ } \ } while (0) -#define nfsm_srvmtofh(f) \ - do { \ - int fhlen; \ - if (nfsd->nd_flag & ND_NFSV3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - fhlen = fxdr_unsigned(int, *tl); \ - if (fhlen != 0 && fhlen != NFSX_V3FH) { \ - error = EBADRPC; \ - nfsm_reply(0); \ - } \ - } else { \ - fhlen = NFSX_V2FH; \ - } \ - if (fhlen != 0) { \ - nfsm_dissect(tl, u_int32_t *, fhlen); \ - bcopy((caddr_t)tl, (caddr_t)(f), fhlen); \ - } else {\ - bzero((caddr_t)(f), NFSX_V3FH); \ - } \ - } while (0) +/* + * Extract a filehandle from an NFS request. + */ +#define nfsm_srvmtofh(ncp, f, v3, errl) do { \ + int _error; \ + if ((_error = nfs_srvmtofh(ncp, f, v3)) != 0) { \ + error = _error; \ + goto errl; \ + } \ +} while (0) #define nfsm_clget \ do { \ @@ -496,69 +555,18 @@ mp->m_len = NFSMSIZ(mp); \ mp2->m_next = mp; \ mp2 = mp; \ - bp = mtod(mp, caddr_t); \ + bp = mtod(mp, char *); \ be = bp+mp->m_len; \ } \ tl = (u_int32_t *)bp; \ } while (0) - -#define nfsm_srvfillattr(a, f) \ - do { \ - nfsm_srvfattr(nfsd, (a), (f)); \ - } while (0) - -#define nfsm_srvwcc_data(br, b, ar, a) \ - do { \ - nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos); \ - } while (0) - -#define nfsm_srvpostop_attr(r, a) \ - do { \ - nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos); \ - } while (0) -#define nfsm_srvsattr(a) \ - do { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_mode = nfstov_mode(*tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_uid = fxdr_unsigned(uid_t, *tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_gid = fxdr_unsigned(gid_t, *tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - (a)->va_size = fxdr_hyper(tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - switch (fxdr_unsigned(int, *tl)) { \ - case NFSV3SATTRTIME_TOCLIENT: \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - fxdr_nfsv3time(tl, &(a)->va_atime); \ - break; \ - case NFSV3SATTRTIME_TOSERVER: \ - getnanotime(&(a)->va_atime); \ - break; \ - }; \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - switch (fxdr_unsigned(int, *tl)) { \ - case NFSV3SATTRTIME_TOCLIENT: \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - fxdr_nfsv3time(tl, &(a)->va_mtime); \ - break; \ - case NFSV3SATTRTIME_TOSERVER: \ - getnanotime(&(a)->va_mtime); \ - break; \ - } \ - } while (0) +#define nfsm_srvsattr(ncp, a, errl) do { \ + int _error; \ + if ((_error = nfs_srvsattr(ncp, a)) != 0) { \ + error = _error; \ + goto errl; \ + } \ +} while (0) #endif Index: nqnfs.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/nfs/nqnfs.h,v retrieving revision 1.25 diff -u -r1.25 nqnfs.h --- nqnfs.h 2000/11/14 08:00:39 1.25 +++ nqnfs.h 2001/01/29 01:19:17 @@ -196,13 +196,16 @@ struct sockaddr *, int *, u_quad_t *, struct ucred *)); int nqnfs_getlease __P((struct vnode *,int,struct ucred *,struct proc *)); -int nqnfs_callback __P((struct nfsmount *,struct mbuf *,struct mbuf *,caddr_t)); +int nqnfs_callback __P((struct nfsmount *, struct nfs_chain *)); int nqnfs_clientd __P((struct nfsmount *,struct ucred *,struct nfsd_cargs *,int,caddr_t,struct proc *)); struct nfsnode; void nqnfs_clientlease __P((struct nfsmount *, struct nfsnode *, int, int, time_t, u_quad_t)); void nqnfs_serverd __P((void)); -int nqnfsrv_getlease __P((struct nfsrv_descript *, struct nfssvc_sock *, struct proc *, struct mbuf **)); -int nqnfsrv_vacated __P((struct nfsrv_descript *, struct nfssvc_sock *, struct proc *, struct mbuf **)); + +int nqnfsrv_getlease __P((struct nfsrv_descript *, struct nfssvc_sock *, + struct proc *)); +int nqnfsrv_vacated __P((struct nfsrv_descript *, struct nfssvc_sock *, + struct proc *)); #endif #endif