Skip to content

Commit 50b77eb

Browse files
author
Alexei Starovoitov
committed
Merge branch 'extend-struct_ops-support-for-operators'
Amery Hung says: ==================== This patchset supports struct_ops operators that acquire kptrs through arguments and operators that return a kptr. A coming new struct_ops use case, bpf qdisc [0], has two operators that are not yet supported by current struct_ops infrastructure. Qdisc_ops::enqueue requires getting referenced skb kptr from the argument; Qdisc_ops::dequeue needs to return a referenced skb kptr. This patchset will allow bpf qdisc and other potential struct_ops implementers to do so. For struct_ops implementers: - To get a kptr from an argument, a struct_ops implementer needs to annotate the argument name in the stub function with "__ref" suffix. - The kptr return will automatically work as we now allow operators that return a struct pointer. - The verifier allows returning a null pointer. More control can be added later if there is a future struct_ops implementer only expecting valid pointers. For struct_ops users: - The referenced kptr acquired through the argument needs to be released or xchged into maps just like ones acquired via kfuncs. - To return a referenced kptr in struct_ops, 1) The type of the pointer must matches the return type 2) The pointer must comes from the kernel (not locally allocated), and 3) The pointer must be in its unmodified form [0] https://lore.kernel.org/bpf/[email protected]/ --- v2 - Replace kcalloc+memcpy with kmemdup_array in bpf_prog_ctx_arg_info_init() - Remove unnecessary checks when kfree-ing ctx_arg_info - Remove conditional assignment of ref_obj_id in btf_ctx_access() v1 - Link: https://lore.kernel.org/bpf/[email protected]/ - Fix missing kfree for ctx_arg_info ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 4eb93fe + af17bad commit 50b77eb

18 files changed

+410
-33
lines changed

include/linux/bpf.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ struct bpf_insn_access_aux {
968968
struct {
969969
struct btf *btf;
970970
u32 btf_id;
971+
u32 ref_obj_id;
971972
};
972973
};
973974
struct bpf_verifier_log *log; /* for verbose logs */
@@ -1481,6 +1482,8 @@ struct bpf_ctx_arg_aux {
14811482
enum bpf_reg_type reg_type;
14821483
struct btf *btf;
14831484
u32 btf_id;
1485+
u32 ref_obj_id;
1486+
bool refcounted;
14841487
};
14851488

14861489
struct btf_mod_pair {
@@ -1507,7 +1510,7 @@ struct bpf_prog_aux {
15071510
u32 max_rdonly_access;
15081511
u32 max_rdwr_access;
15091512
struct btf *attach_btf;
1510-
const struct bpf_ctx_arg_aux *ctx_arg_info;
1513+
struct bpf_ctx_arg_aux *ctx_arg_info;
15111514
void __percpu *priv_stack_ptr;
15121515
struct mutex dst_mutex; /* protects dst_* pointers below, *after* prog becomes visible */
15131516
struct bpf_prog *dst_prog;
@@ -1945,6 +1948,9 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
19451948

19461949
#endif
19471950

1951+
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
1952+
const struct bpf_ctx_arg_aux *info, u32 cnt);
1953+
19481954
#if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_BPF_LSM)
19491955
int bpf_trampoline_link_cgroup_shim(struct bpf_prog *prog,
19501956
int cgroup_atype);
@@ -2546,7 +2552,7 @@ struct bpf_iter__bpf_map_elem {
25462552

25472553
int bpf_iter_reg_target(const struct bpf_iter_reg *reg_info);
25482554
void bpf_iter_unreg_target(const struct bpf_iter_reg *reg_info);
2549-
bool bpf_iter_prog_supported(struct bpf_prog *prog);
2555+
int bpf_iter_prog_supported(struct bpf_prog *prog);
25502556
const struct bpf_func_proto *
25512557
bpf_iter_get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog);
25522558
int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr, struct bpf_prog *prog);

kernel/bpf/bpf_iter.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static void cache_btf_id(struct bpf_iter_target_info *tinfo,
335335
tinfo->btf_id = prog->aux->attach_btf_id;
336336
}
337337

338-
bool bpf_iter_prog_supported(struct bpf_prog *prog)
338+
int bpf_iter_prog_supported(struct bpf_prog *prog)
339339
{
340340
const char *attach_fname = prog->aux->attach_func_name;
341341
struct bpf_iter_target_info *tinfo = NULL, *iter;
@@ -344,7 +344,7 @@ bool bpf_iter_prog_supported(struct bpf_prog *prog)
344344
int prefix_len = strlen(prefix);
345345

346346
if (strncmp(attach_fname, prefix, prefix_len))
347-
return false;
347+
return -EINVAL;
348348

349349
mutex_lock(&targets_mutex);
350350
list_for_each_entry(iter, &targets, list) {
@@ -360,12 +360,11 @@ bool bpf_iter_prog_supported(struct bpf_prog *prog)
360360
}
361361
mutex_unlock(&targets_mutex);
362362

363-
if (tinfo) {
364-
prog->aux->ctx_arg_info_size = tinfo->reg_info->ctx_arg_info_size;
365-
prog->aux->ctx_arg_info = tinfo->reg_info->ctx_arg_info;
366-
}
363+
if (!tinfo)
364+
return -EINVAL;
367365

368-
return tinfo != NULL;
366+
return bpf_prog_ctx_arg_info_init(prog, tinfo->reg_info->ctx_arg_info,
367+
tinfo->reg_info->ctx_arg_info_size);
369368
}
370369

371370
const struct bpf_func_proto *

kernel/bpf/bpf_struct_ops.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ void bpf_struct_ops_image_free(void *image)
146146
}
147147

148148
#define MAYBE_NULL_SUFFIX "__nullable"
149+
#define REFCOUNTED_SUFFIX "__ref"
149150

150151
/* Prepare argument info for every nullable argument of a member of a
151152
* struct_ops type.
@@ -174,11 +175,13 @@ static int prepare_arg_info(struct btf *btf,
174175
struct bpf_struct_ops_arg_info *arg_info)
175176
{
176177
const struct btf_type *stub_func_proto, *pointed_type;
178+
bool is_nullable = false, is_refcounted = false;
177179
const struct btf_param *stub_args, *args;
178180
struct bpf_ctx_arg_aux *info, *info_buf;
179181
u32 nargs, arg_no, info_cnt = 0;
180182
char ksym[KSYM_SYMBOL_LEN];
181183
const char *stub_fname;
184+
const char *suffix;
182185
s32 stub_func_id;
183186
u32 arg_btf_id;
184187
int offset;
@@ -223,10 +226,18 @@ static int prepare_arg_info(struct btf *btf,
223226
info = info_buf;
224227
for (arg_no = 0; arg_no < nargs; arg_no++) {
225228
/* Skip arguments that is not suffixed with
226-
* "__nullable".
229+
* "__nullable or __ref".
227230
*/
228-
if (!btf_param_match_suffix(btf, &stub_args[arg_no],
229-
MAYBE_NULL_SUFFIX))
231+
is_nullable = btf_param_match_suffix(btf, &stub_args[arg_no],
232+
MAYBE_NULL_SUFFIX);
233+
is_refcounted = btf_param_match_suffix(btf, &stub_args[arg_no],
234+
REFCOUNTED_SUFFIX);
235+
236+
if (is_nullable)
237+
suffix = MAYBE_NULL_SUFFIX;
238+
else if (is_refcounted)
239+
suffix = REFCOUNTED_SUFFIX;
240+
else
230241
continue;
231242

232243
/* Should be a pointer to struct */
@@ -236,7 +247,7 @@ static int prepare_arg_info(struct btf *btf,
236247
if (!pointed_type ||
237248
!btf_type_is_struct(pointed_type)) {
238249
pr_warn("stub function %s has %s tagging to an unsupported type\n",
239-
stub_fname, MAYBE_NULL_SUFFIX);
250+
stub_fname, suffix);
240251
goto err_out;
241252
}
242253

@@ -254,11 +265,15 @@ static int prepare_arg_info(struct btf *btf,
254265
}
255266

256267
/* Fill the information of the new argument */
257-
info->reg_type =
258-
PTR_TRUSTED | PTR_TO_BTF_ID | PTR_MAYBE_NULL;
259268
info->btf_id = arg_btf_id;
260269
info->btf = btf;
261270
info->offset = offset;
271+
if (is_nullable) {
272+
info->reg_type = PTR_TRUSTED | PTR_TO_BTF_ID | PTR_MAYBE_NULL;
273+
} else if (is_refcounted) {
274+
info->reg_type = PTR_TRUSTED | PTR_TO_BTF_ID;
275+
info->refcounted = true;
276+
}
262277

263278
info++;
264279
info_cnt++;
@@ -375,7 +390,7 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
375390
st_ops_desc->value_type = btf_type_by_id(btf, value_id);
376391

377392
for_each_member(i, t, member) {
378-
const struct btf_type *func_proto;
393+
const struct btf_type *func_proto, *ret_type;
379394
void **stub_func_addr;
380395
u32 moff;
381396

@@ -412,6 +427,16 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
412427
if (!func_proto || bpf_struct_ops_supported(st_ops, moff))
413428
continue;
414429

430+
if (func_proto->type) {
431+
ret_type = btf_type_resolve_ptr(btf, func_proto->type, NULL);
432+
if (ret_type && !__btf_type_is_struct(ret_type)) {
433+
pr_warn("func ptr %s in struct %s returns non-struct pointer, which is not supported\n",
434+
mname, st_ops->name);
435+
err = -EOPNOTSUPP;
436+
goto errout;
437+
}
438+
}
439+
415440
if (btf_distill_func_proto(log, btf,
416441
func_proto, mname,
417442
&st_ops->func_models[i])) {

kernel/bpf/btf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6774,6 +6774,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
67746774
info->reg_type = ctx_arg_info->reg_type;
67756775
info->btf = ctx_arg_info->btf ? : btf_vmlinux;
67766776
info->btf_id = ctx_arg_info->btf_id;
6777+
info->ref_obj_id = ctx_arg_info->ref_obj_id;
67776778
return true;
67786779
}
67796780
}

kernel/bpf/syscall.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
23132313
kvfree(prog->aux->jited_linfo);
23142314
kvfree(prog->aux->linfo);
23152315
kfree(prog->aux->kfunc_tab);
2316+
kfree(prog->aux->ctx_arg_info);
23162317
if (prog->aux->attach_btf)
23172318
btf_put(prog->aux->attach_btf);
23182319

0 commit comments

Comments
 (0)