Skip to content

Commit aa3496a

Browse files
kkdwvdAlexei Starovoitov
authored andcommitted
bpf: Refactor kptr_off_tab into btf_record
To prepare the BPF verifier to handle special fields in both map values and program allocated types coming from program BTF, we need to refactor the kptr_off_tab handling code into something more generic and reusable across both cases to avoid code duplication. Later patches also require passing this data to helpers at runtime, so that they can work on user defined types, initialize them, destruct them, etc. The main observation is that both map values and such allocated types point to a type in program BTF, hence they can be handled similarly. We can prepare a field metadata table for both cases and store them in struct bpf_map or struct btf depending on the use case. Hence, refactor the code into generic btf_record and btf_field member structs. The btf_record represents the fields of a specific btf_type in user BTF. The cnt indicates the number of special fields we successfully recognized, and field_mask is a bitmask of fields that were found, to enable quick determination of availability of a certain field. Subsequently, refactor the rest of the code to work with these generic types, remove assumptions about kptr and kptr_off_tab, rename variables to more meaningful names, etc. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20221103191013.1236066-7-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent a28ace7 commit aa3496a

8 files changed

Lines changed: 332 additions & 263 deletions

File tree

include/linux/bpf.h

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -165,35 +165,41 @@ struct bpf_map_ops {
165165
};
166166

167167
enum {
168-
/* Support at most 8 pointers in a BPF map value */
169-
BPF_MAP_VALUE_OFF_MAX = 8,
170-
BPF_MAP_OFF_ARR_MAX = BPF_MAP_VALUE_OFF_MAX +
168+
/* Support at most 8 pointers in a BTF type */
169+
BTF_FIELDS_MAX = 8,
170+
BPF_MAP_OFF_ARR_MAX = BTF_FIELDS_MAX +
171171
1 + /* for bpf_spin_lock */
172172
1, /* for bpf_timer */
173173
};
174174

175-
enum bpf_kptr_type {
176-
BPF_KPTR_UNREF,
177-
BPF_KPTR_REF,
175+
enum btf_field_type {
176+
BPF_KPTR_UNREF = (1 << 2),
177+
BPF_KPTR_REF = (1 << 3),
178+
BPF_KPTR = BPF_KPTR_UNREF | BPF_KPTR_REF,
178179
};
179180

180-
struct bpf_map_value_off_desc {
181+
struct btf_field_kptr {
182+
struct btf *btf;
183+
struct module *module;
184+
btf_dtor_kfunc_t dtor;
185+
u32 btf_id;
186+
};
187+
188+
struct btf_field {
181189
u32 offset;
182-
enum bpf_kptr_type type;
183-
struct {
184-
struct btf *btf;
185-
struct module *module;
186-
btf_dtor_kfunc_t dtor;
187-
u32 btf_id;
188-
} kptr;
190+
enum btf_field_type type;
191+
union {
192+
struct btf_field_kptr kptr;
193+
};
189194
};
190195

191-
struct bpf_map_value_off {
192-
u32 nr_off;
193-
struct bpf_map_value_off_desc off[];
196+
struct btf_record {
197+
u32 cnt;
198+
u32 field_mask;
199+
struct btf_field fields[];
194200
};
195201

196-
struct bpf_map_off_arr {
202+
struct btf_field_offs {
197203
u32 cnt;
198204
u32 field_off[BPF_MAP_OFF_ARR_MAX];
199205
u8 field_sz[BPF_MAP_OFF_ARR_MAX];
@@ -215,7 +221,7 @@ struct bpf_map {
215221
u64 map_extra; /* any per-map-type extra fields */
216222
u32 map_flags;
217223
int spin_lock_off; /* >=0 valid offset, <0 error */
218-
struct bpf_map_value_off *kptr_off_tab;
224+
struct btf_record *record;
219225
int timer_off; /* >=0 valid offset, <0 error */
220226
u32 id;
221227
int numa_node;
@@ -227,7 +233,7 @@ struct bpf_map {
227233
struct obj_cgroup *objcg;
228234
#endif
229235
char name[BPF_OBJ_NAME_LEN];
230-
struct bpf_map_off_arr *off_arr;
236+
struct btf_field_offs *field_offs;
231237
/* The 3rd and 4th cacheline with misc members to avoid false sharing
232238
* particularly with refcounting.
233239
*/
@@ -251,6 +257,37 @@ struct bpf_map {
251257
bool frozen; /* write-once; write-protected by freeze_mutex */
252258
};
253259

260+
static inline u32 btf_field_type_size(enum btf_field_type type)
261+
{
262+
switch (type) {
263+
case BPF_KPTR_UNREF:
264+
case BPF_KPTR_REF:
265+
return sizeof(u64);
266+
default:
267+
WARN_ON_ONCE(1);
268+
return 0;
269+
}
270+
}
271+
272+
static inline u32 btf_field_type_align(enum btf_field_type type)
273+
{
274+
switch (type) {
275+
case BPF_KPTR_UNREF:
276+
case BPF_KPTR_REF:
277+
return __alignof__(u64);
278+
default:
279+
WARN_ON_ONCE(1);
280+
return 0;
281+
}
282+
}
283+
284+
static inline bool btf_record_has_field(const struct btf_record *rec, enum btf_field_type type)
285+
{
286+
if (IS_ERR_OR_NULL(rec))
287+
return false;
288+
return rec->field_mask & type;
289+
}
290+
254291
static inline bool map_value_has_spin_lock(const struct bpf_map *map)
255292
{
256293
return map->spin_lock_off >= 0;
@@ -261,23 +298,19 @@ static inline bool map_value_has_timer(const struct bpf_map *map)
261298
return map->timer_off >= 0;
262299
}
263300

264-
static inline bool map_value_has_kptrs(const struct bpf_map *map)
265-
{
266-
return !IS_ERR_OR_NULL(map->kptr_off_tab);
267-
}
268-
269301
static inline void check_and_init_map_value(struct bpf_map *map, void *dst)
270302
{
271303
if (unlikely(map_value_has_spin_lock(map)))
272304
memset(dst + map->spin_lock_off, 0, sizeof(struct bpf_spin_lock));
273305
if (unlikely(map_value_has_timer(map)))
274306
memset(dst + map->timer_off, 0, sizeof(struct bpf_timer));
275-
if (unlikely(map_value_has_kptrs(map))) {
276-
struct bpf_map_value_off *tab = map->kptr_off_tab;
307+
if (!IS_ERR_OR_NULL(map->record)) {
308+
struct btf_field *fields = map->record->fields;
309+
u32 cnt = map->record->cnt;
277310
int i;
278311

279-
for (i = 0; i < tab->nr_off; i++)
280-
*(u64 *)(dst + tab->off[i].offset) = 0;
312+
for (i = 0; i < cnt; i++)
313+
memset(dst + fields[i].offset, 0, btf_field_type_size(fields[i].type));
281314
}
282315
}
283316

@@ -303,19 +336,20 @@ static inline void __copy_map_value(struct bpf_map *map, void *dst, void *src, b
303336
u32 curr_off = 0;
304337
int i;
305338

306-
if (likely(!map->off_arr)) {
339+
if (likely(!map->field_offs)) {
307340
if (long_memcpy)
308341
bpf_long_memcpy(dst, src, round_up(map->value_size, 8));
309342
else
310343
memcpy(dst, src, map->value_size);
311344
return;
312345
}
313346

314-
for (i = 0; i < map->off_arr->cnt; i++) {
315-
u32 next_off = map->off_arr->field_off[i];
347+
for (i = 0; i < map->field_offs->cnt; i++) {
348+
u32 next_off = map->field_offs->field_off[i];
349+
u32 sz = next_off - curr_off;
316350

317-
memcpy(dst + curr_off, src + curr_off, next_off - curr_off);
318-
curr_off += map->off_arr->field_sz[i];
351+
memcpy(dst + curr_off, src + curr_off, sz);
352+
curr_off += map->field_offs->field_sz[i];
319353
}
320354
memcpy(dst + curr_off, src + curr_off, map->value_size - curr_off);
321355
}
@@ -335,16 +369,17 @@ static inline void zero_map_value(struct bpf_map *map, void *dst)
335369
u32 curr_off = 0;
336370
int i;
337371

338-
if (likely(!map->off_arr)) {
372+
if (likely(!map->field_offs)) {
339373
memset(dst, 0, map->value_size);
340374
return;
341375
}
342376

343-
for (i = 0; i < map->off_arr->cnt; i++) {
344-
u32 next_off = map->off_arr->field_off[i];
377+
for (i = 0; i < map->field_offs->cnt; i++) {
378+
u32 next_off = map->field_offs->field_off[i];
379+
u32 sz = next_off - curr_off;
345380

346-
memset(dst + curr_off, 0, next_off - curr_off);
347-
curr_off += map->off_arr->field_sz[i];
381+
memset(dst + curr_off, 0, sz);
382+
curr_off += map->field_offs->field_sz[i];
348383
}
349384
memset(dst + curr_off, 0, map->value_size - curr_off);
350385
}
@@ -1699,11 +1734,13 @@ void bpf_prog_put(struct bpf_prog *prog);
16991734
void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock);
17001735
void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock);
17011736

1702-
struct bpf_map_value_off_desc *bpf_map_kptr_off_contains(struct bpf_map *map, u32 offset);
1703-
void bpf_map_free_kptr_off_tab(struct bpf_map *map);
1704-
struct bpf_map_value_off *bpf_map_copy_kptr_off_tab(const struct bpf_map *map);
1705-
bool bpf_map_equal_kptr_off_tab(const struct bpf_map *map_a, const struct bpf_map *map_b);
1706-
void bpf_map_free_kptrs(struct bpf_map *map, void *map_value);
1737+
struct btf_field *btf_record_find(const struct btf_record *rec,
1738+
u32 offset, enum btf_field_type type);
1739+
void btf_record_free(struct btf_record *rec);
1740+
void bpf_map_free_record(struct bpf_map *map);
1741+
struct btf_record *btf_record_dup(const struct btf_record *rec);
1742+
bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b);
1743+
void bpf_obj_free_fields(const struct btf_record *rec, void *obj);
17071744

17081745
struct bpf_map *bpf_map_get(u32 ufd);
17091746
struct bpf_map *bpf_map_get_with_uref(u32 ufd);

include/linux/btf.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,7 @@ bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
163163
u32 expected_offset, u32 expected_size);
164164
int btf_find_spin_lock(const struct btf *btf, const struct btf_type *t);
165165
int btf_find_timer(const struct btf *btf, const struct btf_type *t);
166-
struct bpf_map_value_off *btf_parse_kptrs(const struct btf *btf,
167-
const struct btf_type *t);
166+
struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type *t);
168167
bool btf_type_is_void(const struct btf_type *t);
169168
s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind);
170169
const struct btf_type *btf_type_skip_modifiers(const struct btf *btf,

kernel/bpf/arraymap.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,7 @@ static void check_and_free_fields(struct bpf_array *arr, void *val)
310310
{
311311
if (map_value_has_timer(&arr->map))
312312
bpf_timer_cancel_and_free(val + arr->map.timer_off);
313-
if (map_value_has_kptrs(&arr->map))
314-
bpf_map_free_kptrs(&arr->map, val);
313+
bpf_obj_free_fields(arr->map.record, val);
315314
}
316315

317316
/* Called from syscall or from eBPF program */
@@ -409,7 +408,7 @@ static void array_map_free_timers(struct bpf_map *map)
409408
struct bpf_array *array = container_of(map, struct bpf_array, map);
410409
int i;
411410

412-
/* We don't reset or free kptr on uref dropping to zero. */
411+
/* We don't reset or free fields other than timer on uref dropping to zero. */
413412
if (!map_value_has_timer(map))
414413
return;
415414

@@ -423,22 +422,22 @@ static void array_map_free(struct bpf_map *map)
423422
struct bpf_array *array = container_of(map, struct bpf_array, map);
424423
int i;
425424

426-
if (map_value_has_kptrs(map)) {
425+
if (!IS_ERR_OR_NULL(map->record)) {
427426
if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
428427
for (i = 0; i < array->map.max_entries; i++) {
429428
void __percpu *pptr = array->pptrs[i & array->index_mask];
430429
int cpu;
431430

432431
for_each_possible_cpu(cpu) {
433-
bpf_map_free_kptrs(map, per_cpu_ptr(pptr, cpu));
432+
bpf_obj_free_fields(map->record, per_cpu_ptr(pptr, cpu));
434433
cond_resched();
435434
}
436435
}
437436
} else {
438437
for (i = 0; i < array->map.max_entries; i++)
439-
bpf_map_free_kptrs(map, array_map_elem_ptr(array, i));
438+
bpf_obj_free_fields(map->record, array_map_elem_ptr(array, i));
440439
}
441-
bpf_map_free_kptr_off_tab(map);
440+
bpf_map_free_record(map);
442441
}
443442

444443
if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)

0 commit comments

Comments
 (0)