Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/bpf/bpf_lru_list.c
29267 views
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 */
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
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 */
34
static bool bpf_lru_node_is_ref(const struct bpf_lru_node *node)
35
{
36
return READ_ONCE(node->ref);
37
}
38
39
static void bpf_lru_node_clear_ref(struct bpf_lru_node *node)
40
{
41
WRITE_ONCE(node->ref, 0);
42
}
43
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
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
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 */
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
*/
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
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
*/
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
*/
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
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
*/
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
*/
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 */
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
697