FreeBSD/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
/*
 * Optimized version of soreceive() for stream (TCP) sockets.
 */
Optimized version of soreceive() for stream (TCP) sockets.
Optimized version of soreceive () for stream ( TCP ) sockets .
static int
sdp_sorecv(struct socket *so, struct sockaddr **psa, struct uio *uio,
    struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
{
	int len = 0, error = 0, flags, oresid;
	struct sockbuf *sb;
	struct mbuf *m, *n = NULL;
	struct sdp_sock *ssk;
	if (so->so_type != SOCK_STREAM)
		return (EINVAL);
	if (psa != NULL)
		*psa = NULL;
	if (controlp != NULL)
		return (EINVAL);
	if (flagsp != NULL)
		flags = *flagsp &~ MSG_EOR;
	else
		flags = 0;
	if (flags & MSG_OOB)
		return (soreceive_rcvoob(so, uio, flags));
	if (mp0 != NULL)
		*mp0 = NULL;
	sb = &so->so_rcv;
	ssk = sdp_sk(so);
	error = sblock(sb, SBLOCKWAIT(flags));
	if (error)
		goto out;
	SOCKBUF_LOCK(sb);
	if (uio->uio_resid == 0) {
		error = EINVAL;
		goto out;
	}
	oresid = uio->uio_resid;
	if (!(so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED))) {
		if (sbavail(sb))
			goto deliver;
		if (!(so->so_state & SS_ISDISCONNECTED))
			error = ENOTCONN;
		goto out;
	}
	if (sbavail(sb) == 0 &&
	    ((so->so_state & SS_NBIO) || (flags & (MSG_DONTWAIT|MSG_NBIO)))) {
		error = EAGAIN;
		goto out;
	}
restart:
	SOCKBUF_LOCK_ASSERT(&so->so_rcv);
	if (so->so_error) {
		if (sbavail(sb))
			goto deliver;
		if (oresid > uio->uio_resid)
			goto out;
		error = so->so_error;
		if (!(flags & MSG_PEEK))
			so->so_error = 0;
		goto out;
	}
	if (sb->sb_state & SBS_CANTRCVMORE) {
		if (sbavail(sb))
			goto deliver;
		else
			goto out;
	}
	if (sbavail(sb) && !(flags & MSG_WAITALL) &&
	    ((so->so_state & SS_NBIO) ||
	     (flags & (MSG_DONTWAIT|MSG_NBIO)) ||
	     sbavail(sb) >= sb->sb_lowat ||
	     sbavail(sb) >= uio->uio_resid ||
	     sbavail(sb) >= sb->sb_hiwat) ) {
		goto deliver;
	}
	if ((flags & MSG_WAITALL) &&
	    (sbavail(sb) >= uio->uio_resid || sbavail(sb) >= sb->sb_lowat))
		goto deliver;
	error = sbwait(sb);
	if (error)
		goto out;
	goto restart;
deliver:
	SOCKBUF_LOCK_ASSERT(&so->so_rcv);
	KASSERT(sbavail(sb), ("%s: sockbuf empty", __func__));
	KASSERT(sb->sb_mb != NULL, ("%s: sb_mb == NULL", __func__));
	if (uio->uio_td)
		uio->uio_td->td_ru.ru_msgrcv++;
	len = min(uio->uio_resid, sbavail(sb));
	if (mp0 != NULL) {
		if (!(flags & MSG_PEEK) && len >= sb->sb_mb->m_len) {
			for (*mp0 = m = sb->sb_mb;
			     m != NULL && m->m_len <= len;
			     m = m->m_next) {
				len -= m->m_len;
				uio->uio_resid -= m->m_len;
				sbfree(sb, m);
				n = m;
			}
			sb->sb_mb = m;
			if (sb->sb_mb == NULL)
				SB_EMPTY_FIXUP(sb);
			n->m_next = NULL;
		}
		if (len > 0) {
			KASSERT(sb->sb_mb != NULL,
			    ("%s: len > 0 && sb->sb_mb empty", __func__));
			m = m_copym(sb->sb_mb, 0, len, M_NOWAIT);
			if (m == NULL)
				len = 0;	
			else
				uio->uio_resid -= m->m_len;
			if (*mp0 != NULL)
				n->m_next = m;
			else
				*mp0 = m;
			if (*mp0 == NULL) {
				error = ENOBUFS;
				goto out;
			}
		}
	} else {
		SOCKBUF_UNLOCK(sb);
		error = m_mbuftouio(uio, sb->sb_mb, len);
		SOCKBUF_LOCK(sb);
		if (error)
			goto out;
	}
	SBLASTRECORDCHK(sb);
	SBLASTMBUFCHK(sb);
	if (!(flags & MSG_PEEK)) {
		if (len > 0)
			sbdrop_locked(sb, len);
		SOCKBUF_UNLOCK(sb);
		SDP_WLOCK(ssk);
		sdp_do_posts(ssk);
		SDP_WUNLOCK(ssk);
		SOCKBUF_LOCK(sb);
	}
	if ((flags & MSG_WAITALL) && uio->uio_resid > 0)
		goto restart;
out:
	SOCKBUF_LOCK_ASSERT(sb);
	SBLASTRECORDCHK(sb);
	SBLASTMBUFCHK(sb);
	SOCKBUF_UNLOCK(sb);
	sbunlock(sb);
	return (error);
}
static int sdp_sorecv ( struct socket * so , struct sockaddr * * psa , struct uio * uio , struct mbuf * * mp0 , struct mbuf * * controlp , int * flagsp ) { int len = 0 , error = 0 , flags , oresid ; struct sockbuf * sb ; struct mbuf * m , * n = NULL ; struct sdp_sock * ssk ; if ( so -> so_type != SOCK_STREAM ) return ( EINVAL ) ; if ( psa != NULL ) * psa = NULL ; if ( controlp != NULL ) return ( EINVAL ) ; if ( flagsp != NULL ) flags = * flagsp & ~ MSG_EOR ; else flags = 0 ; if ( flags & MSG_OOB ) return ( soreceive_rcvoob ( so , uio , flags ) ) ; if ( mp0 != NULL ) * mp0 = NULL ; sb = & so -> so_rcv ; ssk = sdp_sk ( so ) ; error = sblock ( sb , SBLOCKWAIT ( flags ) ) ; if ( error ) goto out ; SOCKBUF_LOCK ( sb ) ; if ( uio -> uio_resid == 0 ) { error = EINVAL ; goto out ; } oresid = uio -> uio_resid ; if ( ! ( so -> so_state & ( SS_ISCONNECTED | SS_ISDISCONNECTED ) ) ) { if ( sbavail ( sb ) ) goto deliver ; if ( ! ( so -> so_state & SS_ISDISCONNECTED ) ) error = ENOTCONN ; goto out ; } if ( sbavail ( sb ) == 0 && ( ( so -> so_state & SS_NBIO ) || ( flags & ( MSG_DONTWAIT | MSG_NBIO ) ) ) ) { error = EAGAIN ; goto out ; } restart : SOCKBUF_LOCK_ASSERT ( & so -> so_rcv ) ; if ( so -> so_error ) { if ( sbavail ( sb ) ) goto deliver ; if ( oresid > uio -> uio_resid ) goto out ; error = so -> so_error ; if ( ! ( flags & MSG_PEEK ) ) so -> so_error = 0 ; goto out ; } if ( sb -> sb_state & SBS_CANTRCVMORE ) { if ( sbavail ( sb ) ) goto deliver ; else goto out ; } if ( sbavail ( sb ) && ! ( flags & MSG_WAITALL ) && ( ( so -> so_state & SS_NBIO ) || ( flags & ( MSG_DONTWAIT | MSG_NBIO ) ) || sbavail ( sb ) >= sb -> sb_lowat || sbavail ( sb ) >= uio -> uio_resid || sbavail ( sb ) >= sb -> sb_hiwat ) ) { goto deliver ; } if ( ( flags & MSG_WAITALL ) && ( sbavail ( sb ) >= uio -> uio_resid || sbavail ( sb ) >= sb -> sb_lowat ) ) goto deliver ; error = sbwait ( sb ) ; if ( error ) goto out ; goto restart ; deliver : SOCKBUF_LOCK_ASSERT ( & so -> so_rcv ) ; KASSERT ( sbavail ( sb ) , ( " " , __func__ ) ) ; KASSERT ( sb -> sb_mb != NULL , ( " " , __func__ ) ) ; if ( uio -> uio_td ) uio -> uio_td -> td_ru . ru_msgrcv ++ ; len = min ( uio -> uio_resid , sbavail ( sb ) ) ; if ( mp0 != NULL ) { if ( ! ( flags & MSG_PEEK ) && len >= sb -> sb_mb -> m_len ) { for ( * mp0 = m = sb -> sb_mb ; m != NULL && m -> m_len <= len ; m = m -> m_next ) { len -= m -> m_len ; uio -> uio_resid -= m -> m_len ; sbfree ( sb , m ) ; n = m ; } sb -> sb_mb = m ; if ( sb -> sb_mb == NULL ) SB_EMPTY_FIXUP ( sb ) ; n -> m_next = NULL ; } if ( len > 0 ) { KASSERT ( sb -> sb_mb != NULL , ( " " , __func__ ) ) ; m = m_copym ( sb -> sb_mb , 0 , len , M_NOWAIT ) ; if ( m == NULL ) len = 0 ; else uio -> uio_resid -= m -> m_len ; if ( * mp0 != NULL ) n -> m_next = m ; else * mp0 = m ; if ( * mp0 == NULL ) { error = ENOBUFS ; goto out ; } } } else { SOCKBUF_UNLOCK ( sb ) ; error = m_mbuftouio ( uio , sb -> sb_mb , len ) ; SOCKBUF_LOCK ( sb ) ; if ( error ) goto out ; } SBLASTRECORDCHK ( sb ) ; SBLASTMBUFCHK ( sb ) ; if ( ! ( flags & MSG_PEEK ) ) { if ( len > 0 ) sbdrop_locked ( sb , len ) ; SOCKBUF_UNLOCK ( sb ) ; SDP_WLOCK ( ssk ) ; sdp_do_posts ( ssk ) ; SDP_WUNLOCK ( ssk ) ; SOCKBUF_LOCK ( sb ) ; } if ( ( flags & MSG_WAITALL ) && uio -> uio_resid > 0 ) goto restart ; out : SOCKBUF_LOCK_ASSERT ( sb ) ; SBLASTRECORDCHK ( sb ) ; SBLASTMBUFCHK ( sb ) ; SOCKBUF_UNLOCK ( sb ) ; sbunlock ( sb ) ; return ( error ) ; }
Optimized version of soreceive() for stream (TCP) sockets.
Optimized version of soreceive () for stream ( TCP ) sockets .
/* We only do stream sockets. */ /* Prevent other readers from entering the socket. */ /* Easy one, no space to copyout anything. */ /* We will never ever get anything unless we are connected. */ /* When disconnecting there may be still some data left. */ /* Socket buffer is empty and we shall not block. */ /* Abort if socket has reported problems. */ /* Door is closed.  Deliver what is left, if any. */ /* Socket buffer got some data that we shall deliver now. */ /* On MSG_WAITALL we must wait until all data or error arrives. */ /*
	 * Wait and block until (more) data comes in.
	 * NB: Drops the sockbuf lock during wait.
	 */ /* Statistics. */ /* Fill uio until full or current end of socket buffer is reached. */ /* Dequeue as many mbufs as possible. */ /* Copy the remainder. */ /* Don't flush data from sockbuf. */ /* NB: Must unlock socket buffer as uiomove may sleep. */ /*
	 * Remove the delivered data from the socket buffer unless we
	 * were only peeking.
	 */ /* Notify protocol that we drained some data. */ /*
	 * For MSG_WAITALL we may have to loop again and wait for
	 * more data to come in.
	 */