From nobody Fri Dec 19 19:23:32 2025 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7ADE3314BC for ; Thu, 6 Nov 2025 13:20:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762435228; cv=none; b=OeU2NdyRDggWRVe7+AC6lQC6DHhY5IPflPvXIPBM9MD/RyyQhNxf8KMnJ3pZC34BEpAK2/i7R+uEvAyyWoQ5co7VAsRU9e2Hr3knOvj8IZT6m78/YW3VHmC2sU6OoJV/Dd2CLTgNLAKVwil+j4qeW2xO/QJ1Xv2CPokLoIbARhI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762435228; c=relaxed/simple; bh=5WMlMP0Qa86xjepvackGCM9Kudf88xqqA/oP2jNoOCQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Nl4bbia+VlWUtOnGiQWVNopUMlRq8IA2rFSE2S8BiKKKWAEGXtCyOZVnZUagdut9hvU3L6hmPp9LwtYH1/h4T+U5fl6KCk9ZCYTGFLXD+AmRsT8iq9ytgpXOdxTsJ+sYnSJ+S8HBLwovrxdNA9c2Zq0DLNF1h+aWxP0UPh70TF4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=aQjYe9Xr; arc=none smtp.client-ip=209.85.216.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aQjYe9Xr" Received: by mail-pj1-f48.google.com with SMTP id 98e67ed59e1d1-340bb1cb9ddso883446a91.2 for ; Thu, 06 Nov 2025 05:20:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762435224; x=1763040024; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=eE4f1ExBgKlia9rPOG35Lwiq1YmfGukK360i7Hwinqw=; b=aQjYe9XrE+e8eNCSH/ilBMoiaZvJph4A6bFp+4ZXXtG/XGfXd0amdwEJQ8GlXP1TUG SodsMDPHx5a8dEX0TTiURx+Y26FjkGpO6gXEqvH5G/KlyhfUXl7NcAjyQLSPqEPiz9Y4 0VFyhTbix9sildE0McG/lVIfEcWHQL2EjUHPa4ef2T0RWh1vn7u3+MsN4JssMPMJNJnG fbKrg9WAzBnr2q3zraxY7dmhz9J+Hw5Moh1FU2fIFTYHTOaZ63brZR+WlcZ+0x7gjNHc m+2a8iIcfDfqsVsFM1rXB5PetEfNe8S8XrTkxsfLjdtFwXbUKQpH+x0DSJYjv8AlGzek I0cA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762435224; x=1763040024; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eE4f1ExBgKlia9rPOG35Lwiq1YmfGukK360i7Hwinqw=; b=DmUqStTdN8P6BqqrkvluOKMkQvW7NqjTH2d4iV9lt4QJ//nq/W1RytK4slw9A/KloY 3sTO8VHwIYZVP2iayQNZUwyBg+QYfYnsjTAwbcpT9EbJQodmcwaTu8nD9fLEsWp3hpsW l0NoIxZ5hFzgA1xIhqCgrLWLv/QfNSKNw/YJN4XVSbAFyTZlrvdaEDu1o6rq/u5++gWo Z6ZK3tNPXldKo+5bA06Ovr+mi0rlUfBc2AQO1TR2O9w8YXij2EObkicMdeYkweYTr8vm mYqa0v96MJe2o/oVn6MU+0pTW+7rBUHuck03spnsPiJ6rHMnxx+FJWncvA85mmF6paoA L+eg== X-Forwarded-Encrypted: i=1; AJvYcCUad1WDBs8NLCwAEiZixixK27eezRcaP5yc21h/Cod2hYkLqzaTeE3LHhHVAp/WepQ5+4kKjOPCoZG4WEw=@vger.kernel.org X-Gm-Message-State: AOJu0YyPZ1vkkik4DolBEmcpekDAEIshG6Dny6fYCbAW4AzlajUjvoe/ 8yF/mSsa3mVM1Bnd7B3ZHMXLWlXYLYH+XQyLupzwIpr/mRF+qsuE56Hx X-Gm-Gg: ASbGncshxxIoCZClOjYhC3ZMT2heBbc9dou4VS1vl382Qmk4RuIy5+wKpnuKVTS4R4J GlVQfedp1X1anW+H1OOlloHtHA1vvx6l2AVl+5VWvvVJCksSQtxbh0mwKqOCxuZPWarGG7tnod9 y8ghapj/YB90zmDuIFIBWxzu3ZvWzASS2ow0uZtao38b3jtPzgjV2QxLr6NrgZ+sJEHY/Kbv3e7 w1bTnEHf3gCtWNuWKW2jZTNTn+doY5R9Ig20OVbLnavKAQa2OGMgQnFwaWuA0tFAe4pv++wXeqz AIAC5UtMVJKu+oLmVmLvHuxQ5zOCy8xL/Gmf7s/RmVDildMfNY8LTPbTcFNuAV3ClZGEs+/r4tW 9+1uMi9ouA8gUd4VZJqxDZfZ4oDJCswit4O0oDtTrPIr2DpqtN1hbdYGLoMJx7MAG2DGcmJJmyX Sn2BjkG9qcU9T868eP X-Google-Smtp-Source: AGHT+IHl0IBfcX7XHHEZM/JveOzysrq0UeZjBlkdDeFpHD0i/NWXnablAyZP2GJ7vtmKTkU9OsY4CA== X-Received: by 2002:a17:90b:2fcd:b0:338:3d07:5174 with SMTP id 98e67ed59e1d1-341a6c4189bmr8351963a91.5.1762435223917; Thu, 06 Nov 2025 05:20:23 -0800 (PST) Received: from pengdl-pc.mioffice.cn ([43.224.245.249]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-341d3e0b0b2sm1914869a91.21.2025.11.06.05.20.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Nov 2025 05:20:22 -0800 (PST) From: Donglin Peng To: ast@kernel.org Cc: eddyz87@gmail.com, andrii.nakryiko@gmail.com, zhangxiaoqin@xiaomi.com, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, Donglin Peng , Alan Maguire , Song Liu , Donglin Peng Subject: [PATCH v5 2/7] libbpf: Add BTF permutation support for type reordering Date: Thu, 6 Nov 2025 21:19:51 +0800 Message-Id: <20251106131956.1222864-3-dolinux.peng@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251106131956.1222864-1-dolinux.peng@gmail.com> References: <20251106131956.1222864-1-dolinux.peng@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Donglin Peng 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 Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Alan Maguire Cc: Song Liu Cc: Xiaoqin Zhang Signed-off-by: Donglin Peng Signed-off-by: Donglin Peng Acked-by: Eduard Zingerman --- tools/lib/bpf/btf.c | 176 +++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/btf.h | 31 +++++++ tools/lib/bpf/libbpf.map | 1 + 3 files changed, 208 insertions(+) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 0c1dab8a199a..aad630822584 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -5830,3 +5830,179 @@ int btf__relocate(struct btf *btf, const struct btf= *base_btf) btf->owns_base =3D false; return libbpf_err(err); } + +struct btf_permute { + /* .BTF section to be permuted in-place */ + struct btf *btf; + /* optional .BTF.ext info along the main BTF info */ + struct btf_ext *btf_ext; + /* Array containing original type IDs (exclude VOID type ID 0) + * in user-defined order + */ + __u32 *ids; + /* Array used to map from original type ID to a new permuted type + * ID + */ + __u32 *ids_map; + /* Number of elements in ids array */ + __u32 ids_sz; +}; + +static int btf_permute_shuffle_types(struct btf_permute *p); +static int btf_permute_remap_types(struct btf_permute *p); +static int btf_permute_remap_type_id(__u32 *type_id, void *ctx); + +int btf__permute(struct btf *btf, __u32 *ids, __u32 ids_sz, const struct b= tf_permute_opts *opts) +{ + struct btf_permute p; + int err =3D 0; + __u32 *ids_map =3D NULL; + + if (!OPTS_VALID(opts, btf_permute_opts) || (ids_sz > btf->nr_types)) + return libbpf_err(-EINVAL); + + ids_map =3D calloc(ids_sz, sizeof(*ids_map)); + if (!ids_map) { + err =3D -ENOMEM; + goto done; + } + + p.btf =3D btf; + p.btf_ext =3D OPTS_GET(opts, btf_ext, NULL); + p.ids =3D ids; + p.ids_map =3D ids_map; + p.ids_sz =3D ids_sz; + + if (btf_ensure_modifiable(btf)) { + err =3D -ENOMEM; + goto done; + } + err =3D btf_permute_shuffle_types(&p); + if (err < 0) { + goto done; + } + err =3D btf_permute_remap_types(&p); + if (err < 0) { + goto done; + } + +done: + free(ids_map); + return libbpf_err(err); +} + +/* Shuffle BTF types. + * + * Rearranges types according to the order specified in p->ids array. + * The p->ids_map array stores the mapping from original type IDs to + * new shuffled IDs, which is used in the next phase to update type + * references. + */ +static int btf_permute_shuffle_types(struct btf_permute *p) +{ + struct btf *btf =3D p->btf; + const struct btf_type *t; + __u32 *new_offs =3D NULL, *ids_map; + void *nt, *new_types =3D NULL; + int i, id, len, err; + + new_offs =3D calloc(p->ids_sz, sizeof(*new_offs)); + new_types =3D calloc(btf->hdr->type_len, 1); + if (!new_offs || !new_types) { + err =3D -ENOMEM; + goto out_err; + } + + nt =3D new_types; + for (i =3D 0; i < p->ids_sz; i++) { + id =3D p->ids[i]; + /* type IDs from base_btf and the VOID type are not allowed */ + if (id < btf->start_id) { + err =3D -EINVAL; + goto out_err; + } + /* must be a valid type ID */ + t =3D btf__type_by_id(btf, id); + if (!t) { + err =3D -EINVAL; + goto out_err; + } + ids_map =3D &p->ids_map[id - btf->start_id]; + /* duplicate type IDs are not allowed */ + if (*ids_map) { + err =3D -EINVAL; + goto out_err; + } + len =3D btf_type_size(t); + memcpy(nt, t, len); + new_offs[i] =3D nt - new_types; + *ids_map =3D btf->start_id + i; + nt +=3D len; + } + + /* resize */ + if (p->ids_sz < btf->nr_types) { + __u32 type_len =3D nt - new_types; + void *tmp_types; + + tmp_types =3D realloc(new_types, type_len); + if (!tmp_types) { + err =3D -ENOMEM; + goto out_err; + } + new_types =3D tmp_types; + btf->nr_types =3D p->ids_sz; + btf->type_offs_cap =3D p->ids_sz; + btf->types_data_cap =3D type_len; + btf->hdr->type_len =3D type_len; + btf->hdr->str_off =3D type_len; + btf->raw_size =3D btf->hdr->hdr_len + btf->hdr->type_len + btf->hdr->str= _len; + } + free(btf->types_data); + free(btf->type_offs); + btf->types_data =3D new_types; + btf->type_offs =3D new_offs; + return 0; + +out_err: + free(new_offs); + free(new_types); + return err; +} + +/* Callback function to remap individual type ID references + * + * This callback is invoked by btf_remap_types() for each type ID reference + * found in the BTF data. It updates the reference to point to the new + * permuted type ID using ids_map array. + */ +static int btf_permute_remap_type_id(__u32 *type_id, void *ctx) +{ + struct btf_permute *p =3D ctx; + __u32 new_type_id =3D *type_id; + + /* skip references that point into the base BTF */ + if (new_type_id < p->btf->start_id) + return 0; + + new_type_id =3D p->ids_map[*type_id - p->btf->start_id]; + if (new_type_id > BTF_MAX_NR_TYPES) + return -EINVAL; + + *type_id =3D new_type_id; + return 0; +} + +/* Remap referenced type IDs into permuted type IDs. + * + * After BTF types are permuted, their final type IDs may differ from orig= inal + * ones. The map from original to a corresponding permuted type ID is stor= ed + * in p->ids_map array and is populated during shuffle phase. During remap= ping + * phase we are rewriting all type IDs referenced from any BTF type (e.g., + * struct fields, func proto args, etc) to their final permuted type IDs. + */ +static int btf_permute_remap_types(struct btf_permute *p) +{ + return btf_remap_types(p->btf, p->btf_ext, btf_permute_remap_type_id, p); +} + diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index ccfd905f03df..a0bf9b011c94 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -273,6 +273,37 @@ LIBBPF_API int btf__dedup(struct btf *btf, const struc= t btf_dedup_opts *opts); */ LIBBPF_API int btf__relocate(struct btf *btf, const struct btf *base_btf); =20 +struct btf_permute_opts { + size_t sz; + /* optional .BTF.ext info along the main BTF info */ + struct btf_ext *btf_ext; + size_t :0; +}; +#define btf_permute_opts__last_field btf_ext + +/** + * @brief **btf__permute()** rearranges BTF types in-place according to sp= ecified mapping + * @param btf BTF object to permute + * @param ids Array containing original type IDs (exclude VOID type ID 0) = in user-defined order. + * @param ids_sz Number of elements in @ids array + * @param opts Optional parameters for BTF extension data reference updates + * @return 0 on success, negative error code on failure + * + * **btf__permute()** performs an in-place permutation of BTF types, rearr= anging them according + * to the order specified in @ids array. If @ids_sz is smaller than the to= tal number of types + * in @btf, the BTF will be truncated to contain only the types specified = in @ids. After + * reordering, all type references within the BTF data and optional BTF ex= tension are updated + * to maintain consistency. Subsequent btf__dedup may be required if the B= TF is truncated during + * permutation. + * + * On error, negative error code is returned and errno is set appropriatel= y. + * Common error codes include: + * - -EINVAL: Invalid parameters or invalid ID mapping (e.g., duplicate = IDs, out-of-range IDs) + * - -ENOMEM: Memory allocation failure during permutation process + */ +LIBBPF_API int btf__permute(struct btf *btf, __u32 *ids, __u32 ids_sz, + const struct btf_permute_opts *opts); + struct btf_dump; =20 struct btf_dump_opts { diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 8ed8749907d4..b778e5a5d0a8 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -451,4 +451,5 @@ LIBBPF_1.7.0 { global: bpf_map__set_exclusive_program; bpf_map__exclusive_program; + btf__permute; } LIBBPF_1.6.0; --=20 2.34.1