@@ -66,22 +66,27 @@ static inline struct fq_skb_cb *fq_skb_cb(struct sk_buff *skb)
66
66
* in linear list (head,tail), otherwise are placed in a rbtree (t_root).
67
67
*/
68
68
struct fq_flow {
69
+ /* First cache line : used in fq_gc(), fq_enqueue(), fq_dequeue() */
69
70
struct rb_root t_root ;
70
71
struct sk_buff * head ; /* list of skbs for this flow : first skb */
71
72
union {
72
73
struct sk_buff * tail ; /* last skb in the list */
73
- unsigned long age ; /* jiffies when flow was emptied, for gc */
74
+ unsigned long age ; /* ( jiffies | 1UL) when flow was emptied, for gc */
74
75
};
75
76
struct rb_node fq_node ; /* anchor in fq_root[] trees */
76
77
struct sock * sk ;
78
+ u32 socket_hash ; /* sk_hash */
77
79
int qlen ; /* number of packets in flow queue */
80
+
81
+ /* Second cache line, used in fq_dequeue() */
78
82
int credit ;
79
- u32 socket_hash ; /* sk_hash */
80
- struct fq_flow * next ; /* next pointer in RR lists, or &detached */
83
+ /* 32bit hole on 64bit arches */
84
+
85
+ struct fq_flow * next ; /* next pointer in RR lists */
81
86
82
87
struct rb_node rate_node ; /* anchor in q->delayed tree */
83
88
u64 time_next_packet ;
84
- };
89
+ } ____cacheline_aligned_in_smp ;
85
90
86
91
struct fq_flow_head {
87
92
struct fq_flow * first ;
@@ -126,20 +131,25 @@ struct fq_sched_data {
126
131
struct qdisc_watchdog watchdog ;
127
132
};
128
133
129
- /* special value to mark a detached flow (not on old/new list) */
130
- static struct fq_flow detached , throttled ;
131
-
134
+ /*
135
+ * f->tail and f->age share the same location.
136
+ * We can use the low order bit to differentiate if this location points
137
+ * to a sk_buff or contains a jiffies value, if we force this value to be odd.
138
+ * This assumes f->tail low order bit must be 0 since alignof(struct sk_buff) >= 2
139
+ */
132
140
static void fq_flow_set_detached (struct fq_flow * f )
133
141
{
134
- f -> next = & detached ;
135
- f -> age = jiffies ;
142
+ f -> age = jiffies | 1UL ;
136
143
}
137
144
138
145
static bool fq_flow_is_detached (const struct fq_flow * f )
139
146
{
140
- return f -> next == & detached ;
147
+ return !!( f -> age & 1UL ) ;
141
148
}
142
149
150
+ /* special value to mark a throttled flow (not on old/new list) */
151
+ static struct fq_flow throttled ;
152
+
143
153
static bool fq_flow_is_throttled (const struct fq_flow * f )
144
154
{
145
155
return f -> next == & throttled ;
@@ -204,9 +214,10 @@ static void fq_gc(struct fq_sched_data *q,
204
214
struct rb_root * root ,
205
215
struct sock * sk )
206
216
{
207
- struct fq_flow * f , * tofree [FQ_GC_MAX ];
208
217
struct rb_node * * p , * parent ;
209
- int fcnt = 0 ;
218
+ void * tofree [FQ_GC_MAX ];
219
+ struct fq_flow * f ;
220
+ int i , fcnt = 0 ;
210
221
211
222
p = & root -> rb_node ;
212
223
parent = NULL ;
@@ -229,15 +240,18 @@ static void fq_gc(struct fq_sched_data *q,
229
240
p = & parent -> rb_left ;
230
241
}
231
242
243
+ if (!fcnt )
244
+ return ;
245
+
246
+ for (i = fcnt ; i > 0 ; ) {
247
+ f = tofree [-- i ];
248
+ rb_erase (& f -> fq_node , root );
249
+ }
232
250
q -> flows -= fcnt ;
233
251
q -> inactive_flows -= fcnt ;
234
252
q -> stat_gc_flows += fcnt ;
235
- while (fcnt ) {
236
- struct fq_flow * f = tofree [-- fcnt ];
237
253
238
- rb_erase (& f -> fq_node , root );
239
- kmem_cache_free (fq_flow_cachep , f );
240
- }
254
+ kmem_cache_free_bulk (fq_flow_cachep , fcnt , tofree );
241
255
}
242
256
243
257
static struct fq_flow * fq_classify (struct sk_buff * skb , struct fq_sched_data * q )
@@ -370,19 +384,17 @@ static void fq_erase_head(struct Qdisc *sch, struct fq_flow *flow,
370
384
}
371
385
}
372
386
373
- /* remove one skb from head of flow queue */
374
- static struct sk_buff * fq_dequeue_head (struct Qdisc * sch , struct fq_flow * flow )
387
+ /* Remove one skb from flow queue.
388
+ * This skb must be the return value of prior fq_peek().
389
+ */
390
+ static void fq_dequeue_skb (struct Qdisc * sch , struct fq_flow * flow ,
391
+ struct sk_buff * skb )
375
392
{
376
- struct sk_buff * skb = fq_peek (flow );
377
-
378
- if (skb ) {
379
- fq_erase_head (sch , flow , skb );
380
- skb_mark_not_on_list (skb );
381
- flow -> qlen -- ;
382
- qdisc_qstats_backlog_dec (sch , skb );
383
- sch -> q .qlen -- ;
384
- }
385
- return skb ;
393
+ fq_erase_head (sch , flow , skb );
394
+ skb_mark_not_on_list (skb );
395
+ flow -> qlen -- ;
396
+ qdisc_qstats_backlog_dec (sch , skb );
397
+ sch -> q .qlen -- ;
386
398
}
387
399
388
400
static void flow_queue_add (struct fq_flow * flow , struct sk_buff * skb )
@@ -494,9 +506,11 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
494
506
if (!sch -> q .qlen )
495
507
return NULL ;
496
508
497
- skb = fq_dequeue_head (sch , & q -> internal );
498
- if (skb )
509
+ skb = fq_peek (& q -> internal );
510
+ if (unlikely (skb )) {
511
+ fq_dequeue_skb (sch , & q -> internal , skb );
499
512
goto out ;
513
+ }
500
514
501
515
now = ktime_get_ns ();
502
516
fq_check_throttled (q , now );
@@ -532,14 +546,13 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
532
546
fq_flow_set_throttled (q , f );
533
547
goto begin ;
534
548
}
549
+ prefetch (& skb -> end );
535
550
if ((s64 )(now - time_next_packet - q -> ce_threshold ) > 0 ) {
536
551
INET_ECN_set_ce (skb );
537
552
q -> stat_ce_mark ++ ;
538
553
}
539
- }
540
-
541
- skb = fq_dequeue_head (sch , f );
542
- if (!skb ) {
554
+ fq_dequeue_skb (sch , f , skb );
555
+ } else {
543
556
head -> first = f -> next ;
544
557
/* force a pass through old_flows to prevent starvation */
545
558
if ((head == & q -> new_flows ) && q -> old_flows .first ) {
@@ -550,7 +563,6 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
550
563
}
551
564
goto begin ;
552
565
}
553
- prefetch (& skb -> end );
554
566
plen = qdisc_pkt_len (skb );
555
567
f -> credit -= plen ;
556
568
0 commit comments