aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2007-11-28 08:15:40 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:11 -0500
commit276f2edc52e309b38a216245952e05880e182c83 (patch)
tree3f581eb831a6f7f16ab30bd0f8e8d80b5b97fe50
parentea4f76ae13b4240dac304ed50636391d6b22e9c5 (diff)
[TFRC]: Migrate TX history to singly-linked lis
This patch was based on another made by Gerrit Renker, his changelog was: ------------------------------------------------------ The patch set migrates TFRC TX history to a singly-linked list. The details are: * use of a consistent naming scheme (all TFRC functions now begin with `tfrc_'); * allocation and cleanup are taken care of internally; * provision of a lookup function, which is used by the CCID TX infrastructure to determine the time a packet was sent (in turn used for RTT sampling); * integration of the new interface with the present use in CCID3. ------------------------------------------------------ Simplifications I did: . removing the tfrc_tx_hist_head that had a pointer to the list head and another for the slabcache. . No need for creating a slabcache for each CCID that wants to use the TFRC tx history routines, create a single slabcache when the dccp_tfrc_lib module init routine is called. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/dccp/ccids/ccid3.c57
-rw-r--r--net/dccp/ccids/ccid3.h3
-rw-r--r--net/dccp/ccids/lib/loss_interval.c12
-rw-r--r--net/dccp/ccids/lib/packet_history.c138
-rw-r--r--net/dccp/ccids/lib/packet_history.h79
5 files changed, 102 insertions, 187 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 42893b1dfa09..f73542ab9d08 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -49,7 +49,6 @@ static int ccid3_debug;
49#define ccid3_pr_debug(format, a...) 49#define ccid3_pr_debug(format, a...)
50#endif 50#endif
51 51
52static struct dccp_tx_hist *ccid3_tx_hist;
53static struct dccp_rx_hist *ccid3_rx_hist; 52static struct dccp_rx_hist *ccid3_rx_hist;
54 53
55/* 54/*
@@ -389,28 +388,18 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
389 unsigned int len) 388 unsigned int len)
390{ 389{
391 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); 390 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
392 struct dccp_tx_hist_entry *packet;
393 391
394 ccid3_hc_tx_update_s(hctx, len); 392 ccid3_hc_tx_update_s(hctx, len);
395 393
396 packet = dccp_tx_hist_entry_new(ccid3_tx_hist, GFP_ATOMIC); 394 if (tfrc_tx_hist_add(&hctx->ccid3hctx_hist, dccp_sk(sk)->dccps_gss))
397 if (unlikely(packet == NULL)) {
398 DCCP_CRIT("packet history - out of memory!"); 395 DCCP_CRIT("packet history - out of memory!");
399 return;
400 }
401 dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet);
402
403 packet->dccphtx_tstamp = ktime_get_real();
404 packet->dccphtx_seqno = dccp_sk(sk)->dccps_gss;
405 packet->dccphtx_rtt = hctx->ccid3hctx_rtt;
406 packet->dccphtx_sent = 1;
407} 396}
408 397
409static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) 398static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
410{ 399{
411 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); 400 struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
412 struct ccid3_options_received *opt_recv; 401 struct ccid3_options_received *opt_recv;
413 struct dccp_tx_hist_entry *packet; 402 struct tfrc_tx_hist_entry *packet;
414 ktime_t now; 403 ktime_t now;
415 unsigned long t_nfb; 404 unsigned long t_nfb;
416 u32 pinv, r_sample; 405 u32 pinv, r_sample;
@@ -425,16 +414,19 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
425 switch (hctx->ccid3hctx_state) { 414 switch (hctx->ccid3hctx_state) {
426 case TFRC_SSTATE_NO_FBACK: 415 case TFRC_SSTATE_NO_FBACK:
427 case TFRC_SSTATE_FBACK: 416 case TFRC_SSTATE_FBACK:
428 /* get packet from history to look up t_recvdata */ 417 /* estimate RTT from history if ACK number is valid */
429 packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, 418 packet = tfrc_tx_hist_find_entry(hctx->ccid3hctx_hist,
430 DCCP_SKB_CB(skb)->dccpd_ack_seq); 419 DCCP_SKB_CB(skb)->dccpd_ack_seq);
431 if (unlikely(packet == NULL)) { 420 if (packet == NULL) {
432 DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist " 421 DCCP_WARN("%s(%p): %s with bogus ACK-%llu\n", dccp_role(sk), sk,
433 "in history!\n", dccp_role(sk), sk, 422 dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type),
434 (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, 423 (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq);
435 dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
436 return; 424 return;
437 } 425 }
426 /*
427 * Garbage-collect older (irrelevant) entries
428 */
429 tfrc_tx_hist_purge(&packet->next);
438 430
439 /* Update receive rate in units of 64 * bytes/second */ 431 /* Update receive rate in units of 64 * bytes/second */
440 hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate; 432 hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;
@@ -451,7 +443,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
451 /* 443 /*
452 * Calculate new RTT sample and update moving average 444 * Calculate new RTT sample and update moving average
453 */ 445 */
454 r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, packet->dccphtx_tstamp)); 446 r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, packet->stamp));
455 hctx->ccid3hctx_rtt = tfrc_ewma(hctx->ccid3hctx_rtt, r_sample, 9); 447 hctx->ccid3hctx_rtt = tfrc_ewma(hctx->ccid3hctx_rtt, r_sample, 9);
456 448
457 if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) { 449 if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
@@ -493,9 +485,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
493 /* unschedule no feedback timer */ 485 /* unschedule no feedback timer */
494 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); 486 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
495 487
496 /* remove all packets older than the one acked from history */
497 dccp_tx_hist_purge_older(ccid3_tx_hist,
498 &hctx->ccid3hctx_hist, packet);
499 /* 488 /*
500 * As we have calculated new ipi, delta, t_nom it is possible 489 * As we have calculated new ipi, delta, t_nom it is possible
501 * that we now can send a packet, so wake up dccp_wait_for_ccid 490 * that we now can send a packet, so wake up dccp_wait_for_ccid
@@ -598,7 +587,7 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
598 struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid); 587 struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
599 588
600 hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; 589 hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
601 INIT_LIST_HEAD(&hctx->ccid3hctx_hist); 590 hctx->ccid3hctx_hist = NULL;
602 setup_timer(&hctx->ccid3hctx_no_feedback_timer, 591 setup_timer(&hctx->ccid3hctx_no_feedback_timer,
603 ccid3_hc_tx_no_feedback_timer, (unsigned long)sk); 592 ccid3_hc_tx_no_feedback_timer, (unsigned long)sk);
604 593
@@ -612,8 +601,7 @@ static void ccid3_hc_tx_exit(struct sock *sk)
612 ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM); 601 ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
613 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); 602 sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
614 603
615 /* Empty packet history */ 604 tfrc_tx_hist_purge(&hctx->ccid3hctx_hist);
616 dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
617} 605}
618 606
619static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) 607static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1036,19 +1024,12 @@ static __init int ccid3_module_init(void)
1036 if (ccid3_rx_hist == NULL) 1024 if (ccid3_rx_hist == NULL)
1037 goto out; 1025 goto out;
1038 1026
1039 ccid3_tx_hist = dccp_tx_hist_new("ccid3");
1040 if (ccid3_tx_hist == NULL)
1041 goto out_free_rx;
1042
1043 rc = ccid_register(&ccid3); 1027 rc = ccid_register(&ccid3);
1044 if (rc != 0) 1028 if (rc != 0)
1045 goto out_free_tx; 1029 goto out_free_rx;
1046out: 1030out:
1047 return rc; 1031 return rc;
1048 1032
1049out_free_tx:
1050 dccp_tx_hist_delete(ccid3_tx_hist);
1051 ccid3_tx_hist = NULL;
1052out_free_rx: 1033out_free_rx:
1053 dccp_rx_hist_delete(ccid3_rx_hist); 1034 dccp_rx_hist_delete(ccid3_rx_hist);
1054 ccid3_rx_hist = NULL; 1035 ccid3_rx_hist = NULL;
@@ -1060,10 +1041,6 @@ static __exit void ccid3_module_exit(void)
1060{ 1041{
1061 ccid_unregister(&ccid3); 1042 ccid_unregister(&ccid3);
1062 1043
1063 if (ccid3_tx_hist != NULL) {
1064 dccp_tx_hist_delete(ccid3_tx_hist);
1065 ccid3_tx_hist = NULL;
1066 }
1067 if (ccid3_rx_hist != NULL) { 1044 if (ccid3_rx_hist != NULL) {
1068 dccp_rx_hist_delete(ccid3_rx_hist); 1045 dccp_rx_hist_delete(ccid3_rx_hist);
1069 ccid3_rx_hist = NULL; 1046 ccid3_rx_hist = NULL;
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index 36eca34228f0..b842a7dd99de 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -40,6 +40,7 @@
40#include <linux/list.h> 40#include <linux/list.h>
41#include <linux/types.h> 41#include <linux/types.h>
42#include <linux/tfrc.h> 42#include <linux/tfrc.h>
43#include "lib/packet_history.h"
43#include "../ccid.h" 44#include "../ccid.h"
44 45
45/* Two seconds as per RFC 3448 4.2 */ 46/* Two seconds as per RFC 3448 4.2 */
@@ -111,7 +112,7 @@ struct ccid3_hc_tx_sock {
111 ktime_t ccid3hctx_t_ld; 112 ktime_t ccid3hctx_t_ld;
112 ktime_t ccid3hctx_t_nom; 113 ktime_t ccid3hctx_t_nom;
113 u32 ccid3hctx_delta; 114 u32 ccid3hctx_delta;
114 struct list_head ccid3hctx_hist; 115 struct tfrc_tx_hist_entry *ccid3hctx_hist;
115 struct ccid3_options_received ccid3hctx_options_received; 116 struct ccid3_options_received ccid3hctx_options_received;
116}; 117};
117 118
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index d26b88dbbb45..f2ca4eb74ddb 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -277,7 +277,7 @@ void dccp_li_update_li(struct sock *sk,
277 277
278EXPORT_SYMBOL_GPL(dccp_li_update_li); 278EXPORT_SYMBOL_GPL(dccp_li_update_li);
279 279
280static __init int dccp_li_init(void) 280int __init dccp_li_init(void)
281{ 281{
282 dccp_li_cachep = kmem_cache_create("dccp_li_hist", 282 dccp_li_cachep = kmem_cache_create("dccp_li_hist",
283 sizeof(struct dccp_li_hist_entry), 283 sizeof(struct dccp_li_hist_entry),
@@ -285,10 +285,10 @@ static __init int dccp_li_init(void)
285 return dccp_li_cachep == NULL ? -ENOBUFS : 0; 285 return dccp_li_cachep == NULL ? -ENOBUFS : 0;
286} 286}
287 287
288static __exit void dccp_li_exit(void) 288void dccp_li_exit(void)
289{ 289{
290 kmem_cache_destroy(dccp_li_cachep); 290 if (dccp_li_cachep != NULL) {
291 kmem_cache_destroy(dccp_li_cachep);
292 dccp_li_cachep = NULL;
293 }
291} 294}
292
293module_init(dccp_li_init);
294module_exit(dccp_li_exit);
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index 34c4f6047724..139736064713 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * net/dccp/packet_history.c 2 * net/dccp/packet_history.c
3 * 3 *
4 * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand. 4 * Copyright (c) 2007 The University of Aberdeen, Scotland, UK
5 * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
5 * 6 *
6 * An implementation of the DCCP protocol 7 * An implementation of the DCCP protocol
7 * 8 *
@@ -39,93 +40,48 @@
39#include "packet_history.h" 40#include "packet_history.h"
40 41
41/* 42/*
42 * Transmitter History Routines 43 * Transmitter History Routines
43 */ 44 */
44struct dccp_tx_hist *dccp_tx_hist_new(const char *name) 45static struct kmem_cache *tfrc_tx_hist;
45{
46 struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
47 static const char dccp_tx_hist_mask[] = "tx_hist_%s";
48 char *slab_name;
49 46
50 if (hist == NULL) 47struct tfrc_tx_hist_entry *
51 goto out; 48 tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno)
52
53 slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
54 GFP_ATOMIC);
55 if (slab_name == NULL)
56 goto out_free_hist;
57
58 sprintf(slab_name, dccp_tx_hist_mask, name);
59 hist->dccptxh_slab = kmem_cache_create(slab_name,
60 sizeof(struct dccp_tx_hist_entry),
61 0, SLAB_HWCACHE_ALIGN,
62 NULL);
63 if (hist->dccptxh_slab == NULL)
64 goto out_free_slab_name;
65out:
66 return hist;
67out_free_slab_name:
68 kfree(slab_name);
69out_free_hist:
70 kfree(hist);
71 hist = NULL;
72 goto out;
73}
74
75EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
76
77void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
78{ 49{
79 const char* name = kmem_cache_name(hist->dccptxh_slab); 50 while (head != NULL && head->seqno != seqno)
51 head = head->next;
80 52
81 kmem_cache_destroy(hist->dccptxh_slab); 53 return head;
82 kfree(name);
83 kfree(hist);
84} 54}
55EXPORT_SYMBOL_GPL(tfrc_tx_hist_find_entry);
85 56
86EXPORT_SYMBOL_GPL(dccp_tx_hist_delete); 57int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno)
87
88struct dccp_tx_hist_entry *
89 dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
90{ 58{
91 struct dccp_tx_hist_entry *packet = NULL, *entry; 59 struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist, gfp_any());
92 60
93 list_for_each_entry(entry, list, dccphtx_node) 61 if (entry == NULL)
94 if (entry->dccphtx_seqno == seq) { 62 return -ENOBUFS;
95 packet = entry; 63 entry->seqno = seqno;
96 break; 64 entry->stamp = ktime_get_real();
97 } 65 entry->next = *headp;
98 66 *headp = entry;
99 return packet; 67 return 0;
100} 68}
69EXPORT_SYMBOL_GPL(tfrc_tx_hist_add);
101 70
102EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry); 71void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp)
103
104void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
105{ 72{
106 struct dccp_tx_hist_entry *entry, *next; 73 struct tfrc_tx_hist_entry *head = *headp;
107 74
108 list_for_each_entry_safe(entry, next, list, dccphtx_node) { 75 while (head != NULL) {
109 list_del_init(&entry->dccphtx_node); 76 struct tfrc_tx_hist_entry *next = head->next;
110 dccp_tx_hist_entry_delete(hist, entry);
111 }
112}
113
114EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
115 77
116void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist, 78 kmem_cache_free(tfrc_tx_hist, head);
117 struct list_head *list, 79 head = next;
118 struct dccp_tx_hist_entry *packet)
119{
120 struct dccp_tx_hist_entry *next;
121
122 list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
123 list_del_init(&packet->dccphtx_node);
124 dccp_tx_hist_entry_delete(hist, packet);
125 } 80 }
126}
127 81
128EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older); 82 *headp = NULL;
83}
84EXPORT_SYMBOL_GPL(tfrc_tx_hist_purge);
129 85
130/* 86/*
131 * Receiver History Routines 87 * Receiver History Routines
@@ -147,8 +103,7 @@ struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
147 sprintf(slab_name, dccp_rx_hist_mask, name); 103 sprintf(slab_name, dccp_rx_hist_mask, name);
148 hist->dccprxh_slab = kmem_cache_create(slab_name, 104 hist->dccprxh_slab = kmem_cache_create(slab_name,
149 sizeof(struct dccp_rx_hist_entry), 105 sizeof(struct dccp_rx_hist_entry),
150 0, SLAB_HWCACHE_ALIGN, 106 0, SLAB_HWCACHE_ALIGN, NULL);
151 NULL);
152 if (hist->dccprxh_slab == NULL) 107 if (hist->dccprxh_slab == NULL)
153 goto out_free_slab_name; 108 goto out_free_slab_name;
154out: 109out:
@@ -293,6 +248,37 @@ void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
293 248
294EXPORT_SYMBOL_GPL(dccp_rx_hist_purge); 249EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
295 250
251extern int __init dccp_li_init(void);
252extern void dccp_li_exit(void);
253
254static __init int packet_history_init(void)
255{
256 if (dccp_li_init() != 0)
257 goto out;
258
259 tfrc_tx_hist = kmem_cache_create("tfrc_tx_hist",
260 sizeof(struct tfrc_tx_hist_entry), 0,
261 SLAB_HWCACHE_ALIGN, NULL);
262 if (tfrc_tx_hist == NULL)
263 goto out_li_exit;
264
265 return 0;
266out_li_exit:
267 dccp_li_exit();
268out:
269 return -ENOBUFS;
270}
271module_init(packet_history_init);
272
273static __exit void packet_history_exit(void)
274{
275 if (tfrc_tx_hist != NULL) {
276 kmem_cache_destroy(tfrc_tx_hist);
277 tfrc_tx_hist = NULL;
278 }
279 dccp_li_exit();
280}
281module_exit(packet_history_exit);
296 282
297MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, " 283MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
298 "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>"); 284 "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
index 032bb61c6e39..5c07182dd659 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -1,10 +1,9 @@
1/* 1/*
2 * net/dccp/packet_history.h 2 * Packet RX/TX history data structures and routines for TFRC-based protocols.
3 * 3 *
4 * Copyright (c) 2007 The University of Aberdeen, Scotland, UK
4 * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand. 5 * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand.
5 * 6 *
6 * An implementation of the DCCP protocol
7 *
8 * This code has been developed by the University of Waikato WAND 7 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/ 8 * research group. For further information please see http://www.wand.net.nz/
10 * or e-mail Ian McDonald - ian.mcdonald@jandi.co.nz 9 * or e-mail Ian McDonald - ian.mcdonald@jandi.co.nz
@@ -49,71 +48,23 @@
49#define TFRC_WIN_COUNT_PER_RTT 4 48#define TFRC_WIN_COUNT_PER_RTT 4
50#define TFRC_WIN_COUNT_LIMIT 16 49#define TFRC_WIN_COUNT_LIMIT 16
51 50
52/* 51/**
53 * Transmitter History data structures and declarations 52 * tfrc_tx_hist_entry - Simple singly-linked TX history list
53 * @next: next oldest entry (LIFO order)
54 * @seqno: sequence number of this entry
55 * @stamp: send time of packet with sequence number @seqno
54 */ 56 */
55struct dccp_tx_hist_entry { 57struct tfrc_tx_hist_entry {
56 struct list_head dccphtx_node; 58 struct tfrc_tx_hist_entry *next;
57 u64 dccphtx_seqno:48, 59 u64 seqno;
58 dccphtx_sent:1; 60 ktime_t stamp;
59 u32 dccphtx_rtt;
60 ktime_t dccphtx_tstamp;
61};
62
63struct dccp_tx_hist {
64 struct kmem_cache *dccptxh_slab;
65}; 61};
66 62
67extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name); 63extern int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno);
68extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist); 64extern void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp);
69
70static inline struct dccp_tx_hist_entry *
71 dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
72 const gfp_t prio)
73{
74 struct dccp_tx_hist_entry *entry = kmem_cache_alloc(hist->dccptxh_slab,
75 prio);
76
77 if (entry != NULL)
78 entry->dccphtx_sent = 0;
79
80 return entry;
81}
82
83static inline struct dccp_tx_hist_entry *
84 dccp_tx_hist_head(struct list_head *list)
85{
86 struct dccp_tx_hist_entry *head = NULL;
87
88 if (!list_empty(list))
89 head = list_entry(list->next, struct dccp_tx_hist_entry,
90 dccphtx_node);
91 return head;
92}
93
94extern struct dccp_tx_hist_entry *
95 dccp_tx_hist_find_entry(const struct list_head *list,
96 const u64 seq);
97
98static inline void dccp_tx_hist_add_entry(struct list_head *list,
99 struct dccp_tx_hist_entry *entry)
100{
101 list_add(&entry->dccphtx_node, list);
102}
103
104static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
105 struct dccp_tx_hist_entry *entry)
106{
107 if (entry != NULL)
108 kmem_cache_free(hist->dccptxh_slab, entry);
109}
110
111extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
112 struct list_head *list);
113 65
114extern void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist, 66extern struct tfrc_tx_hist_entry *
115 struct list_head *list, 67 tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 ackno);
116 struct dccp_tx_hist_entry *next);
117 68
118/* 69/*
119 * Receiver History data structures and declarations 70 * Receiver History data structures and declarations