Skip to content

Commit 5359bf0

Browse files
Donglin PengKernel Patches Daemon
authored andcommitted
libbpf: Add BTF permutation support for type reordering
Introduce btf__permute() API to allow in-place rearrangement of BTF types. This function reorganizes BTF type order according to a provided array of type IDs, updating all type references to maintain consistency. The permutation process involves: 1. Shuffling types into new order based on the provided IDs array 2. Remapping all type ID references to point to new locations 3. Handling BTF extension data if provided via options This is particularly useful for optimizing type locality after BTF deduplication or for meeting specific layout requirements in specialized use cases. Cc: Eduard Zingerman <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Alan Maguire <[email protected]> Cc: Song Liu <[email protected]> Cc: Xiaoqin Zhang <[email protected]> Signed-off-by: Donglin Peng <[email protected]> Signed-off-by: Donglin Peng <[email protected]> Acked-by: Eduard Zingerman <[email protected]>
1 parent 608c60b commit 5359bf0

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed

tools/lib/bpf/btf.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5830,3 +5830,179 @@ int btf__relocate(struct btf *btf, const struct btf *base_btf)
58305830
btf->owns_base = false;
58315831
return libbpf_err(err);
58325832
}
5833+
5834+
struct btf_permute {
5835+
/* .BTF section to be permuted in-place */
5836+
struct btf *btf;
5837+
/* optional .BTF.ext info along the main BTF info */
5838+
struct btf_ext *btf_ext;
5839+
/* Array containing original type IDs (exclude VOID type ID 0)
5840+
* in user-defined order
5841+
*/
5842+
__u32 *ids;
5843+
/* Array used to map from original type ID to a new permuted type
5844+
* ID
5845+
*/
5846+
__u32 *ids_map;
5847+
/* Number of elements in ids array */
5848+
__u32 ids_sz;
5849+
};
5850+
5851+
static int btf_permute_shuffle_types(struct btf_permute *p);
5852+
static int btf_permute_remap_types(struct btf_permute *p);
5853+
static int btf_permute_remap_type_id(__u32 *type_id, void *ctx);
5854+
5855+
int btf__permute(struct btf *btf, __u32 *ids, __u32 ids_sz, const struct btf_permute_opts *opts)
5856+
{
5857+
struct btf_permute p;
5858+
int err = 0;
5859+
__u32 *ids_map = NULL;
5860+
5861+
if (!OPTS_VALID(opts, btf_permute_opts) || (ids_sz > btf->nr_types))
5862+
return libbpf_err(-EINVAL);
5863+
5864+
ids_map = calloc(ids_sz, sizeof(*ids_map));
5865+
if (!ids_map) {
5866+
err = -ENOMEM;
5867+
goto done;
5868+
}
5869+
5870+
p.btf = btf;
5871+
p.btf_ext = OPTS_GET(opts, btf_ext, NULL);
5872+
p.ids = ids;
5873+
p.ids_map = ids_map;
5874+
p.ids_sz = ids_sz;
5875+
5876+
if (btf_ensure_modifiable(btf)) {
5877+
err = -ENOMEM;
5878+
goto done;
5879+
}
5880+
err = btf_permute_shuffle_types(&p);
5881+
if (err < 0) {
5882+
goto done;
5883+
}
5884+
err = btf_permute_remap_types(&p);
5885+
if (err < 0) {
5886+
goto done;
5887+
}
5888+
5889+
done:
5890+
free(ids_map);
5891+
return libbpf_err(err);
5892+
}
5893+
5894+
/* Shuffle BTF types.
5895+
*
5896+
* Rearranges types according to the order specified in p->ids array.
5897+
* The p->ids_map array stores the mapping from original type IDs to
5898+
* new shuffled IDs, which is used in the next phase to update type
5899+
* references.
5900+
*/
5901+
static int btf_permute_shuffle_types(struct btf_permute *p)
5902+
{
5903+
struct btf *btf = p->btf;
5904+
const struct btf_type *t;
5905+
__u32 *new_offs = NULL, *ids_map;
5906+
void *nt, *new_types = NULL;
5907+
int i, id, len, err;
5908+
5909+
new_offs = calloc(p->ids_sz, sizeof(*new_offs));
5910+
new_types = calloc(btf->hdr->type_len, 1);
5911+
if (!new_offs || !new_types) {
5912+
err = -ENOMEM;
5913+
goto out_err;
5914+
}
5915+
5916+
nt = new_types;
5917+
for (i = 0; i < p->ids_sz; i++) {
5918+
id = p->ids[i];
5919+
/* type IDs from base_btf and the VOID type are not allowed */
5920+
if (id < btf->start_id) {
5921+
err = -EINVAL;
5922+
goto out_err;
5923+
}
5924+
/* must be a valid type ID */
5925+
t = btf__type_by_id(btf, id);
5926+
if (!t) {
5927+
err = -EINVAL;
5928+
goto out_err;
5929+
}
5930+
ids_map = &p->ids_map[id - btf->start_id];
5931+
/* duplicate type IDs are not allowed */
5932+
if (*ids_map) {
5933+
err = -EINVAL;
5934+
goto out_err;
5935+
}
5936+
len = btf_type_size(t);
5937+
memcpy(nt, t, len);
5938+
new_offs[i] = nt - new_types;
5939+
*ids_map = btf->start_id + i;
5940+
nt += len;
5941+
}
5942+
5943+
/* resize */
5944+
if (p->ids_sz < btf->nr_types) {
5945+
__u32 type_len = nt - new_types;
5946+
void *tmp_types;
5947+
5948+
tmp_types = realloc(new_types, type_len);
5949+
if (!tmp_types) {
5950+
err = -ENOMEM;
5951+
goto out_err;
5952+
}
5953+
new_types = tmp_types;
5954+
btf->nr_types = p->ids_sz;
5955+
btf->type_offs_cap = p->ids_sz;
5956+
btf->types_data_cap = type_len;
5957+
btf->hdr->type_len = type_len;
5958+
btf->hdr->str_off = type_len;
5959+
btf->raw_size = btf->hdr->hdr_len + btf->hdr->type_len + btf->hdr->str_len;
5960+
}
5961+
free(btf->types_data);
5962+
free(btf->type_offs);
5963+
btf->types_data = new_types;
5964+
btf->type_offs = new_offs;
5965+
return 0;
5966+
5967+
out_err:
5968+
free(new_offs);
5969+
free(new_types);
5970+
return err;
5971+
}
5972+
5973+
/* Callback function to remap individual type ID references
5974+
*
5975+
* This callback is invoked by btf_remap_types() for each type ID reference
5976+
* found in the BTF data. It updates the reference to point to the new
5977+
* permuted type ID using ids_map array.
5978+
*/
5979+
static int btf_permute_remap_type_id(__u32 *type_id, void *ctx)
5980+
{
5981+
struct btf_permute *p = ctx;
5982+
__u32 new_type_id = *type_id;
5983+
5984+
/* skip references that point into the base BTF */
5985+
if (new_type_id < p->btf->start_id)
5986+
return 0;
5987+
5988+
new_type_id = p->ids_map[*type_id - p->btf->start_id];
5989+
if (new_type_id > BTF_MAX_NR_TYPES)
5990+
return -EINVAL;
5991+
5992+
*type_id = new_type_id;
5993+
return 0;
5994+
}
5995+
5996+
/* Remap referenced type IDs into permuted type IDs.
5997+
*
5998+
* After BTF types are permuted, their final type IDs may differ from original
5999+
* ones. The map from original to a corresponding permuted type ID is stored
6000+
* in p->ids_map array and is populated during shuffle phase. During remapping
6001+
* phase we are rewriting all type IDs referenced from any BTF type (e.g.,
6002+
* struct fields, func proto args, etc) to their final permuted type IDs.
6003+
*/
6004+
static int btf_permute_remap_types(struct btf_permute *p)
6005+
{
6006+
return btf_remap_types(p->btf, p->btf_ext, btf_permute_remap_type_id, p);
6007+
}
6008+

tools/lib/bpf/btf.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,37 @@ LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts);
281281
*/
282282
LIBBPF_API int btf__relocate(struct btf *btf, const struct btf *base_btf);
283283

284+
struct btf_permute_opts {
285+
size_t sz;
286+
/* optional .BTF.ext info along the main BTF info */
287+
struct btf_ext *btf_ext;
288+
size_t :0;
289+
};
290+
#define btf_permute_opts__last_field btf_ext
291+
292+
/**
293+
* @brief **btf__permute()** rearranges BTF types in-place according to specified mapping
294+
* @param btf BTF object to permute
295+
* @param ids Array containing original type IDs (exclude VOID type ID 0) in user-defined order.
296+
* @param ids_sz Number of elements in @ids array
297+
* @param opts Optional parameters for BTF extension data reference updates
298+
* @return 0 on success, negative error code on failure
299+
*
300+
* **btf__permute()** performs an in-place permutation of BTF types, rearranging them according
301+
* to the order specified in @ids array. If @ids_sz is smaller than the total number of types
302+
* in @btf, the BTF will be truncated to contain only the types specified in @ids. After
303+
* reordering, all type references within the BTF data and optional BTF extension are updated
304+
* to maintain consistency. Subsequent btf__dedup may be required if the BTF is truncated during
305+
* permutation.
306+
*
307+
* On error, negative error code is returned and errno is set appropriately.
308+
* Common error codes include:
309+
* - -EINVAL: Invalid parameters or invalid ID mapping (e.g., duplicate IDs, out-of-range IDs)
310+
* - -ENOMEM: Memory allocation failure during permutation process
311+
*/
312+
LIBBPF_API int btf__permute(struct btf *btf, __u32 *ids, __u32 ids_sz,
313+
const struct btf_permute_opts *opts);
314+
284315
struct btf_dump;
285316

286317
struct btf_dump_opts {

tools/lib/bpf/libbpf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,4 +451,5 @@ LIBBPF_1.7.0 {
451451
global:
452452
bpf_map__set_exclusive_program;
453453
bpf_map__exclusive_program;
454+
btf__permute;
454455
} LIBBPF_1.6.0;

0 commit comments

Comments
 (0)