⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs_socket.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 * For reliable protocols, lock against other senders/receivers	 * in case a reconnect is necessary.	 * For SOCK_STREAM, first get the Record Mark to find out how much	 * more there is to get.	 * We must lock the socket against other receivers	 * until we have an entire rpc request/reply.	 */	if (sotype != SOCK_DGRAM) {		if (error = nfs_sndlock(&rep->r_nmp->nm_flag, rep))			return (error);tryagain:		/*		 * Check for fatal errors and resending request.		 */		/*		 * Ugh: If a reconnect attempt just happened, nm_so		 * would have changed. NULL indicates a failed		 * attempt that has essentially shut down this		 * mount point.		 */		if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {			nfs_sndunlock(&rep->r_nmp->nm_flag);			return (EINTR);		}		if ((so = rep->r_nmp->nm_so) == NULL) {			if (error = nfs_reconnect(rep)) {				nfs_sndunlock(&rep->r_nmp->nm_flag);				return (error);			}			goto tryagain;		}		while (rep->r_flags & R_MUSTRESEND) {			m = m_copym(rep->r_mreq, 0, M_COPYALL, M_WAIT);			nfsstats.rpcretries++;			if (error = nfs_send(so, rep->r_nmp->nm_nam, m, rep)) {				if (error == EINTR || error == ERESTART ||				    (error = nfs_reconnect(rep))) {					nfs_sndunlock(&rep->r_nmp->nm_flag);					return (error);				}				goto tryagain;			}		}		nfs_sndunlock(&rep->r_nmp->nm_flag);		if (sotype == SOCK_STREAM) {			aio.iov_base = (caddr_t) &len;			aio.iov_len = sizeof(u_long);			auio.uio_iov = &aio;			auio.uio_iovcnt = 1;			auio.uio_segflg = UIO_SYSSPACE;			auio.uio_rw = UIO_READ;			auio.uio_offset = 0;			auio.uio_resid = sizeof(u_long);			auio.uio_procp = p;			do {			   rcvflg = MSG_WAITALL;			   error = soreceive(so, (struct mbuf **)0, &auio,				(struct mbuf **)0, (struct mbuf **)0, &rcvflg);			   if (error == EWOULDBLOCK && rep) {				if (rep->r_flags & R_SOFTTERM)					return (EINTR);			   }			} while (error == EWOULDBLOCK);			if (!error && auio.uio_resid > 0) {			    log(LOG_INFO,				 "short receive (%d/%d) from nfs server %s\n",				 sizeof(u_long) - auio.uio_resid,				 sizeof(u_long),				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);			    error = EPIPE;			}			if (error)				goto errout;			len = ntohl(len) & ~0x80000000;			/*			 * This is SERIOUS! We are out of sync with the sender			 * and forcing a disconnect/reconnect is all I can do.			 */			if (len > NFS_MAXPACKET) {			    log(LOG_ERR, "%s (%d) from nfs server %s\n",				"impossible packet length",				len,				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);			    error = EFBIG;			    goto errout;			}			auio.uio_resid = len;			do {			    rcvflg = MSG_WAITALL;			    error =  soreceive(so, (struct mbuf **)0,				&auio, mp, (struct mbuf **)0, &rcvflg);			} while (error == EWOULDBLOCK || error == EINTR ||				 error == ERESTART);			if (!error && auio.uio_resid > 0) {			    log(LOG_INFO,				"short receive (%d/%d) from nfs server %s\n",				len - auio.uio_resid, len,				rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);			    error = EPIPE;			}		} else {			/*			 * NB: Since uio_resid is big, MSG_WAITALL is ignored			 * and soreceive() will return when it has either a			 * control msg or a data msg.			 * We have no use for control msg., but must grab them			 * and then throw them away so we know what is going			 * on.			 */			auio.uio_resid = len = 100000000; /* Anything Big */			auio.uio_procp = p;			do {			    rcvflg = 0;			    error =  soreceive(so, (struct mbuf **)0,				&auio, mp, &control, &rcvflg);			    if (control)				m_freem(control);			    if (error == EWOULDBLOCK && rep) {				if (rep->r_flags & R_SOFTTERM)					return (EINTR);			    }			} while (error == EWOULDBLOCK ||				 (!error && *mp == NULL && control));			if ((rcvflg & MSG_EOR) == 0)				printf("Egad!!\n");			if (!error && *mp == NULL)				error = EPIPE;			len -= auio.uio_resid;		}errout:		if (error && error != EINTR && error != ERESTART) {			m_freem(*mp);			*mp = (struct mbuf *)0;			if (error != EPIPE)				log(LOG_INFO,				    "receive error %d from nfs server %s\n",				    error,				 rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);			error = nfs_sndlock(&rep->r_nmp->nm_flag, rep);			if (!error)				error = nfs_reconnect(rep);			if (!error)				goto tryagain;		}	} else {		if ((so = rep->r_nmp->nm_so) == NULL)			return (EACCES);		if (so->so_state & SS_ISCONNECTED)			getnam = (struct mbuf **)0;		else			getnam = aname;		auio.uio_resid = len = 1000000;		auio.uio_procp = p;		do {			rcvflg = 0;			error =  soreceive(so, getnam, &auio, mp,				(struct mbuf **)0, &rcvflg);			if (error == EWOULDBLOCK &&			    (rep->r_flags & R_SOFTTERM))				return (EINTR);		} while (error == EWOULDBLOCK);		len -= auio.uio_resid;	}	if (error) {		m_freem(*mp);		*mp = (struct mbuf *)0;	}	/*	 * Search for any mbufs that are not a multiple of 4 bytes long	 * or with m_data not longword aligned.	 * These could cause pointer alignment problems, so copy them to	 * well aligned mbufs.	 */	nfs_realign(*mp, 5 * NFSX_UNSIGNED);	return (error);}/* * Implement receipt of reply on a socket. * We must search through the list of received datagrams matching them * with outstanding requests using the xid, until ours is found. *//* ARGSUSED */nfs_reply(myrep)	struct nfsreq *myrep;{	register struct nfsreq *rep;	register struct nfsmount *nmp = myrep->r_nmp;	register long t1;	struct mbuf *mrep, *nam, *md;	u_long rxid, *tl;	caddr_t dpos, cp2;	int error;	/*	 * Loop around until we get our own reply	 */	for (;;) {		/*		 * Lock against other receivers so that I don't get stuck in		 * sbwait() after someone else has received my reply for me.		 * Also necessary for connection based protocols to avoid		 * race conditions during a reconnect.		 */		if (error = nfs_rcvlock(myrep))			return (error);		/* Already received, bye bye */		if (myrep->r_mrep != NULL) {			nfs_rcvunlock(&nmp->nm_flag);			return (0);		}		/*		 * Get the next Rpc reply off the socket		 */		error = nfs_receive(myrep, &nam, &mrep);		nfs_rcvunlock(&nmp->nm_flag);		if (error) {			/*			 * Ignore routing errors on connectionless protocols??			 */			if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) {				nmp->nm_so->so_error = 0;				if (myrep->r_flags & R_GETONEREP)					return (0);				continue;			}			return (error);		}		if (nam)			m_freem(nam);			/*		 * Get the xid and check that it is an rpc reply		 */		md = mrep;		dpos = mtod(md, caddr_t);		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);		rxid = *tl++;		if (*tl != rpc_reply) {			if (nmp->nm_flag & NFSMNT_NQNFS) {				if (nqnfs_callback(nmp, mrep, md, dpos))					nfsstats.rpcinvalid++;			} else {				nfsstats.rpcinvalid++;				m_freem(mrep);			}nfsmout:			if (myrep->r_flags & R_GETONEREP)				return (0);			continue;		}		/*		 * Loop through the request list to match up the reply		 * Iff no match, just drop the datagram		 */		rep = nfsreqh.r_next;		while (rep != &nfsreqh) {			if (rep->r_mrep == NULL && rxid == rep->r_xid) {				/* Found it.. */				rep->r_mrep = mrep;				rep->r_md = md;				rep->r_dpos = dpos;				if (nfsrtton) {					struct rttl *rt;					rt = &nfsrtt.rttl[nfsrtt.pos];					rt->proc = rep->r_procnum;					rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]);					rt->sent = nmp->nm_sent;					rt->cwnd = nmp->nm_cwnd;					rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1];					rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1];					rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid;					rt->tstamp = time;					if (rep->r_flags & R_TIMING)						rt->rtt = rep->r_rtt;					else						rt->rtt = 1000000;					nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ;				}				/*				 * Update congestion window.				 * Do the additive increase of				 * one rpc/rtt.				 */				if (nmp->nm_cwnd <= nmp->nm_sent) {					nmp->nm_cwnd +=					   (NFS_CWNDSCALE * NFS_CWNDSCALE +					   (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd;					if (nmp->nm_cwnd > NFS_MAXCWND)						nmp->nm_cwnd = NFS_MAXCWND;				}				rep->r_flags &= ~R_SENT;				nmp->nm_sent -= NFS_CWNDSCALE;				/*				 * Update rtt using a gain of 0.125 on the mean				 * and a gain of 0.25 on the deviation.				 */				if (rep->r_flags & R_TIMING) {					/*					 * Since the timer resolution of					 * NFS_HZ is so course, it can often					 * result in r_rtt == 0. Since					 * r_rtt == N means that the actual					 * rtt is between N+dt and N+2-dt ticks,					 * add 1.					 */					t1 = rep->r_rtt + 1;					t1 -= (NFS_SRTT(rep) >> 3);					NFS_SRTT(rep) += t1;					if (t1 < 0)						t1 = -t1;					t1 -= (NFS_SDRTT(rep) >> 2);					NFS_SDRTT(rep) += t1;				}				nmp->nm_timeouts = 0;				break;			}			rep = rep->r_next;		}		/*		 * If not matched to a request, drop it.		 * If it's mine, get out.		 */		if (rep == &nfsreqh) {			nfsstats.rpcunexpected++;			m_freem(mrep);		} else if (rep == myrep) {			if (rep->r_mrep == NULL)				panic("nfsreply nil");			return (0);		}		if (myrep->r_flags & R_GETONEREP)			return (0);	}}/* * nfs_request - goes something like this *	- fill in request struct *	- links it into list *	- calls nfs_send() for first transmit *	- 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 */nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)	struct vnode *vp;	struct mbuf *mrest;	int procnum;	struct proc *procp;	struct ucred *cred;	struct mbuf **mrp;	struct mbuf **mdp;	caddr_t *dposp;{	register struct mbuf *m, *mrep;	register struct nfsreq *rep;	register u_long *tl;	register int i;	struct nfsmount *nmp;	struct mbuf *md, *mheadend;	struct nfsreq *reph;	struct nfsnode *np;	time_t reqtime, waituntil;	caddr_t dpos, cp2;	int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type;	int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0;	u_long xid;	u_quad_t frev;	char *auth_str;	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;	/*	 * Get the RPC header with authorization.	 */kerbauth:	auth_str = (char *)0;	if (nmp->nm_flag & NFSMNT_KERB) {		if (failed_auth) {			error = nfs_getauth(nmp, rep, cred, &auth_type,				&auth_str, &auth_len);			if (error) {				free((caddr_t)rep, M_NFSREQ);				m_freem(mrest);				return (error);			}		} else {			auth_type = RPCAUTH_UNIX;			auth_len = 5 * NFSX_UNSIGNED;		}	} 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;	}	m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum,	     auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid);	if (auth_str)		free(auth_str, M_TEMP);	/*	 * For stream protocols, insert a Sun RPC Record Mark.	 */	if (nmp->nm_sotype == SOCK_STREAM) {		M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);		*mtod(m, u_long *) = htonl(0x80000000 |			 (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;	else		rep->r_retry = NFS_MAXREXMIT + 1;	/* past clip limit */	rep->r_rtt = rep->r_rexmit = 0;	if (proct[procnum] > 0)		rep->r_flags = R_TIMING;	else		rep->r_flags = 0;	rep->r_mrep = NULL;	/*	 * Do the client side RPC.	 */	nfsstats.rpcrequests++;	/*	 * Chain request into list of outstanding requests. Be sure	 * to put it LAST so timer finds oldest requests first.	 */	s = splsoftclock();	reph = &nfsreqh;	reph->r_prev->r_next = rep;	rep->r_prev = reph->r_prev;	reph->r_prev = rep;	rep->r_next = reph;	/* Get send time for nqnfs */	reqtime = time.tv_sec;	/*	 * If backing off another request or avoiding congestion, don't	 * send this one now but let timer do it. If not timing a request,	 * do it now.	 */	if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM ||		(nmp->nm_flag & NFSMNT_DUMBTIMR) ||		nmp->nm_sent < nmp->nm_cwnd)) {		splx(s);		if (nmp->nm_soflags & PR_CONNREQUIRED)			error = nfs_sndlock(&nmp->nm_flag, rep);		if (!error) {			m = m_copym(m, 0, M_COPYALL, M_WAIT);			error = nfs_send(nmp->nm_so, nmp->nm_nam, m, rep);			if (nmp->nm_soflags & PR_CONNREQUIRED)				nfs_sndunlock(&nmp->nm_flag);		}		if (!error && (rep->r_flags & R_MUSTRESEND) == 0) {			nmp->nm_sent += NFS_CWNDSCALE;			rep->r_flags |= R_SENT;		}	} else {		splx(s);		rep->r_rtt = -1;	}	/*	 * Wait for the reply from our send or the timer's.	 */	if (!error || error == EPIPE)		error = nfs_reply(rep);	/*	 * RPC done, unlink the request.	 */	s = splsoftclock();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -