NULL out cc_data in pluggable TCP {cc}_cb_destroy
When ABE was added (rS331214) to NewReno and leak fixed (rS333699) , it now has a destructor (newreno_cb_destroy) for per connection state. Other congestion controls may allocate and free cc_data on entry and exit, but the field is never explicitly NULLed if moving back to NewReno which only internally allocates stateful data (no entry contstructor) resulting in a situation where newreno_cb_destory might be called on a junk pointer. - NULL out cc_data in the framework after calling {cc}_cb_destroy - free(9) checks for NULL so there is no need to perform not NULL checks before calling free. - Improve a comment about NewReno in tcp_ccalgounload This is the result of a debugging session from Jason Wolfe, Jason Eggleston, and mmacy@ and very helpful insight from lstewart@. Submitted by: Kevin Bowling Reviewed by: lstewart Sponsored by: Limelight Networks Differential Revision: https://reviews.freebsd.org/D16282
This commit is contained in:
parent
8707733f71
commit
2269988749
@ -307,8 +307,7 @@ static void
|
|||||||
chd_cb_destroy(struct cc_var *ccv)
|
chd_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (ccv->cc_data != NULL)
|
free(ccv->cc_data, M_CHD);
|
||||||
free(ccv->cc_data, M_CHD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -213,9 +213,7 @@ cubic_ack_received(struct cc_var *ccv, uint16_t type)
|
|||||||
static void
|
static void
|
||||||
cubic_cb_destroy(struct cc_var *ccv)
|
cubic_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
|
free(ccv->cc_data, M_CUBIC);
|
||||||
if (ccv->cc_data != NULL)
|
|
||||||
free(ccv->cc_data, M_CUBIC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -184,8 +184,7 @@ dctcp_after_idle(struct cc_var *ccv)
|
|||||||
static void
|
static void
|
||||||
dctcp_cb_destroy(struct cc_var *ccv)
|
dctcp_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
if (ccv->cc_data != NULL)
|
free(ccv->cc_data, M_dctcp);
|
||||||
free(ccv->cc_data, M_dctcp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -238,9 +238,7 @@ htcp_ack_received(struct cc_var *ccv, uint16_t type)
|
|||||||
static void
|
static void
|
||||||
htcp_cb_destroy(struct cc_var *ccv)
|
htcp_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
|
free(ccv->cc_data, M_HTCP);
|
||||||
if (ccv->cc_data != NULL)
|
|
||||||
free(ccv->cc_data, M_HTCP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -127,9 +127,7 @@ newreno_malloc(struct cc_var *ccv)
|
|||||||
static void
|
static void
|
||||||
newreno_cb_destroy(struct cc_var *ccv)
|
newreno_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
|
free(ccv->cc_data, M_NEWRENO);
|
||||||
if (ccv->cc_data != NULL)
|
|
||||||
free(ccv->cc_data, M_NEWRENO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -170,9 +170,7 @@ vegas_ack_received(struct cc_var *ccv, uint16_t ack_type)
|
|||||||
static void
|
static void
|
||||||
vegas_cb_destroy(struct cc_var *ccv)
|
vegas_cb_destroy(struct cc_var *ccv)
|
||||||
{
|
{
|
||||||
|
free(ccv->cc_data, M_VEGAS);
|
||||||
if (ccv->cc_data != NULL)
|
|
||||||
free(ccv->cc_data, M_VEGAS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1730,10 +1730,18 @@ tcp_ccalgounload(struct cc_algo *unload_algo)
|
|||||||
*/
|
*/
|
||||||
if (CC_ALGO(tp) == unload_algo) {
|
if (CC_ALGO(tp) == unload_algo) {
|
||||||
tmpalgo = CC_ALGO(tp);
|
tmpalgo = CC_ALGO(tp);
|
||||||
/* NewReno does not require any init. */
|
|
||||||
CC_ALGO(tp) = &newreno_cc_algo;
|
|
||||||
if (tmpalgo->cb_destroy != NULL)
|
if (tmpalgo->cb_destroy != NULL)
|
||||||
tmpalgo->cb_destroy(tp->ccv);
|
tmpalgo->cb_destroy(tp->ccv);
|
||||||
|
CC_DATA(tp) = NULL;
|
||||||
|
/*
|
||||||
|
* NewReno may allocate memory on
|
||||||
|
* demand for certain stateful
|
||||||
|
* configuration as needed, but is
|
||||||
|
* coded to never fail on memory
|
||||||
|
* allocation failure so it is a safe
|
||||||
|
* fallback.
|
||||||
|
*/
|
||||||
|
CC_ALGO(tp) = &newreno_cc_algo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INP_WUNLOCK(inp);
|
INP_WUNLOCK(inp);
|
||||||
@ -1885,6 +1893,7 @@ tcp_discardcb(struct tcpcb *tp)
|
|||||||
/* Allow the CC algorithm to clean up after itself. */
|
/* Allow the CC algorithm to clean up after itself. */
|
||||||
if (CC_ALGO(tp)->cb_destroy != NULL)
|
if (CC_ALGO(tp)->cb_destroy != NULL)
|
||||||
CC_ALGO(tp)->cb_destroy(tp->ccv);
|
CC_ALGO(tp)->cb_destroy(tp->ccv);
|
||||||
|
CC_DATA(tp) = NULL;
|
||||||
|
|
||||||
#ifdef TCP_HHOOK
|
#ifdef TCP_HHOOK
|
||||||
khelp_destroy_osd(tp->osd);
|
khelp_destroy_osd(tp->osd);
|
||||||
|
@ -1729,6 +1729,7 @@ tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp
|
|||||||
*/
|
*/
|
||||||
if (CC_ALGO(tp)->cb_destroy != NULL)
|
if (CC_ALGO(tp)->cb_destroy != NULL)
|
||||||
CC_ALGO(tp)->cb_destroy(tp->ccv);
|
CC_ALGO(tp)->cb_destroy(tp->ccv);
|
||||||
|
CC_DATA(tp) = NULL;
|
||||||
CC_ALGO(tp) = algo;
|
CC_ALGO(tp) = algo;
|
||||||
/*
|
/*
|
||||||
* If something goes pear shaped initialising the new
|
* If something goes pear shaped initialising the new
|
||||||
|
Loading…
Reference in New Issue
Block a user