1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2016 Facebook
3 */
4 #include <linux/cpumask.h>
5 #include <linux/spinlock.h>
6 #include <linux/percpu.h>
7
8 #include "bpf_lru_list.h"
9
10 #define LOCAL_FREE_TARGET (128)
11 #define LOCAL_NR_SCANS LOCAL_FREE_TARGET
12
13 #define PERCPU_FREE_TARGET (4)
14 #define PERCPU_NR_SCANS PERCPU_FREE_TARGET
15
16 /* Helpers to get the local list index */
17 #define LOCAL_LIST_IDX(t) ((t) - BPF_LOCAL_LIST_T_OFFSET)
18 #define LOCAL_FREE_LIST_IDX LOCAL_LIST_IDX(BPF_LRU_LOCAL_LIST_T_FREE)
19 #define LOCAL_PENDING_LIST_IDX LOCAL_LIST_IDX(BPF_LRU_LOCAL_LIST_T_PENDING)
20 #define IS_LOCAL_LIST_TYPE(t) ((t) >= BPF_LOCAL_LIST_T_OFFSET)
21
22 /* Local list helpers */
local_free_list(struct bpf_lru_locallist * loc_l)23 static struct list_head *local_free_list(struct bpf_lru_locallist *loc_l)
24 {
25 return &loc_l->lists[LOCAL_FREE_LIST_IDX];
26 }
27
local_pending_list(struct bpf_lru_locallist * loc_l)28 static struct list_head *local_pending_list(struct bpf_lru_locallist *loc_l)
29 {
30 return &loc_l->lists[LOCAL_PENDING_LIST_IDX];
31 }
32
33 /* bpf_lru_node helpers */
bpf_lru_node_is_ref(const struct bpf_lru_node * node)34 static bool bpf_lru_node_is_ref(const struct bpf_lru_node *node)
35 {
36 return READ_ONCE(node->ref);
37 }
38
bpf_lru_node_clear_ref(struct bpf_lru_node * node)39 static void bpf_lru_node_clear_ref(struct bpf_lru_node *node)
40 {
41 WRITE_ONCE(node->ref, 0);
42 }
43
bpf_lru_list_count_inc(struct bpf_lru_list * l,enum bpf_lru_list_type type)44 static void bpf_lru_list_count_inc(struct bpf_lru_list *l,
45 enum bpf_lru_list_type type)
46 {
47 if (type < NR_BPF_LRU_LIST_COUNT)
48 l->counts[type]++;
49 }
50
bpf_lru_list_count_dec(struct bpf_lru_list * l,enum bpf_lru_list_type type)51 static void bpf_lru_list_count_dec(struct bpf_lru_list *l,
52 enum bpf_lru_list_type type)
53 {
54 if (type < NR_BPF_LRU_LIST_COUNT)
55 l->counts[type]--;
56 }
57
__bpf_lru_node_move_to_free(struct bpf_lru_list * l,struct bpf_lru_node * node,struct list_head * free_list,enum bpf_lru_list_type tgt_free_type)58 static void __bpf_lru_node_move_to_free(struct bpf_lru_list *l,
59 struct bpf_lru_node *node,
60 struct list_head *free_list,
61 enum bpf_lru_list_type tgt_free_type)
62 {
63 if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type)))
64 return;
65
66 /* If the removing node is the next_inactive_rotation candidate,
67 * move the next_inactive_rotation pointer also.
68 */
69 if (&node->list == l->next_inactive_rotation)
70 l->next_inactive_rotation = l->next_inactive_rotation->prev;
71
72 bpf_lru_list_count_dec(l, node->type);
73
74 node->type = tgt_free_type;
75 list_move(&node->list, free_list);
76 }
77
78 /* Move nodes from local list to the LRU list */
__bpf_lru_node_move_in(struct bpf_lru_list * l,struct bpf_lru_node * node,enum bpf_lru_list_type tgt_type)79 static void __bpf_lru_node_move_in(struct bpf_lru_list *l,
80 struct bpf_lru_node *node,
81 enum bpf_lru_list_type tgt_type)
82 {
83 if (WARN_ON_ONCE(!IS_LOCAL_LIST_TYPE(node->type)) ||
84 WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(tgt_type)))
85 return;
86
87 bpf_lru_list_count_inc(l, tgt_type);
88 node->type = tgt_type;
89 bpf_lru_node_clear_ref(node);
90 list_move(&node->list, &l->lists[tgt_type]);
91 }
92
93 /* Move nodes between or within active and inactive list (like
94 * active to inactive, inactive to active or tail of active back to
95 * the head of active).
96 */
__bpf_lru_node_move(struct bpf_lru_list * l,struct bpf_lru_node * node,enum bpf_lru_list_type tgt_type)97 static void __bpf_lru_node_move(struct bpf_lru_list *l,
98 struct bpf_lru_node *node,
99 enum bpf_lru_list_type tgt_type)
100 {
101 if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type)) ||
102 WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(tgt_type)))
103 return;
104
105 if (node->type != tgt_type) {
106 bpf_lru_list_count_dec(l, node->type);
107 bpf_lru_list_count_inc(l, tgt_type);
108 node->type = tgt_type;
109 }
110 bpf_lru_node_clear_ref(node);
111
112 /* If the moving node is the next_inactive_rotation candidate,
113 * move the next_inactive_rotation pointer also.
114 */
115 if (&node->list == l->next_inactive_rotation)
116 l->next_inactive_rotation = l->next_inactive_rotation->prev;
117
118 list_move(&node->list, &l->lists[tgt_type]);
119 }
120
bpf_lru_list_inactive_low(const struct bpf_lru_list * l)121 static bool bpf_lru_list_inactive_low(const struct bpf_lru_list *l)
122 {
123 return l->counts[BPF_LRU_LIST_T_INACTIVE] <
124 l->counts[BPF_LRU_LIST_T_ACTIVE];
125 }
126
127 /* Rotate the active list:
128 * 1. Start from tail
129 * 2. If the node has the ref bit set, it will be rotated
130 * back to the head of active list with the ref bit cleared.
131 * Give this node one more chance to survive in the active list.
132 * 3. If the ref bit is not set, move it to the head of the
133 * inactive list.
134 * 4. It will at most scan nr_scans nodes
135 */
__bpf_lru_list_rotate_active(struct bpf_lru * lru,struct bpf_lru_list * l)136 static void __bpf_lru_list_rotate_active(struct bpf_lru *lru,
137 struct bpf_lru_list *l)
138 {
139 struct list_head *active = &l->lists[BPF_LRU_LIST_T_ACTIVE];
140 struct bpf_lru_node *node, *tmp_node, *first_node;
141 unsigned int i = 0;
142
143 first_node = list_first_entry(active, struct bpf_lru_node, list);
144 list_for_each_entry_safe_reverse(node, tmp_node, active, list) {
145 if (bpf_lru_node_is_ref(node))
146 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
147 else
148 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_INACTIVE);
149
150 if (++i == lru->nr_scans || node == first_node)
151 break;
152 }
153 }
154
155 /* Rotate the inactive list. It starts from the next_inactive_rotation
156 * 1. If the node has ref bit set, it will be moved to the head
157 * of active list with the ref bit cleared.
158 * 2. If the node does not have ref bit set, it will leave it
159 * at its current location (i.e. do nothing) so that it can
160 * be considered during the next inactive_shrink.
161 * 3. It will at most scan nr_scans nodes
162 */
__bpf_lru_list_rotate_inactive(struct bpf_lru * lru,struct bpf_lru_list * l)163 static void __bpf_lru_list_rotate_inactive(struct bpf_lru *lru,
164 struct bpf_lru_list *l)
165 {
166 struct list_head *inactive = &l->lists[BPF_LRU_LIST_T_INACTIVE];
167 struct list_head *cur, *last, *next = inactive;
168 struct bpf_lru_node *node;
169 unsigned int i = 0;
170
171 if (list_empty(inactive))
172 return;
173
174 last = l->next_inactive_rotation->next;
175 if (last == inactive)
176 last = last->next;
177
178 cur = l->next_inactive_rotation;
179 while (i < lru->nr_scans) {
180 if (cur == inactive) {
181 cur = cur->prev;
182 continue;
183 }
184
185 node = list_entry(cur, struct bpf_lru_node, list);
186 next = cur->prev;
187 if (bpf_lru_node_is_ref(node))
188 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
189 if (cur == last)
190 break;
191 cur = next;
192 i++;
193 }
194
195 l->next_inactive_rotation = next;
196 }
197
198 /* Shrink the inactive list. It starts from the tail of the
199 * inactive list and only move the nodes without the ref bit
200 * set to the designated free list.
201 */
202 static unsigned int
__bpf_lru_list_shrink_inactive(struct bpf_lru * lru,struct bpf_lru_list * l,unsigned int tgt_nshrink,struct list_head * free_list,enum bpf_lru_list_type tgt_free_type)203 __bpf_lru_list_shrink_inactive(struct bpf_lru *lru,
204 struct bpf_lru_list *l,
205 unsigned int tgt_nshrink,
206 struct list_head *free_list,
207 enum bpf_lru_list_type tgt_free_type)
208 {
209 struct list_head *inactive = &l->lists[BPF_LRU_LIST_T_INACTIVE];
210 struct bpf_lru_node *node, *tmp_node;
211 unsigned int nshrinked = 0;
212 unsigned int i = 0;
213
214 list_for_each_entry_safe_reverse(node, tmp_node, inactive, list) {
215 if (bpf_lru_node_is_ref(node)) {
216 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
217 } else if (lru->del_from_htab(lru->del_arg, node)) {
218 __bpf_lru_node_move_to_free(l, node, free_list,
219 tgt_free_type);
220 if (++nshrinked == tgt_nshrink)
221 break;
222 }
223
224 if (++i == lru->nr_scans)
225 break;
226 }
227
228 return nshrinked;
229 }
230
231 /* 1. Rotate the active list (if needed)
232 * 2. Always rotate the inactive list
233 */
__bpf_lru_list_rotate(struct bpf_lru * lru,struct bpf_lru_list * l)234 static void __bpf_lru_list_rotate(struct bpf_lru *lru, struct bpf_lru_list *l)
235 {
236 if (bpf_lru_list_inactive_low(l))
237 __bpf_lru_list_rotate_active(lru, l);
238
239 __bpf_lru_list_rotate_inactive(lru, l);
240 }
241
242 /* Calls __bpf_lru_list_shrink_inactive() to shrink some
243 * ref-bit-cleared nodes and move them to the designated
244 * free list.
245 *
246 * If it cannot get a free node after calling
247 * __bpf_lru_list_shrink_inactive(). It will just remove
248 * one node from either inactive or active list without
249 * honoring the ref-bit. It prefers inactive list to active
250 * list in this situation.
251 */
__bpf_lru_list_shrink(struct bpf_lru * lru,struct bpf_lru_list * l,unsigned int tgt_nshrink,struct list_head * free_list,enum bpf_lru_list_type tgt_free_type)252 static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
253 struct bpf_lru_list *l,
254 unsigned int tgt_nshrink,
255 struct list_head *free_list,
256 enum bpf_lru_list_type tgt_free_type)
257
258 {
259 struct bpf_lru_node *node, *tmp_node;
260 struct list_head *force_shrink_list;
261 unsigned int nshrinked;
262
263 nshrinked = __bpf_lru_list_shrink_inactive(lru, l, tgt_nshrink,
264 free_list, tgt_free_type);
265 if (nshrinked)
266 return nshrinked;
267
268 /* Do a force shrink by ignoring the reference bit */
269 if (!list_empty(&l->lists[BPF_LRU_LIST_T_INACTIVE]))
270 force_shrink_list = &l->lists[BPF_LRU_LIST_T_INACTIVE];
271 else
272 force_shrink_list = &l->lists[BPF_LRU_LIST_T_ACTIVE];
273
274 list_for_each_entry_safe_reverse(node, tmp_node, force_shrink_list,
275 list) {
276 if (lru->del_from_htab(lru->del_arg, node)) {
277 __bpf_lru_node_move_to_free(l, node, free_list,
278 tgt_free_type);
279 return 1;
280 }
281 }
282
283 return 0;
284 }
285
286 /* Flush the nodes from the local pending list to the LRU list */
__local_list_flush(struct bpf_lru_list * l,struct bpf_lru_locallist * loc_l)287 static void __local_list_flush(struct bpf_lru_list *l,
288 struct bpf_lru_locallist *loc_l)
289 {
290 struct bpf_lru_node *node, *tmp_node;
291
292 list_for_each_entry_safe_reverse(node, tmp_node,
293 local_pending_list(loc_l), list) {
294 if (bpf_lru_node_is_ref(node))
295 __bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_ACTIVE);
296 else
297 __bpf_lru_node_move_in(l, node,
298 BPF_LRU_LIST_T_INACTIVE);
299 }
300 }
301
bpf_lru_list_push_free(struct bpf_lru_list * l,struct bpf_lru_node * node)302 static void bpf_lru_list_push_free(struct bpf_lru_list *l,
303 struct bpf_lru_node *node)
304 {
305 unsigned long flags;
306
307 if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type)))
308 return;
309
310 raw_spin_lock_irqsave(&l->lock, flags);
311 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE);
312 raw_spin_unlock_irqrestore(&l->lock, flags);
313 }
314
bpf_lru_list_pop_free_to_local(struct bpf_lru * lru,struct bpf_lru_locallist * loc_l)315 static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
316 struct bpf_lru_locallist *loc_l)
317 {
318 struct bpf_lru_list *l = &lru->common_lru.lru_list;
319 struct bpf_lru_node *node, *tmp_node;
320 unsigned int nfree = 0;
321
322 raw_spin_lock(&l->lock);
323
324 __local_list_flush(l, loc_l);
325
326 __bpf_lru_list_rotate(lru, l);
327
328 list_for_each_entry_safe(node, tmp_node, &l->lists[BPF_LRU_LIST_T_FREE],
329 list) {
330 __bpf_lru_node_move_to_free(l, node, local_free_list(loc_l),
331 BPF_LRU_LOCAL_LIST_T_FREE);
332 if (++nfree == lru->target_free)
333 break;
334 }
335
336 if (nfree < lru->target_free)
337 __bpf_lru_list_shrink(lru, l, lru->target_free - nfree,
338 local_free_list(loc_l),
339 BPF_LRU_LOCAL_LIST_T_FREE);
340
341 raw_spin_unlock(&l->lock);
342 }
343
__local_list_add_pending(struct bpf_lru * lru,struct bpf_lru_locallist * loc_l,int cpu,struct bpf_lru_node * node,u32 hash)344 static void __local_list_add_pending(struct bpf_lru *lru,
345 struct bpf_lru_locallist *loc_l,
346 int cpu,
347 struct bpf_lru_node *node,
348 u32 hash)
349 {
350 *(u32 *)((void *)node + lru->hash_offset) = hash;
351 node->cpu = cpu;
352 node->type = BPF_LRU_LOCAL_LIST_T_PENDING;
353 bpf_lru_node_clear_ref(node);
354 list_add(&node->list, local_pending_list(loc_l));
355 }
356
357 static struct bpf_lru_node *
__local_list_pop_free(struct bpf_lru_locallist * loc_l)358 __local_list_pop_free(struct bpf_lru_locallist *loc_l)
359 {
360 struct bpf_lru_node *node;
361
362 node = list_first_entry_or_null(local_free_list(loc_l),
363 struct bpf_lru_node,
364 list);
365 if (node)
366 list_del(&node->list);
367
368 return node;
369 }
370
371 static struct bpf_lru_node *
__local_list_pop_pending(struct bpf_lru * lru,struct bpf_lru_locallist * loc_l)372 __local_list_pop_pending(struct bpf_lru *lru, struct bpf_lru_locallist *loc_l)
373 {
374 struct bpf_lru_node *node;
375 bool force = false;
376
377 ignore_ref:
378 /* Get from the tail (i.e. older element) of the pending list. */
379 list_for_each_entry_reverse(node, local_pending_list(loc_l),
380 list) {
381 if ((!bpf_lru_node_is_ref(node) || force) &&
382 lru->del_from_htab(lru->del_arg, node)) {
383 list_del(&node->list);
384 return node;
385 }
386 }
387
388 if (!force) {
389 force = true;
390 goto ignore_ref;
391 }
392
393 return NULL;
394 }
395
bpf_percpu_lru_pop_free(struct bpf_lru * lru,u32 hash)396 static struct bpf_lru_node *bpf_percpu_lru_pop_free(struct bpf_lru *lru,
397 u32 hash)
398 {
399 struct list_head *free_list;
400 struct bpf_lru_node *node = NULL;
401 struct bpf_lru_list *l;
402 unsigned long flags;
403 int cpu = raw_smp_processor_id();
404
405 l = per_cpu_ptr(lru->percpu_lru, cpu);
406
407 raw_spin_lock_irqsave(&l->lock, flags);
408
409 __bpf_lru_list_rotate(lru, l);
410
411 free_list = &l->lists[BPF_LRU_LIST_T_FREE];
412 if (list_empty(free_list))
413 __bpf_lru_list_shrink(lru, l, PERCPU_FREE_TARGET, free_list,
414 BPF_LRU_LIST_T_FREE);
415
416 if (!list_empty(free_list)) {
417 node = list_first_entry(free_list, struct bpf_lru_node, list);
418 *(u32 *)((void *)node + lru->hash_offset) = hash;
419 bpf_lru_node_clear_ref(node);
420 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_INACTIVE);
421 }
422
423 raw_spin_unlock_irqrestore(&l->lock, flags);
424
425 return node;
426 }
427
bpf_common_lru_pop_free(struct bpf_lru * lru,u32 hash)428 static struct bpf_lru_node *bpf_common_lru_pop_free(struct bpf_lru *lru,
429 u32 hash)
430 {
431 struct bpf_lru_locallist *loc_l, *steal_loc_l;
432 struct bpf_common_lru *clru = &lru->common_lru;
433 struct bpf_lru_node *node;
434 int steal, first_steal;
435 unsigned long flags;
436 int cpu = raw_smp_processor_id();
437
438 loc_l = per_cpu_ptr(clru->local_list, cpu);
439
440 raw_spin_lock_irqsave(&loc_l->lock, flags);
441
442 node = __local_list_pop_free(loc_l);
443 if (!node) {
444 bpf_lru_list_pop_free_to_local(lru, loc_l);
445 node = __local_list_pop_free(loc_l);
446 }
447
448 if (node)
449 __local_list_add_pending(lru, loc_l, cpu, node, hash);
450
451 raw_spin_unlock_irqrestore(&loc_l->lock, flags);
452
453 if (node)
454 return node;
455
456 /* No free nodes found from the local free list and
457 * the global LRU list.
458 *
459 * Steal from the local free/pending list of the
460 * current CPU and remote CPU in RR. It starts
461 * with the loc_l->next_steal CPU.
462 */
463
464 first_steal = loc_l->next_steal;
465 steal = first_steal;
466 do {
467 steal_loc_l = per_cpu_ptr(clru->local_list, steal);
468
469 raw_spin_lock_irqsave(&steal_loc_l->lock, flags);
470
471 node = __local_list_pop_free(steal_loc_l);
472 if (!node)
473 node = __local_list_pop_pending(lru, steal_loc_l);
474
475 raw_spin_unlock_irqrestore(&steal_loc_l->lock, flags);
476
477 steal = cpumask_next_wrap(steal, cpu_possible_mask);
478 } while (!node && steal != first_steal);
479
480 loc_l->next_steal = steal;
481
482 if (node) {
483 raw_spin_lock_irqsave(&loc_l->lock, flags);
484 __local_list_add_pending(lru, loc_l, cpu, node, hash);
485 raw_spin_unlock_irqrestore(&loc_l->lock, flags);
486 }
487
488 return node;
489 }
490
bpf_lru_pop_free(struct bpf_lru * lru,u32 hash)491 struct bpf_lru_node *bpf_lru_pop_free(struct bpf_lru *lru, u32 hash)
492 {
493 if (lru->percpu)
494 return bpf_percpu_lru_pop_free(lru, hash);
495 else
496 return bpf_common_lru_pop_free(lru, hash);
497 }
498
bpf_common_lru_push_free(struct bpf_lru * lru,struct bpf_lru_node * node)499 static void bpf_common_lru_push_free(struct bpf_lru *lru,
500 struct bpf_lru_node *node)
501 {
502 u8 node_type = READ_ONCE(node->type);
503 unsigned long flags;
504
505 if (WARN_ON_ONCE(node_type == BPF_LRU_LIST_T_FREE) ||
506 WARN_ON_ONCE(node_type == BPF_LRU_LOCAL_LIST_T_FREE))
507 return;
508
509 if (node_type == BPF_LRU_LOCAL_LIST_T_PENDING) {
510 struct bpf_lru_locallist *loc_l;
511
512 loc_l = per_cpu_ptr(lru->common_lru.local_list, node->cpu);
513
514 raw_spin_lock_irqsave(&loc_l->lock, flags);
515
516 if (unlikely(node->type != BPF_LRU_LOCAL_LIST_T_PENDING)) {
517 raw_spin_unlock_irqrestore(&loc_l->lock, flags);
518 goto check_lru_list;
519 }
520
521 node->type = BPF_LRU_LOCAL_LIST_T_FREE;
522 bpf_lru_node_clear_ref(node);
523 list_move(&node->list, local_free_list(loc_l));
524
525 raw_spin_unlock_irqrestore(&loc_l->lock, flags);
526 return;
527 }
528
529 check_lru_list:
530 bpf_lru_list_push_free(&lru->common_lru.lru_list, node);
531 }
532
bpf_percpu_lru_push_free(struct bpf_lru * lru,struct bpf_lru_node * node)533 static void bpf_percpu_lru_push_free(struct bpf_lru *lru,
534 struct bpf_lru_node *node)
535 {
536 struct bpf_lru_list *l;
537 unsigned long flags;
538
539 l = per_cpu_ptr(lru->percpu_lru, node->cpu);
540
541 raw_spin_lock_irqsave(&l->lock, flags);
542
543 __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE);
544
545 raw_spin_unlock_irqrestore(&l->lock, flags);
546 }
547
bpf_lru_push_free(struct bpf_lru * lru,struct bpf_lru_node * node)548 void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node)
549 {
550 if (lru->percpu)
551 bpf_percpu_lru_push_free(lru, node);
552 else
553 bpf_common_lru_push_free(lru, node);
554 }
555
bpf_common_lru_populate(struct bpf_lru * lru,void * buf,u32 node_offset,u32 elem_size,u32 nr_elems)556 static void bpf_common_lru_populate(struct bpf_lru *lru, void *buf,
557 u32 node_offset, u32 elem_size,
558 u32 nr_elems)
559 {
560 struct bpf_lru_list *l = &lru->common_lru.lru_list;
561 u32 i;
562
563 for (i = 0; i < nr_elems; i++) {
564 struct bpf_lru_node *node;
565
566 node = (struct bpf_lru_node *)(buf + node_offset);
567 node->type = BPF_LRU_LIST_T_FREE;
568 bpf_lru_node_clear_ref(node);
569 list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]);
570 buf += elem_size;
571 }
572
573 lru->target_free = clamp((nr_elems / num_possible_cpus()) / 2,
574 1, LOCAL_FREE_TARGET);
575 }
576
bpf_percpu_lru_populate(struct bpf_lru * lru,void * buf,u32 node_offset,u32 elem_size,u32 nr_elems)577 static void bpf_percpu_lru_populate(struct bpf_lru *lru, void *buf,
578 u32 node_offset, u32 elem_size,
579 u32 nr_elems)
580 {
581 u32 i, pcpu_entries;
582 int cpu;
583 struct bpf_lru_list *l;
584
585 pcpu_entries = nr_elems / num_possible_cpus();
586
587 i = 0;
588
589 for_each_possible_cpu(cpu) {
590 struct bpf_lru_node *node;
591
592 l = per_cpu_ptr(lru->percpu_lru, cpu);
593 again:
594 node = (struct bpf_lru_node *)(buf + node_offset);
595 node->cpu = cpu;
596 node->type = BPF_LRU_LIST_T_FREE;
597 bpf_lru_node_clear_ref(node);
598 list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]);
599 i++;
600 buf += elem_size;
601 if (i == nr_elems)
602 break;
603 if (i % pcpu_entries)
604 goto again;
605 }
606 }
607
bpf_lru_populate(struct bpf_lru * lru,void * buf,u32 node_offset,u32 elem_size,u32 nr_elems)608 void bpf_lru_populate(struct bpf_lru *lru, void *buf, u32 node_offset,
609 u32 elem_size, u32 nr_elems)
610 {
611 if (lru->percpu)
612 bpf_percpu_lru_populate(lru, buf, node_offset, elem_size,
613 nr_elems);
614 else
615 bpf_common_lru_populate(lru, buf, node_offset, elem_size,
616 nr_elems);
617 }
618
bpf_lru_locallist_init(struct bpf_lru_locallist * loc_l,int cpu)619 static void bpf_lru_locallist_init(struct bpf_lru_locallist *loc_l, int cpu)
620 {
621 int i;
622
623 for (i = 0; i < NR_BPF_LRU_LOCAL_LIST_T; i++)
624 INIT_LIST_HEAD(&loc_l->lists[i]);
625
626 loc_l->next_steal = cpu;
627
628 raw_spin_lock_init(&loc_l->lock);
629 }
630
bpf_lru_list_init(struct bpf_lru_list * l)631 static void bpf_lru_list_init(struct bpf_lru_list *l)
632 {
633 int i;
634
635 for (i = 0; i < NR_BPF_LRU_LIST_T; i++)
636 INIT_LIST_HEAD(&l->lists[i]);
637
638 for (i = 0; i < NR_BPF_LRU_LIST_COUNT; i++)
639 l->counts[i] = 0;
640
641 l->next_inactive_rotation = &l->lists[BPF_LRU_LIST_T_INACTIVE];
642
643 raw_spin_lock_init(&l->lock);
644 }
645
bpf_lru_init(struct bpf_lru * lru,bool percpu,u32 hash_offset,del_from_htab_func del_from_htab,void * del_arg)646 int bpf_lru_init(struct bpf_lru *lru, bool percpu, u32 hash_offset,
647 del_from_htab_func del_from_htab, void *del_arg)
648 {
649 int cpu;
650
651 if (percpu) {
652 lru->percpu_lru = alloc_percpu(struct bpf_lru_list);
653 if (!lru->percpu_lru)
654 return -ENOMEM;
655
656 for_each_possible_cpu(cpu) {
657 struct bpf_lru_list *l;
658
659 l = per_cpu_ptr(lru->percpu_lru, cpu);
660 bpf_lru_list_init(l);
661 }
662 lru->nr_scans = PERCPU_NR_SCANS;
663 } else {
664 struct bpf_common_lru *clru = &lru->common_lru;
665
666 clru->local_list = alloc_percpu(struct bpf_lru_locallist);
667 if (!clru->local_list)
668 return -ENOMEM;
669
670 for_each_possible_cpu(cpu) {
671 struct bpf_lru_locallist *loc_l;
672
673 loc_l = per_cpu_ptr(clru->local_list, cpu);
674 bpf_lru_locallist_init(loc_l, cpu);
675 }
676
677 bpf_lru_list_init(&clru->lru_list);
678 lru->nr_scans = LOCAL_NR_SCANS;
679 }
680
681 lru->percpu = percpu;
682 lru->del_from_htab = del_from_htab;
683 lru->del_arg = del_arg;
684 lru->hash_offset = hash_offset;
685
686 return 0;
687 }
688
bpf_lru_destroy(struct bpf_lru * lru)689 void bpf_lru_destroy(struct bpf_lru *lru)
690 {
691 if (lru->percpu)
692 free_percpu(lru->percpu_lru);
693 else
694 free_percpu(lru->common_lru.local_list);
695 }
696