Skip to content

Commit eb48f6c

Browse files
Benjamin TissoiresAlexei Starovoitov
authored andcommitted
bpf: wq: add bpf_wq_init
We need to teach the verifier about the second argument which is declared as void * but which is of type KF_ARG_PTR_TO_MAP. We could have dropped this extra case if we declared the second argument as struct bpf_map *, but that means users will have to do extra casting to have their program compile. We also need to duplicate the timer code for the checking if the map argument is matching the provided workqueue. Signed-off-by: Benjamin Tissoires <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b4abee7 commit eb48f6c

File tree

1 file changed

+102
-2
lines changed

1 file changed

+102
-2
lines changed

kernel/bpf/helpers.c

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,11 +1109,18 @@ struct bpf_hrtimer {
11091109
struct hrtimer timer;
11101110
};
11111111

1112-
/* the actual struct hidden inside uapi struct bpf_timer */
1112+
struct bpf_work {
1113+
struct bpf_async_cb cb;
1114+
struct work_struct work;
1115+
struct work_struct delete_work;
1116+
};
1117+
1118+
/* the actual struct hidden inside uapi struct bpf_timer and bpf_wq */
11131119
struct bpf_async_kern {
11141120
union {
11151121
struct bpf_async_cb *cb;
11161122
struct bpf_hrtimer *timer;
1123+
struct bpf_work *work;
11171124
};
11181125
/* bpf_spin_lock is used here instead of spinlock_t to make
11191126
* sure that it always fits into space reserved by struct bpf_timer
@@ -1124,6 +1131,7 @@ struct bpf_async_kern {
11241131

11251132
enum bpf_async_type {
11261133
BPF_ASYNC_TYPE_TIMER = 0,
1134+
BPF_ASYNC_TYPE_WQ,
11271135
};
11281136

11291137
static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running);
@@ -1167,11 +1175,64 @@ static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
11671175
return HRTIMER_NORESTART;
11681176
}
11691177

1178+
static void bpf_wq_work(struct work_struct *work)
1179+
{
1180+
struct bpf_work *w = container_of(work, struct bpf_work, work);
1181+
struct bpf_tramp_run_ctx __maybe_unused run_ctx;
1182+
struct bpf_async_cb *cb = &w->cb;
1183+
struct bpf_prog *prog = cb->prog;
1184+
struct bpf_map *map = cb->map;
1185+
bpf_callback_t callback_fn;
1186+
void *value = cb->value;
1187+
void *key;
1188+
u32 idx;
1189+
1190+
BTF_TYPE_EMIT(struct bpf_wq);
1191+
1192+
callback_fn = READ_ONCE(cb->callback_fn);
1193+
if (!callback_fn || !prog)
1194+
return;
1195+
1196+
if (map->map_type == BPF_MAP_TYPE_ARRAY) {
1197+
struct bpf_array *array = container_of(map, struct bpf_array, map);
1198+
1199+
/* compute the key */
1200+
idx = ((char *)value - array->value) / array->elem_size;
1201+
key = &idx;
1202+
} else { /* hash or lru */
1203+
key = value - round_up(map->key_size, 8);
1204+
}
1205+
1206+
run_ctx.bpf_cookie = 0;
1207+
1208+
if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
1209+
/* recursion detected */
1210+
__bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx);
1211+
return;
1212+
}
1213+
1214+
callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);
1215+
/* The verifier checked that return value is zero. */
1216+
1217+
__bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */,
1218+
&run_ctx);
1219+
}
1220+
1221+
static void bpf_wq_delete_work(struct work_struct *work)
1222+
{
1223+
struct bpf_work *w = container_of(work, struct bpf_work, delete_work);
1224+
1225+
cancel_work_sync(&w->work);
1226+
1227+
kfree_rcu(w, cb.rcu);
1228+
}
1229+
11701230
static int __bpf_async_init(struct bpf_async_kern *async, struct bpf_map *map, u64 flags,
11711231
enum bpf_async_type type)
11721232
{
11731233
struct bpf_async_cb *cb;
11741234
struct bpf_hrtimer *t;
1235+
struct bpf_work *w;
11751236
clockid_t clockid;
11761237
size_t size;
11771238
int ret = 0;
@@ -1183,6 +1244,9 @@ static int __bpf_async_init(struct bpf_async_kern *async, struct bpf_map *map, u
11831244
case BPF_ASYNC_TYPE_TIMER:
11841245
size = sizeof(struct bpf_hrtimer);
11851246
break;
1247+
case BPF_ASYNC_TYPE_WQ:
1248+
size = sizeof(struct bpf_work);
1249+
break;
11861250
default:
11871251
return -EINVAL;
11881252
}
@@ -1201,13 +1265,22 @@ static int __bpf_async_init(struct bpf_async_kern *async, struct bpf_map *map, u
12011265
goto out;
12021266
}
12031267

1204-
if (type == BPF_ASYNC_TYPE_TIMER) {
1268+
switch (type) {
1269+
case BPF_ASYNC_TYPE_TIMER:
12051270
clockid = flags & (MAX_CLOCKS - 1);
12061271
t = (struct bpf_hrtimer *)cb;
12071272

12081273
hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT);
12091274
t->timer.function = bpf_timer_cb;
12101275
cb->value = (void *)async - map->record->timer_off;
1276+
break;
1277+
case BPF_ASYNC_TYPE_WQ:
1278+
w = (struct bpf_work *)cb;
1279+
1280+
INIT_WORK(&w->work, bpf_wq_work);
1281+
INIT_WORK(&w->delete_work, bpf_wq_delete_work);
1282+
cb->value = (void *)async - map->record->wq_off;
1283+
break;
12111284
}
12121285
cb->map = map;
12131286
cb->prog = NULL;
@@ -1473,7 +1546,19 @@ void bpf_timer_cancel_and_free(void *val)
14731546
*/
14741547
void bpf_wq_cancel_and_free(void *val)
14751548
{
1549+
struct bpf_work *work;
1550+
14761551
BTF_TYPE_EMIT(struct bpf_wq);
1552+
1553+
work = (struct bpf_work *)__bpf_async_cancel_and_free(val);
1554+
if (!work)
1555+
return;
1556+
/* Trigger cancel of the sleepable work, but *do not* wait for
1557+
* it to finish if it was running as we might not be in a
1558+
* sleepable context.
1559+
* kfree will be called once the work has finished.
1560+
*/
1561+
schedule_work(&work->delete_work);
14771562
}
14781563

14791564
BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)
@@ -2612,6 +2697,20 @@ __bpf_kfunc void bpf_throw(u64 cookie)
26122697
WARN(1, "A call to BPF exception callback should never return\n");
26132698
}
26142699

2700+
__bpf_kfunc int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags)
2701+
{
2702+
struct bpf_async_kern *async = (struct bpf_async_kern *)wq;
2703+
struct bpf_map *map = p__map;
2704+
2705+
BUILD_BUG_ON(sizeof(struct bpf_async_kern) > sizeof(struct bpf_wq));
2706+
BUILD_BUG_ON(__alignof__(struct bpf_async_kern) != __alignof__(struct bpf_wq));
2707+
2708+
if (flags)
2709+
return -EINVAL;
2710+
2711+
return __bpf_async_init(async, map, flags, BPF_ASYNC_TYPE_WQ);
2712+
}
2713+
26152714
__bpf_kfunc_end_defs();
26162715

26172716
BTF_KFUNCS_START(generic_btf_ids)
@@ -2689,6 +2788,7 @@ BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly)
26892788
BTF_ID_FLAGS(func, bpf_dynptr_size)
26902789
BTF_ID_FLAGS(func, bpf_dynptr_clone)
26912790
BTF_ID_FLAGS(func, bpf_modify_return_test_tp)
2791+
BTF_ID_FLAGS(func, bpf_wq_init)
26922792
BTF_KFUNCS_END(common_btf_ids)
26932793

26942794
static const struct btf_kfunc_id_set common_kfunc_set = {

0 commit comments

Comments
 (0)