diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2007-03-20 13:56:11 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:26:52 -0400 |
commit | 1266adee12d25385a25e1c57b1e3ff05a90bb4d7 (patch) | |
tree | eb42be8ede3ca9d5ac00076ebee20be5771c30ee /net/dccp | |
parent | 8699be7d240e37c91a84bdf32e79941d72bc7bd5 (diff) |
[CCID3]: Remove race condition and update t_ipi when `s' changes
This:
1. removes a race condition in the access to the scheduled send time t_nom which
results from allowing asynchronous r/w access to t_nom without locks;
2. updates the inter-packet interval t_ipi = s/X when `s' changes, following a
suggestion by Ian McDonald.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 35 |
1 files changed, 12 insertions, 23 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 26ab73db2868..95eca99e4dd9 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -82,20 +82,14 @@ static void ccid3_hc_tx_set_state(struct sock *sk, | |||
82 | } | 82 | } |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * Recalculate scheduled nominal send time t_nom, inter-packet interval | 85 | * Recalculate t_ipi and delta (should be called whenever X changes) |
86 | * t_ipi, and delta value. Should be called after each change to X. | ||
87 | */ | 86 | */ |
88 | static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) | 87 | static inline void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx) |
89 | { | 88 | { |
90 | timeval_sub_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); | ||
91 | |||
92 | /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */ | 89 | /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */ |
93 | hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s, | 90 | hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s, |
94 | hctx->ccid3hctx_x >> 6); | 91 | hctx->ccid3hctx_x >> 6); |
95 | 92 | ||
96 | /* Update nominal send time with regard to the new t_ipi */ | ||
97 | timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); | ||
98 | |||
99 | /* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */ | 93 | /* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */ |
100 | hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2, | 94 | hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2, |
101 | TFRC_OPSYS_HALF_TIME_GRAN); | 95 | TFRC_OPSYS_HALF_TIME_GRAN); |
@@ -119,8 +113,6 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) | |||
119 | * fine-grained resolution of sending rates. This requires scaling by 2^6 | 113 | * fine-grained resolution of sending rates. This requires scaling by 2^6 |
120 | * throughout the code. Only X_calc is unscaled (in bytes/second). | 114 | * throughout the code. Only X_calc is unscaled (in bytes/second). |
121 | * | 115 | * |
122 | * If X has changed, we also update the scheduled send time t_now, | ||
123 | * the inter-packet interval t_ipi, and the delta value. | ||
124 | */ | 116 | */ |
125 | static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) | 117 | static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) |
126 | 118 | ||
@@ -151,7 +143,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) | |||
151 | "X_recv=%llu\n", old_x >> 6, hctx->ccid3hctx_x >> 6, | 143 | "X_recv=%llu\n", old_x >> 6, hctx->ccid3hctx_x >> 6, |
152 | hctx->ccid3hctx_x_calc, hctx->ccid3hctx_x_recv >> 6); | 144 | hctx->ccid3hctx_x_calc, hctx->ccid3hctx_x_recv >> 6); |
153 | 145 | ||
154 | ccid3_update_send_time(hctx); | 146 | ccid3_update_send_interval(hctx); |
155 | } | 147 | } |
156 | } | 148 | } |
157 | 149 | ||
@@ -161,14 +153,12 @@ static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) | |||
161 | */ | 153 | */ |
162 | static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) | 154 | static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) |
163 | { | 155 | { |
164 | hctx->ccid3hctx_s = hctx->ccid3hctx_s == 0 ? len : | 156 | const u16 old_s = hctx->ccid3hctx_s; |
165 | (9 * hctx->ccid3hctx_s + len) / 10; | 157 | |
166 | /* | 158 | hctx->ccid3hctx_s = old_s == 0 ? len : (9 * old_s + len) / 10; |
167 | * Note: We could do a potential optimisation here - when `s' changes, | 159 | |
168 | * recalculate sending rate and consequently t_ipi, t_delta, and | 160 | if (hctx->ccid3hctx_s != old_s) |
169 | * t_now. This is however non-standard, and the benefits are not | 161 | ccid3_update_send_interval(hctx); |
170 | * clear, so it is currently left out. | ||
171 | */ | ||
172 | } | 162 | } |
173 | 163 | ||
174 | /* | 164 | /* |
@@ -228,7 +218,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
228 | /* The value of R is still undefined and so we can not recompute | 218 | /* The value of R is still undefined and so we can not recompute |
229 | * the timout value. Keep initial value as per [RFC 4342, 5]. */ | 219 | * the timout value. Keep initial value as per [RFC 4342, 5]. */ |
230 | t_nfb = TFRC_INITIAL_TIMEOUT; | 220 | t_nfb = TFRC_INITIAL_TIMEOUT; |
231 | ccid3_update_send_time(hctx); | 221 | ccid3_update_send_interval(hctx); |
232 | break; | 222 | break; |
233 | case TFRC_SSTATE_FBACK: | 223 | case TFRC_SSTATE_FBACK: |
234 | /* | 224 | /* |
@@ -334,8 +324,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
334 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); | 324 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); |
335 | 325 | ||
336 | /* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */ | 326 | /* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */ |
337 | ccid3_hc_tx_update_s(hctx, skb->len); | 327 | hctx->ccid3hctx_x = hctx->ccid3hctx_s = skb->len; |
338 | hctx->ccid3hctx_x = hctx->ccid3hctx_s; | ||
339 | hctx->ccid3hctx_x <<= 6; | 328 | hctx->ccid3hctx_x <<= 6; |
340 | 329 | ||
341 | /* First timeout, according to [RFC 3448, 4.2], is 1 second */ | 330 | /* First timeout, according to [RFC 3448, 4.2], is 1 second */ |
@@ -484,7 +473,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
484 | hctx->ccid3hctx_x = scaled_div(w_init << 6, r_sample); | 473 | hctx->ccid3hctx_x = scaled_div(w_init << 6, r_sample); |
485 | hctx->ccid3hctx_t_ld = now; | 474 | hctx->ccid3hctx_t_ld = now; |
486 | 475 | ||
487 | ccid3_update_send_time(hctx); | 476 | ccid3_update_send_interval(hctx); |
488 | 477 | ||
489 | ccid3_pr_debug("%s(%p), s=%u, MSS=%u, w_init=%u, " | 478 | ccid3_pr_debug("%s(%p), s=%u, MSS=%u, w_init=%u, " |
490 | "R_sample=%dus, X=%u\n", dccp_role(sk), | 479 | "R_sample=%dus, X=%u\n", dccp_role(sk), |