tcp: fix leaks in tcp_chg_pacing_rate error paths

tcp_chg_pacing_rate() is expected to release the hw rate limit table,
but failed to do so in several error cases, leading to ever
increasing counts of flows using the rate.

This patch was mostly done by rrs

Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D34058
Reviewed by: hselasky, rrs,  jhb (inital version, outside of Differential)
This commit is contained in:
Andrew Gallatin
2022-01-27 10:35:03 -05:00
parent 9ba117960e
commit 8a7404b2ae
+21
View File
@@ -1411,6 +1411,7 @@ tcp_chg_pacing_rate(const struct tcp_hwrate_limit_table *crte,
* tags if it didn't allocate one when an
* existing rate was present, so ignore.
*/
tcp_rel_pacing_rate(crte, tp);
if (error)
*error = EOPNOTSUPP;
return (NULL);
@@ -1419,6 +1420,7 @@ tcp_chg_pacing_rate(const struct tcp_hwrate_limit_table *crte,
#endif
if (tp->t_inpcb->inp_snd_tag == NULL) {
/* Wrong interface */
tcp_rel_pacing_rate(crte, tp);
if (error)
*error = EINVAL;
return (NULL);
@@ -1457,10 +1459,29 @@ tcp_chg_pacing_rate(const struct tcp_hwrate_limit_table *crte,
#endif
err = in_pcbmodify_txrtlmt(tp->t_inpcb, nrte->rate);
if (err) {
struct tcp_rate_set *lrs;
uint64_t pre;
rl_decrement_using(nrte);
lrs = __DECONST(struct tcp_rate_set *, rs);
pre = atomic_fetchadd_64(&lrs->rs_flows_using, -1);
/* Do we still have a snd-tag attached? */
if (tp->t_inpcb->inp_snd_tag)
in_pcbdetach_txrtlmt(tp->t_inpcb);
if (pre == 1) {
struct epoch_tracker et;
NET_EPOCH_ENTER(et);
mtx_lock(&rs_mtx);
/*
* Is it dead?
*/
if (lrs->rs_flags & RS_IS_DEAD)
rs_defer_destroy(lrs);
mtx_unlock(&rs_mtx);
NET_EPOCH_EXIT(et);
}
if (error)
*error = err;
return (NULL);