Skip to content

Commit be2749b

Browse files
Benjamin TissoiresAlexei Starovoitov
authored andcommitted
bpf: make timer data struct more generic
To be able to add workqueues and reuse most of the timer code, we need to make bpf_hrtimer more generic. There is no code change except that the new struct gets a new u64 flags attribute. We are still below 2 cache lines, so this shouldn't impact the current running codes. The ordering is also changed. Everything related to async callback is now on top of bpf_hrtimer. Signed-off-by: Benjamin Tissoires <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent a7de265 commit be2749b

File tree

1 file changed

+38
-33
lines changed

1 file changed

+38
-33
lines changed

kernel/bpf/helpers.c

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,11 +1079,20 @@ const struct bpf_func_proto bpf_snprintf_proto = {
10791079
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
10801080
};
10811081

1082+
struct bpf_async_cb {
1083+
struct bpf_map *map;
1084+
struct bpf_prog *prog;
1085+
void __rcu *callback_fn;
1086+
void *value;
1087+
struct rcu_head rcu;
1088+
u64 flags;
1089+
};
1090+
10821091
/* BPF map elements can contain 'struct bpf_timer'.
10831092
* Such map owns all of its BPF timers.
10841093
* 'struct bpf_timer' is allocated as part of map element allocation
10851094
* and it's zero initialized.
1086-
* That space is used to keep 'struct bpf_timer_kern'.
1095+
* That space is used to keep 'struct bpf_async_kern'.
10871096
* bpf_timer_init() allocates 'struct bpf_hrtimer', inits hrtimer, and
10881097
* remembers 'struct bpf_map *' pointer it's part of.
10891098
* bpf_timer_set_callback() increments prog refcnt and assign bpf callback_fn.
@@ -1096,16 +1105,12 @@ const struct bpf_func_proto bpf_snprintf_proto = {
10961105
* freeing the timers when inner map is replaced or deleted by user space.
10971106
*/
10981107
struct bpf_hrtimer {
1108+
struct bpf_async_cb cb;
10991109
struct hrtimer timer;
1100-
struct bpf_map *map;
1101-
struct bpf_prog *prog;
1102-
void __rcu *callback_fn;
1103-
void *value;
1104-
struct rcu_head rcu;
11051110
};
11061111

11071112
/* the actual struct hidden inside uapi struct bpf_timer */
1108-
struct bpf_timer_kern {
1113+
struct bpf_async_kern {
11091114
struct bpf_hrtimer *timer;
11101115
/* bpf_spin_lock is used here instead of spinlock_t to make
11111116
* sure that it always fits into space reserved by struct bpf_timer
@@ -1119,14 +1124,14 @@ static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running);
11191124
static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
11201125
{
11211126
struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer);
1122-
struct bpf_map *map = t->map;
1123-
void *value = t->value;
1127+
struct bpf_map *map = t->cb.map;
1128+
void *value = t->cb.value;
11241129
bpf_callback_t callback_fn;
11251130
void *key;
11261131
u32 idx;
11271132

11281133
BTF_TYPE_EMIT(struct bpf_timer);
1129-
callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held());
1134+
callback_fn = rcu_dereference_check(t->cb.callback_fn, rcu_read_lock_bh_held());
11301135
if (!callback_fn)
11311136
goto out;
11321137

@@ -1155,16 +1160,16 @@ static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
11551160
return HRTIMER_NORESTART;
11561161
}
11571162

1158-
BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map,
1163+
BPF_CALL_3(bpf_timer_init, struct bpf_async_kern *, timer, struct bpf_map *, map,
11591164
u64, flags)
11601165
{
11611166
clockid_t clockid = flags & (MAX_CLOCKS - 1);
11621167
struct bpf_hrtimer *t;
11631168
int ret = 0;
11641169

11651170
BUILD_BUG_ON(MAX_CLOCKS != 16);
1166-
BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer));
1167-
BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer));
1171+
BUILD_BUG_ON(sizeof(struct bpf_async_kern) > sizeof(struct bpf_timer));
1172+
BUILD_BUG_ON(__alignof__(struct bpf_async_kern) != __alignof__(struct bpf_timer));
11681173

11691174
if (in_nmi())
11701175
return -EOPNOTSUPP;
@@ -1187,10 +1192,10 @@ BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map
11871192
ret = -ENOMEM;
11881193
goto out;
11891194
}
1190-
t->value = (void *)timer - map->record->timer_off;
1191-
t->map = map;
1192-
t->prog = NULL;
1193-
rcu_assign_pointer(t->callback_fn, NULL);
1195+
t->cb.value = (void *)timer - map->record->timer_off;
1196+
t->cb.map = map;
1197+
t->cb.prog = NULL;
1198+
rcu_assign_pointer(t->cb.callback_fn, NULL);
11941199
hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT);
11951200
t->timer.function = bpf_timer_cb;
11961201
WRITE_ONCE(timer->timer, t);
@@ -1222,7 +1227,7 @@ static const struct bpf_func_proto bpf_timer_init_proto = {
12221227
.arg3_type = ARG_ANYTHING,
12231228
};
12241229

1225-
BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callback_fn,
1230+
BPF_CALL_3(bpf_timer_set_callback, struct bpf_async_kern *, timer, void *, callback_fn,
12261231
struct bpf_prog_aux *, aux)
12271232
{
12281233
struct bpf_prog *prev, *prog = aux->prog;
@@ -1237,7 +1242,7 @@ BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callb
12371242
ret = -EINVAL;
12381243
goto out;
12391244
}
1240-
if (!atomic64_read(&t->map->usercnt)) {
1245+
if (!atomic64_read(&t->cb.map->usercnt)) {
12411246
/* maps with timers must be either held by user space
12421247
* or pinned in bpffs. Otherwise timer might still be
12431248
* running even when bpf prog is detached and user space
@@ -1246,7 +1251,7 @@ BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callb
12461251
ret = -EPERM;
12471252
goto out;
12481253
}
1249-
prev = t->prog;
1254+
prev = t->cb.prog;
12501255
if (prev != prog) {
12511256
/* Bump prog refcnt once. Every bpf_timer_set_callback()
12521257
* can pick different callback_fn-s within the same prog.
@@ -1259,9 +1264,9 @@ BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callb
12591264
if (prev)
12601265
/* Drop prev prog refcnt when swapping with new prog */
12611266
bpf_prog_put(prev);
1262-
t->prog = prog;
1267+
t->cb.prog = prog;
12631268
}
1264-
rcu_assign_pointer(t->callback_fn, callback_fn);
1269+
rcu_assign_pointer(t->cb.callback_fn, callback_fn);
12651270
out:
12661271
__bpf_spin_unlock_irqrestore(&timer->lock);
12671272
return ret;
@@ -1275,7 +1280,7 @@ static const struct bpf_func_proto bpf_timer_set_callback_proto = {
12751280
.arg2_type = ARG_PTR_TO_FUNC,
12761281
};
12771282

1278-
BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, flags)
1283+
BPF_CALL_3(bpf_timer_start, struct bpf_async_kern *, timer, u64, nsecs, u64, flags)
12791284
{
12801285
struct bpf_hrtimer *t;
12811286
int ret = 0;
@@ -1287,7 +1292,7 @@ BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, fla
12871292
return -EINVAL;
12881293
__bpf_spin_lock_irqsave(&timer->lock);
12891294
t = timer->timer;
1290-
if (!t || !t->prog) {
1295+
if (!t || !t->cb.prog) {
12911296
ret = -EINVAL;
12921297
goto out;
12931298
}
@@ -1315,18 +1320,18 @@ static const struct bpf_func_proto bpf_timer_start_proto = {
13151320
.arg3_type = ARG_ANYTHING,
13161321
};
13171322

1318-
static void drop_prog_refcnt(struct bpf_hrtimer *t)
1323+
static void drop_prog_refcnt(struct bpf_async_cb *async)
13191324
{
1320-
struct bpf_prog *prog = t->prog;
1325+
struct bpf_prog *prog = async->prog;
13211326

13221327
if (prog) {
13231328
bpf_prog_put(prog);
1324-
t->prog = NULL;
1325-
rcu_assign_pointer(t->callback_fn, NULL);
1329+
async->prog = NULL;
1330+
rcu_assign_pointer(async->callback_fn, NULL);
13261331
}
13271332
}
13281333

1329-
BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer)
1334+
BPF_CALL_1(bpf_timer_cancel, struct bpf_async_kern *, timer)
13301335
{
13311336
struct bpf_hrtimer *t;
13321337
int ret = 0;
@@ -1348,7 +1353,7 @@ BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer)
13481353
ret = -EDEADLK;
13491354
goto out;
13501355
}
1351-
drop_prog_refcnt(t);
1356+
drop_prog_refcnt(&t->cb);
13521357
out:
13531358
__bpf_spin_unlock_irqrestore(&timer->lock);
13541359
/* Cancel the timer and wait for associated callback to finish
@@ -1371,7 +1376,7 @@ static const struct bpf_func_proto bpf_timer_cancel_proto = {
13711376
*/
13721377
void bpf_timer_cancel_and_free(void *val)
13731378
{
1374-
struct bpf_timer_kern *timer = val;
1379+
struct bpf_async_kern *timer = val;
13751380
struct bpf_hrtimer *t;
13761381

13771382
/* Performance optimization: read timer->timer without lock first. */
@@ -1383,7 +1388,7 @@ void bpf_timer_cancel_and_free(void *val)
13831388
t = timer->timer;
13841389
if (!t)
13851390
goto out;
1386-
drop_prog_refcnt(t);
1391+
drop_prog_refcnt(&t->cb);
13871392
/* The subsequent bpf_timer_start/cancel() helpers won't be able to use
13881393
* this timer, since it won't be initialized.
13891394
*/
@@ -1410,7 +1415,7 @@ void bpf_timer_cancel_and_free(void *val)
14101415
*/
14111416
if (this_cpu_read(hrtimer_running) != t)
14121417
hrtimer_cancel(&t->timer);
1413-
kfree_rcu(t, rcu);
1418+
kfree_rcu(t, cb.rcu);
14141419
}
14151420

14161421
BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)

0 commit comments

Comments
 (0)