📄 nfs_socket.c
字号:
mlen = hsiz; /* * Loop through the mbuf list consolidating data. */ while (m) { while (olen > 0) { if (mlen == 0) { m2->m_flags &= ~M_PKTHDR; if (m2->m_flags & M_EXT) m2->m_data = m2->m_ext.ext_buf; else m2->m_data = m2->m_dat; m2->m_len = 0; mlen = M_TRAILINGSPACE(m2); tcp = mtod(m2, caddr_t); mnew = m2; m2 = m2->m_next; } siz = min(mlen, olen); if (tcp != fcp) bcopy(fcp, tcp, siz); mnew->m_len += siz; mlen -= siz; olen -= siz; tcp += siz; fcp += siz; } m = m->m_next; if (m) { olen = m->m_len; fcp = mtod(m, caddr_t); } } /* * Finally, set m_len == 0 for any trailing mbufs that have * been copied out of. */ while (m2) { m2->m_len = 0; m2 = m2->m_next; } return; } m = m->m_next; }}/* * Socket upcall routine for the nfsd sockets. * The caddr_t arg is a pointer to the "struct nfssvc_sock". * Essentially do as much as possible non-blocking, else punt and it will * be called with M_WAIT from an nfsd. */voidnfsrv_rcv(so, arg, waitflag) struct socket *so; caddr_t arg; int waitflag;{ register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; register struct mbuf *m; struct mbuf *mp, *nam; struct uio auio; int flags, error; if ((slp->ns_flag & SLP_VALID) == 0) return;#ifdef notdef /* * Define this to test for nfsds handling this under heavy load. */ if (waitflag == M_DONTWAIT) { slp->ns_flag |= SLP_NEEDQ; goto dorecs; }#endif auio.uio_procp = NULL; if (so->so_type == SOCK_STREAM) { /* * If there are already records on the queue, defer soreceive() * to an nfsd so that there is feedback to the TCP layer that * the nfs servers are heavily loaded. */ if (slp->ns_rec && waitflag == M_DONTWAIT) { slp->ns_flag |= SLP_NEEDQ; goto dorecs; } /* * Do soreceive(). */ auio.uio_resid = 1000000000; flags = MSG_DONTWAIT; error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags); if (error || mp == (struct mbuf *)0) { if (error == EWOULDBLOCK) slp->ns_flag |= SLP_NEEDQ; else slp->ns_flag |= SLP_DISCONN; goto dorecs; } m = mp; if (slp->ns_rawend) { slp->ns_rawend->m_next = m; slp->ns_cc += 1000000000 - auio.uio_resid; } else { slp->ns_raw = m; slp->ns_cc = 1000000000 - auio.uio_resid; } while (m->m_next) m = m->m_next; slp->ns_rawend = m; /* * Now try and parse record(s) out of the raw stream data. */ if (error = nfsrv_getstream(slp, waitflag)) { if (error == EPERM) slp->ns_flag |= SLP_DISCONN; else slp->ns_flag |= SLP_NEEDQ; } } else { do { auio.uio_resid = 1000000000; flags = MSG_DONTWAIT; error = soreceive(so, &nam, &auio, &mp, (struct mbuf **)0, &flags); if (mp) { nfs_realign(mp, 10 * NFSX_UNSIGNED); if (nam) { m = nam; m->m_next = mp; } else m = mp; if (slp->ns_recend) slp->ns_recend->m_nextpkt = m; else slp->ns_rec = m; slp->ns_recend = m; m->m_nextpkt = (struct mbuf *)0; } if (error) { if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && error != EWOULDBLOCK) { slp->ns_flag |= SLP_DISCONN; goto dorecs; } } } while (mp); } /* * Now try and process the request records, non-blocking. */dorecs: if (waitflag == M_DONTWAIT && (slp->ns_rec || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) nfsrv_wakenfsd(slp);}/* * Try and extract an RPC request from the mbuf data list received on a * stream socket. The "waitflag" argument indicates whether or not it * can sleep. */nfsrv_getstream(slp, waitflag) register struct nfssvc_sock *slp; int waitflag;{ register struct mbuf *m; register char *cp1, *cp2; register int len; struct mbuf *om, *m2, *recm; u_long recmark; if (slp->ns_flag & SLP_GETSTREAM) panic("nfs getstream"); slp->ns_flag |= SLP_GETSTREAM; for (;;) { if (slp->ns_reclen == 0) { if (slp->ns_cc < NFSX_UNSIGNED) { slp->ns_flag &= ~SLP_GETSTREAM; return (0); } m = slp->ns_raw; if (m->m_len >= NFSX_UNSIGNED) { bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); m->m_data += NFSX_UNSIGNED; m->m_len -= NFSX_UNSIGNED; } else { cp1 = (caddr_t)&recmark; cp2 = mtod(m, caddr_t); while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { while (m->m_len == 0) { m = m->m_next; cp2 = mtod(m, caddr_t); } *cp1++ = *cp2++; m->m_data++; m->m_len--; } } slp->ns_cc -= NFSX_UNSIGNED; slp->ns_reclen = ntohl(recmark) & ~0x80000000; if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) { slp->ns_flag &= ~SLP_GETSTREAM; return (EPERM); } } /* * Now get the record part. */ if (slp->ns_cc == slp->ns_reclen) { recm = slp->ns_raw; slp->ns_raw = slp->ns_rawend = (struct mbuf *)0; slp->ns_cc = slp->ns_reclen = 0; } else if (slp->ns_cc > slp->ns_reclen) { len = 0; m = slp->ns_raw; om = (struct mbuf *)0; while (len < slp->ns_reclen) { if ((len + m->m_len) > slp->ns_reclen) { m2 = m_copym(m, 0, slp->ns_reclen - len, waitflag); if (m2) { if (om) { om->m_next = m2; recm = slp->ns_raw; } else recm = m2; m->m_data += slp->ns_reclen - len; m->m_len -= slp->ns_reclen - len; len = slp->ns_reclen; } else { slp->ns_flag &= ~SLP_GETSTREAM; return (EWOULDBLOCK); } } else if ((len + m->m_len) == slp->ns_reclen) { om = m; len += m->m_len; m = m->m_next; recm = slp->ns_raw; om->m_next = (struct mbuf *)0; } else { om = m; len += m->m_len; m = m->m_next; } } slp->ns_raw = m; slp->ns_cc -= len; slp->ns_reclen = 0; } else { slp->ns_flag &= ~SLP_GETSTREAM; return (0); } nfs_realign(recm, 10 * NFSX_UNSIGNED); if (slp->ns_recend) slp->ns_recend->m_nextpkt = recm; else slp->ns_rec = recm; slp->ns_recend = recm; }}/* * Parse an RPC header. */nfsrv_dorec(slp, nd) register struct nfssvc_sock *slp; register struct nfsd *nd;{ register struct mbuf *m; int error; if ((slp->ns_flag & SLP_VALID) == 0 || (m = slp->ns_rec) == (struct mbuf *)0) return (ENOBUFS); if (slp->ns_rec = m->m_nextpkt) m->m_nextpkt = (struct mbuf *)0; else slp->ns_recend = (struct mbuf *)0; if (m->m_type == MT_SONAME) { nd->nd_nam = m; nd->nd_md = nd->nd_mrep = m->m_next; m->m_next = (struct mbuf *)0; } else { nd->nd_nam = (struct mbuf *)0; nd->nd_md = nd->nd_mrep = m; } nd->nd_dpos = mtod(nd->nd_md, caddr_t); if (error = nfs_getreq(nd, TRUE)) { m_freem(nd->nd_nam); return (error); } return (0);}/* * Parse an RPC request * - verify it * - fill in the cred struct. */nfs_getreq(nd, has_header) register struct nfsd *nd; int has_header;{ register int len, i; register u_long *tl; register long t1; struct uio uio; struct iovec iov; caddr_t dpos, cp2; u_long nfsvers, auth_type; int error = 0, nqnfs = 0; struct mbuf *mrep, *md; mrep = nd->nd_mrep; md = nd->nd_md; dpos = nd->nd_dpos; if (has_header) { nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED); nd->nd_retxid = *tl++; if (*tl++ != rpc_call) { m_freem(mrep); return (EBADRPC); } } else { nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED); } nd->nd_repstat = 0; if (*tl++ != rpc_vers) { nd->nd_repstat = ERPCMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } nfsvers = nfs_vers; if (*tl != nfs_prog) { if (*tl == nqnfs_prog) { nqnfs++; nfsvers = nqnfs_vers; } else { nd->nd_repstat = EPROGUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } } tl++; if (*tl++ != nfsvers) { nd->nd_repstat = EPROGMISMATCH; nd->nd_procnum = NFSPROC_NOOP; return (0); } nd->nd_procnum = fxdr_unsigned(u_long, *tl++); if (nd->nd_procnum == NFSPROC_NULL) return (0); if (nd->nd_procnum >= NFS_NPROCS || (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) || (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) { nd->nd_repstat = EPROCUNAVAIL; nd->nd_procnum = NFSPROC_NOOP; return (0); } auth_type = *tl++; len = fxdr_unsigned(int, *tl++); if (len < 0 || len > RPCAUTH_MAXSIZ) { m_freem(mrep); return (EBADRPC); } /* * Handle auth_unix or auth_kerb. */ if (auth_type == rpc_auth_unix) { len = fxdr_unsigned(int, *++tl); if (len < 0 || len > NFS_MAXNAMLEN) { m_freem(mrep); return (EBADRPC); } nfsm_adv(nfsm_rndup(len)); nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 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_long *, (len + 2)*NFSX_UNSIGNED); for (i = 1; i <= len; i++) if (i < NGROUPS) nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); else tl++; nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); } else if (auth_type == rpc_auth_kerb) { nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); nd->nd_authlen = fxdr_unsigned(int, *tl); uio.uio_resid = nfsm_rndup(nd->nd_authlen); if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { m_freem(mrep); return (EBADRPC); } uio.uio_offset = 0; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; iov.iov_base = (caddr_t)nd->nd_authstr; iov.iov_len = RPCAUTH_MAXSIZ; nfsm_mtouio(&uio, uio.uio_resid); nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); nd->nd_flag |= NFSD_NEEDAUTH; } /* * Do we have any use for the verifier. * According to the "Remote Procedure Call Protocol Spec." it * should be AUTH_NULL, but some clients make it AUTH_UNIX? * For now, just skip over it */ len = fxdr_unsigned(int, *++tl); if (len < 0 || len > RPCAUTH_MAXSIZ) { m_freem(mrep); return (EBADRPC); } if (len > 0) { nfsm_adv(nfsm_rndup(len)); } /* * For nqnfs, get piggybacked lease request. */ if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); nd->nd_nqlflag = fxdr_unsigned(int, *tl); if (nd->nd_nqlflag) { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); nd->nd_duration = fxdr_unsigned(int, *tl); } else nd->nd_duration = NQ_MINLEASE; } else { nd->nd_nqlflag = NQL_NOVAL; nd->nd_duration = NQ_MINLEASE; } nd->nd_md = md; nd->nd_dpos = dpos; return (0);nfsmout: return (error);}/* * Search for a sleeping nfsd and wake it up. * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the * running nfsds will go look for the work in the nfssvc_sock list. */voidnfsrv_wakenfsd(slp) struct nfssvc_sock *slp;{ register struct nfsd *nd = nfsd_head.nd_next; if ((slp->ns_flag & SLP_VALID) == 0) return; while (nd != (struct nfsd *)&nfsd_head) { if (nd->nd_flag & NFSD_WAITING) { nd->nd_flag &= ~NFSD_WAITING; if (nd->nd_slp) panic("nfsd wakeup"); slp->ns_sref++; nd->nd_slp = slp; wakeup((caddr_t)nd); return; } nd = nd->nd_next; } slp->ns_flag |= SLP_DOREC; nfsd_head.nd_flag |= NFSD_CHECKSLP;}nfs_msg(p, server, msg) struct proc *p; char *server, *msg;{ tpr_t tpr; if (p) tpr = tprintf_open(p); else tpr = NULL; tprintf(tpr, "nfs server %s: %s\n", server, msg); tprintf_close(tpr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -