Re: [PATCH v3 3/3] perf maps: Remove the replacement of kernel map

From: Adrian Hunter
Date: Wed May 22 2024 - 04:58:21 EST


On 20/05/24 12:06, Leo Yan wrote:
> The kernel text map has been removed from the kernel maps by
> maps__remove_maps(), and the kcore maps are organized in order, allowing
> us to achieve neat kernel maps.
>
> As a result, it is not necessary to replace the old kernel text map.
> Instead, the commit finds the latest text map, assigns it to
> 'machine->vmlinux_map', and releases the old map.

There is also the parameter 'map' that the caller can continue
to use. It was originally vmlinux_map which was checked:

/* This function requires that the map is the kernel map */
if (!__map__is_kernel(map))
return -EINVAL;

Although that now looks broken and should probably be:

/* This function requires that the map is the kernel map */
if (map != machine__kernel_map(machine))
return -EINVAL;

>
> One concern is if a platform fails to find a kernel text map after
> updating maps list with kcore, in this case, it should not happen and
> reports the failure.
>
> Signed-off-by: Leo Yan <leo.yan@xxxxxxx>
> ---
> tools/perf/util/symbol.c | 77 ++++++++++------------------------------
> 1 file changed, 19 insertions(+), 58 deletions(-)
>
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 915435d55498..a4b65d868fc9 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1335,13 +1335,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
> const char *kallsyms_filename)
> {
> struct maps *kmaps = map__kmaps(map);
> + struct map *vmlinux_map;
> struct kcore_mapfn_data md;
> - struct map *map_ref, *replacement_map = NULL;
> struct machine *machine;
> bool is_64_bit;
> int err, fd;
> char kcore_filename[PATH_MAX];
> - u64 stext;
>
> if (!kmaps)
> return -EINVAL;
> @@ -1386,51 +1385,6 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
> maps__remove_maps(kmaps, remove_old_maps);
> machine->trampolines_mapped = false;
>
> - /* Find the kernel map using the '_stext' symbol */
> - if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) {
> - u64 replacement_size = 0;
> - struct map_list_node *new_node;
> -
> - list_for_each_entry(new_node, &md.maps, node) {
> - struct map *new_map = new_node->map;
> - u64 new_size = map__size(new_map);
> -
> - if (!(stext >= map__start(new_map) && stext < map__end(new_map)))
> - continue;
> -
> - /*
> - * On some architectures, ARM64 for example, the kernel
> - * text can get allocated inside of the vmalloc segment.
> - * Select the smallest matching segment, in case stext
> - * falls within more than one in the list.
> - */
> - if (!replacement_map || new_size < replacement_size) {
> - replacement_map = new_map;
> - replacement_size = new_size;
> - }
> - }
> - }
> -
> - if (!replacement_map)
> - replacement_map = list_entry(md.maps.next, struct map_list_node, node)->map;
> -
> - /*
> - * Update addresses of vmlinux map. Re-insert it to ensure maps are
> - * correctly ordered. Do this before using maps__merge_in() for the
> - * remaining maps so vmlinux gets split if necessary.
> - */
> - map_ref = map__get(map);
> -
> - map__set_start(map_ref, map__start(replacement_map));
> - map__set_end(map_ref, map__end(replacement_map));
> - map__set_pgoff(map_ref, map__pgoff(replacement_map));
> - map__set_mapping_type(map_ref, map__mapping_type(replacement_map));
> -
> - err = maps__insert(kmaps, map_ref);
> - map__put(map_ref);
> - if (err)
> - goto out_err;
> -
> /* Add new maps */
> while (!list_empty(&md.maps)) {
> struct map_list_node *new_node = list_entry(md.maps.next, struct map_list_node, node);
> @@ -1438,21 +1392,28 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
>
> list_del_init(&new_node->node);
>
> - /* skip if replacement_map, already inserted above */
> - if (!RC_CHK_EQUAL(new_map, replacement_map)) {
> - /*
> - * Merge kcore map into existing maps,
> - * and ensure that current maps (eBPF)
> - * stay intact.
> - */
> - if (maps__merge_in(kmaps, new_map)) {
> - err = -EINVAL;
> - goto out_err;
> - }
> + /*
> + * Merge kcore map into existing maps,
> + * and ensure that current maps (eBPF)
> + * stay intact.
> + */
> + if (maps__merge_in(kmaps, new_map)) {
> + err = -EINVAL;
> + goto out_err;
> }
> free(new_node);
> }
>
> + /* Update vmlinux_map */
> + vmlinux_map = maps__find(kmaps, map__start(map));
> + if (vmlinux_map) {
> + free(machine->vmlinux_map);

Reference counting?

> + machine->vmlinux_map = vmlinux_map;
> + } else {
> + pr_err("Failed to find vmlinux map from kcore\n");
> + goto out_err;
> + }
> +
> if (machine__is(machine, "x86_64")) {
> u64 addr;
>