Commit a5f6b9d5 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'Enable struct_ops programs to be sleepable'

David Vernet says:

====================

This is part 4 of https://lore.kernel.org/bpf/20230123232228.646563-1-void@manifault.com/

Part 3: https://lore.kernel.org/all/20230125050359.339273-1-void@manifault.com/
Part 2: https://lore.kernel.org/all/20230124160802.1122124-1-void@manifault.com/



Changelog:
----------
v3 -> v4:
- Fix accidental typo in name of dummy_st_ops introduced in v2, moving
  it back to dummy_st_ops from dummy_st_ops_success. Should fix s390x
  testruns.

v2 -> v3:
- Don't call a KF_SLEEPABLE kfunc from the dummy_st_ops testsuite, and
  remove the newly added bpf_kfunc_call_test_sleepable() test kfunc
  (Martin).
- Include vmlinux.h from progs/dummy_st_ops_success.c (previously
  progs/dummy_st_ops.c) rather than manually defining
  struct bpf_dummy_ops_state and struct bpf_dummy_ops.
  (Martin).
- Fix a typo added to prog_tests/dummy_st_ops.c in a previous version:
  s/trace_dummy_st_ops_success__open/trace_dummy_st_ops__open.

v1 -> v2:
- Add support for specifying sleepable struct_ops programs with
  struct_ops.s in libbpf (Alexei).
- Move failure test case into new dummy_st_ops_fail.c prog file.
- Update test_dummy_sleepable() to use struct_ops.s instead of manually
  setting prog flags. Also remove open_load_skel() helper which is no
  longer needed.
- Fix verifier tests to expect new sleepable prog failure message.
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 2514a312 7dd88059
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1422,7 +1422,8 @@ struct bpf_struct_ops {
	const struct bpf_verifier_ops *verifier_ops;
	int (*init)(struct btf *btf);
	int (*check_member)(const struct btf_type *t,
			    const struct btf_member *member);
			    const struct btf_member *member,
			    const struct bpf_prog *prog);
	int (*init_member)(const struct btf_type *t,
			   const struct btf_member *member,
			   void *kdata, const void *udata);
@@ -1473,6 +1474,7 @@ struct bpf_dummy_ops {
	int (*test_1)(struct bpf_dummy_ops_state *cb);
	int (*test_2)(struct bpf_dummy_ops_state *cb, int a1, unsigned short a2,
		      char a3, unsigned long a4);
	int (*test_sleepable)(struct bpf_dummy_ops_state *cb);
};

int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,
+4 −3
Original line number Diff line number Diff line
@@ -16792,7 +16792,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
	}

	if (st_ops->check_member) {
		int err = st_ops->check_member(t, member);
		int err = st_ops->check_member(t, member, prog);

		if (err) {
			verbose(env, "attach to unsupported member %s of struct %s\n",
@@ -17114,7 +17114,8 @@ static bool can_be_sleepable(struct bpf_prog *prog)
		}
	}
	return prog->type == BPF_PROG_TYPE_LSM ||
	       prog->type == BPF_PROG_TYPE_KPROBE; /* only for uprobes */
	       prog->type == BPF_PROG_TYPE_KPROBE /* only for uprobes */ ||
	       prog->type == BPF_PROG_TYPE_STRUCT_OPS;
}

static int check_attach_btf_id(struct bpf_verifier_env *env)
@@ -17136,7 +17137,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
	}

	if (prog->aux->sleepable && !can_be_sleepable(prog)) {
		verbose(env, "Only fentry/fexit/fmod_ret, lsm, iter and uprobe programs can be sleepable\n");
		verbose(env, "Only fentry/fexit/fmod_ret, lsm, iter, uprobe, and struct_ops programs can be sleepable\n");
		return -EINVAL;
	}

+18 −0
Original line number Diff line number Diff line
@@ -154,6 +154,23 @@ static bool bpf_dummy_ops_is_valid_access(int off, int size,
	return bpf_tracing_btf_ctx_access(off, size, type, prog, info);
}

static int bpf_dummy_ops_check_member(const struct btf_type *t,
				      const struct btf_member *member,
				      const struct bpf_prog *prog)
{
	u32 moff = __btf_member_bit_offset(t, member) / 8;

	switch (moff) {
	case offsetof(struct bpf_dummy_ops, test_sleepable):
		break;
	default:
		if (prog->aux->sleepable)
			return -EINVAL;
	}

	return 0;
}

static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log,
					   const struct bpf_reg_state *reg,
					   int off, int size, enum bpf_access_type atype,
@@ -208,6 +225,7 @@ static void bpf_dummy_unreg(void *kdata)
struct bpf_struct_ops bpf_bpf_dummy_ops = {
	.verifier_ops = &bpf_dummy_verifier_ops,
	.init = bpf_dummy_init,
	.check_member = bpf_dummy_ops_check_member,
	.init_member = bpf_dummy_init_member,
	.reg = bpf_dummy_reg,
	.unreg = bpf_dummy_unreg,
+2 −1
Original line number Diff line number Diff line
@@ -248,7 +248,8 @@ static int bpf_tcp_ca_init_member(const struct btf_type *t,
}

static int bpf_tcp_ca_check_member(const struct btf_type *t,
				   const struct btf_member *member)
				   const struct btf_member *member,
				   const struct bpf_prog *prog)
{
	if (is_unsupported(__btf_member_bit_offset(t, member) / 8))
		return -ENOTSUPP;
+1 −0
Original line number Diff line number Diff line
@@ -8605,6 +8605,7 @@ static const struct bpf_sec_def section_defs[] = {
	SEC_DEF("cgroup/setsockopt",	CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT, SEC_ATTACHABLE),
	SEC_DEF("cgroup/dev",		CGROUP_DEVICE, BPF_CGROUP_DEVICE, SEC_ATTACHABLE_OPT),
	SEC_DEF("struct_ops+",		STRUCT_OPS, 0, SEC_NONE),
	SEC_DEF("struct_ops.s+",	STRUCT_OPS, 0, SEC_SLEEPABLE),
	SEC_DEF("sk_lookup",		SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
};

Loading