inpcb: don't return INP_DROPPED entries from pcb lookups
The in_pcbdrop() KPI, which is used solely by TCP, allows to remove a pcb from hash list and mark it as dropped. The comment suggests that such pcb won't be returned by lookups. Indeed, every call to in_pcblookup*() is accompanied by a check for INP_DROPPED. Do what comment suggests: never return such pcbs and remove unnecessary checks. Reviewed by: tuexen Differential revision: https://reviews.freebsd.org/D37061
This commit is contained in:
parent
b5c3819c7b
commit
f567d55f51
@ -1536,15 +1536,15 @@ in_pcbrele(struct inpcb *inp, const inp_lookup_t lock)
|
|||||||
in_pcbrele_rlocked(inp) : in_pcbrele_wlocked(inp));
|
in_pcbrele_rlocked(inp) : in_pcbrele_wlocked(inp));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static inline bool
|
||||||
inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock)
|
_inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock, const int ignflags)
|
||||||
{
|
{
|
||||||
|
|
||||||
MPASS(lock == INPLOOKUP_RLOCKPCB || lock == INPLOOKUP_WLOCKPCB);
|
MPASS(lock == INPLOOKUP_RLOCKPCB || lock == INPLOOKUP_WLOCKPCB);
|
||||||
SMR_ASSERT_ENTERED(inp->inp_pcbinfo->ipi_smr);
|
SMR_ASSERT_ENTERED(inp->inp_pcbinfo->ipi_smr);
|
||||||
|
|
||||||
if (__predict_true(inp_trylock(inp, lock))) {
|
if (__predict_true(inp_trylock(inp, lock))) {
|
||||||
if (__predict_false(inp->inp_flags & INP_FREED)) {
|
if (__predict_false(inp->inp_flags & ignflags)) {
|
||||||
smr_exit(inp->inp_pcbinfo->ipi_smr);
|
smr_exit(inp->inp_pcbinfo->ipi_smr);
|
||||||
inp_unlock(inp, lock);
|
inp_unlock(inp, lock);
|
||||||
return (false);
|
return (false);
|
||||||
@ -1564,7 +1564,7 @@ inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock)
|
|||||||
* through in_pcbfree() and has another reference, that
|
* through in_pcbfree() and has another reference, that
|
||||||
* prevented its release by our in_pcbrele().
|
* prevented its release by our in_pcbrele().
|
||||||
*/
|
*/
|
||||||
if (__predict_false(inp->inp_flags & INP_FREED)) {
|
if (__predict_false(inp->inp_flags & ignflags)) {
|
||||||
inp_unlock(inp, lock);
|
inp_unlock(inp, lock);
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
@ -1575,6 +1575,18 @@ inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in_pcblookup() family of functions ignore not only freed entries,
|
||||||
|
* that may be found due to lockless access to the hash, but dropped
|
||||||
|
* entries, too.
|
||||||
|
*/
|
||||||
|
return (_inp_smr_lock(inp, lock, INP_FREED | INP_DROPPED));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inp_next() - inpcb hash/list traversal iterator
|
* inp_next() - inpcb hash/list traversal iterator
|
||||||
*
|
*
|
||||||
@ -1631,7 +1643,7 @@ inp_next(struct inpcb_iterator *ii)
|
|||||||
inp = II_LIST_NEXT(inp, hash)) {
|
inp = II_LIST_NEXT(inp, hash)) {
|
||||||
if (match != NULL && (match)(inp, ctx) == false)
|
if (match != NULL && (match)(inp, ctx) == false)
|
||||||
continue;
|
continue;
|
||||||
if (__predict_true(inp_smr_lock(inp, lock)))
|
if (__predict_true(_inp_smr_lock(inp, lock, INP_FREED)))
|
||||||
break;
|
break;
|
||||||
else {
|
else {
|
||||||
smr_enter(ipi->ipi_smr);
|
smr_enter(ipi->ipi_smr);
|
||||||
|
@ -937,16 +937,7 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port)
|
|||||||
goto dropwithreset;
|
goto dropwithreset;
|
||||||
}
|
}
|
||||||
INP_LOCK_ASSERT(inp);
|
INP_LOCK_ASSERT(inp);
|
||||||
/*
|
|
||||||
* While waiting for inp lock during the lookup, another thread
|
|
||||||
* can have dropped the inpcb, in which case we need to loop back
|
|
||||||
* and try to find a new inpcb to deliver to.
|
|
||||||
*/
|
|
||||||
if (inp->inp_flags & INP_DROPPED) {
|
|
||||||
INP_UNLOCK(inp);
|
|
||||||
inp = NULL;
|
|
||||||
goto findpcb;
|
|
||||||
}
|
|
||||||
if ((inp->inp_flowtype == M_HASHTYPE_NONE) &&
|
if ((inp->inp_flowtype == M_HASHTYPE_NONE) &&
|
||||||
(M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) &&
|
(M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) &&
|
||||||
((inp->inp_socket == NULL) || !SOLISTENING(inp->inp_socket))) {
|
((inp->inp_socket == NULL) || !SOLISTENING(inp->inp_socket))) {
|
||||||
|
@ -1360,9 +1360,7 @@ tcp_lro_flush_tcphpts(struct lro_ctrl *lc, struct lro_entry *le)
|
|||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
|
|
||||||
/* Check if the inp is dead, Jim. */
|
/* Check if the inp is dead, Jim. */
|
||||||
if (tp == NULL ||
|
if (tp->t_state == TCPS_TIME_WAIT) {
|
||||||
(inp->inp_flags & INP_DROPPED) ||
|
|
||||||
(tp->t_state == TCPS_TIME_WAIT)) {
|
|
||||||
INP_WUNLOCK(inp);
|
INP_WUNLOCK(inp);
|
||||||
return (TCP_LRO_CANNOT);
|
return (TCP_LRO_CANNOT);
|
||||||
}
|
}
|
||||||
|
@ -2878,8 +2878,7 @@ tcp_ctlinput_with_port(struct icmp *icp, uint16_t port)
|
|||||||
inp = in_pcblookup(&V_tcbinfo, ip->ip_dst, th->th_dport, ip->ip_src,
|
inp = in_pcblookup(&V_tcbinfo, ip->ip_dst, th->th_dport, ip->ip_src,
|
||||||
th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
|
th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
|
||||||
if (inp != NULL) {
|
if (inp != NULL) {
|
||||||
if (!(inp->inp_flags & INP_DROPPED) &&
|
if (inp->inp_socket != NULL) {
|
||||||
!(inp->inp_socket == NULL)) {
|
|
||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
#ifdef TCP_OFFLOAD
|
#ifdef TCP_OFFLOAD
|
||||||
if (tp->t_flags & TF_TOE && errno == EMSGSIZE) {
|
if (tp->t_flags & TF_TOE && errno == EMSGSIZE) {
|
||||||
@ -3071,8 +3070,7 @@ tcp6_ctlinput_with_port(struct ip6ctlparam *ip6cp, uint16_t port)
|
|||||||
}
|
}
|
||||||
m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
|
m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
|
||||||
if (inp != NULL) {
|
if (inp != NULL) {
|
||||||
if (!(inp->inp_flags & INP_DROPPED) &&
|
if (inp->inp_socket != NULL) {
|
||||||
!(inp->inp_socket == NULL)) {
|
|
||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
#ifdef TCP_OFFLOAD
|
#ifdef TCP_OFFLOAD
|
||||||
if (tp->t_flags & TF_TOE && errno == EMSGSIZE) {
|
if (tp->t_flags & TF_TOE && errno == EMSGSIZE) {
|
||||||
@ -3697,8 +3695,7 @@ sysctl_drop(SYSCTL_HANDLER_ARGS)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (inp != NULL) {
|
if (inp != NULL) {
|
||||||
if ((inp->inp_flags & INP_DROPPED) == 0 &&
|
if (!SOLISTENING(inp->inp_socket)) {
|
||||||
!SOLISTENING(inp->inp_socket)) {
|
|
||||||
tp = intotcpcb(inp);
|
tp = intotcpcb(inp);
|
||||||
tp = tcp_drop(tp, ECONNABORTED);
|
tp = tcp_drop(tp, ECONNABORTED);
|
||||||
if (tp != NULL)
|
if (tp != NULL)
|
||||||
@ -3817,8 +3814,7 @@ sysctl_switch_tls(SYSCTL_HANDLER_ARGS)
|
|||||||
}
|
}
|
||||||
NET_EPOCH_EXIT(et);
|
NET_EPOCH_EXIT(et);
|
||||||
if (inp != NULL) {
|
if (inp != NULL) {
|
||||||
if ((inp->inp_flags & INP_DROPPED) != 0 ||
|
if (inp->inp_socket == NULL) {
|
||||||
inp->inp_socket == NULL) {
|
|
||||||
error = ECONNRESET;
|
error = ECONNRESET;
|
||||||
INP_WUNLOCK(inp);
|
INP_WUNLOCK(inp);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user