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), |
