Skip to content

Commit

Permalink
perf tools: Preserve eBPF maps when loading kcore
Browse files Browse the repository at this point in the history
We need to preserve eBPF maps even if they are covered by kcore, because
we need to access eBPF dso for source data.

Add the map_groups__merge_in function to do that.  It merges a map into
map_groups by splitting the new map within the existing map regions.

Suggested-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190508132010.14512-9-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Jiri Olsa authored and Arnaldo Carvalho de Melo committed May 28, 2019
1 parent 8529f2e commit fb5a88d
Showing 1 changed file with 93 additions and 4 deletions.
97 changes: 93 additions & 4 deletions tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,85 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
return 0;
}

/*
* Merges map into map_groups by splitting the new map
* within the existing map regions.
*/
static int map_groups__merge_in(struct map_groups *kmaps, struct map *new_map)
{
struct map *old_map;
LIST_HEAD(merged);

for (old_map = map_groups__first(kmaps); old_map;
old_map = map_groups__next(old_map)) {

/* no overload with this one */
if (new_map->end < old_map->start ||
new_map->start >= old_map->end)
continue;

if (new_map->start < old_map->start) {
/*
* |new......
* |old....
*/
if (new_map->end < old_map->end) {
/*
* |new......| -> |new..|
* |old....| -> |old....|
*/
new_map->end = old_map->start;
} else {
/*
* |new.............| -> |new..| |new..|
* |old....| -> |old....|
*/
struct map *m = map__clone(new_map);

if (!m)
return -ENOMEM;

m->end = old_map->start;
list_add_tail(&m->node, &merged);
new_map->start = old_map->end;
}
} else {
/*
* |new......
* |old....
*/
if (new_map->end < old_map->end) {
/*
* |new..| -> x
* |old.........| -> |old.........|
*/
map__put(new_map);
new_map = NULL;
break;
} else {
/*
* |new......| -> |new...|
* |old....| -> |old....|
*/
new_map->start = old_map->end;
}
}
}

while (!list_empty(&merged)) {
old_map = list_entry(merged.next, struct map, node);
list_del_init(&old_map->node);
map_groups__insert(kmaps, old_map);
map__put(old_map);
}

if (new_map) {
map_groups__insert(kmaps, new_map);
map__put(new_map);
}
return 0;
}

static int dso__load_kcore(struct dso *dso, struct map *map,
const char *kallsyms_filename)
{
Expand Down Expand Up @@ -1222,7 +1301,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
while (old_map) {
struct map *next = map_groups__next(old_map);

if (old_map != map)
/*
* We need to preserve eBPF maps even if they are
* covered by kcore, because we need to access
* eBPF dso for source data.
*/
if (old_map != map && !__map__is_bpf_prog(old_map))
map_groups__remove(kmaps, old_map);
old_map = next;
}
Expand Down Expand Up @@ -1256,11 +1340,16 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
map_groups__remove(kmaps, map);
map_groups__insert(kmaps, map);
map__put(map);
map__put(new_map);
} else {
map_groups__insert(kmaps, new_map);
/*
* Merge kcore map into existing maps,
* and ensure that current maps (eBPF)
* stay intact.
*/
if (map_groups__merge_in(kmaps, new_map))
goto out_err;
}

map__put(new_map);
}

if (machine__is(machine, "x86_64")) {
Expand Down

0 comments on commit fb5a88d

Please sign in to comment.