Commit f045b8c4 authored by Krister Johansen's avatar Krister Johansen Committed by Arnaldo Carvalho de Melo

perf buildid-cache: Support binary objects from other namespaces

Teach buildid-cache how to add, remove, and update binary objects from
other mount namespaces.  Allow probe events tracing binaries in
different namespaces to add their objects to the probe and build-id
caches too.  As a handy side effect, this also lets us access SDT probes
in binaries from alternate mount namespaces.
Signed-off-by: default avatarKrister Johansen <kjlx@templeofstupid.com>
Tested-by: default avatarBrendan Gregg <brendan.d.gregg@gmail.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1499305693-1599-5-git-send-email-kjlx@templeofstupid.com
[ Add util/namespaces.c to tools/perf/util/python-ext-sources, to fix the python binding 'perf test' ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 544abd44
...@@ -61,6 +61,11 @@ OPTIONS ...@@ -61,6 +61,11 @@ OPTIONS
--verbose:: --verbose::
Be more verbose. Be more verbose.
--target-ns=PID:
Obtain mount namespace information from the target pid. This is
used when creating a uprobe for a process that resides in a
different mount namespace from the perf(1) utility.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1] linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1]
...@@ -273,6 +273,11 @@ Add a uprobe to a target process running in a different mount namespace ...@@ -273,6 +273,11 @@ Add a uprobe to a target process running in a different mount namespace
./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc ./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc
Add a USDT probe to a target process running in a different mount namespace
./perf probe --target-ns <target pid> -x /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.121-0.b13.el7_3.x86_64/jre/lib/amd64/server/libjvm.so %sdt_hotspot:thread__sleep__end
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1] linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <unistd.h> #include <unistd.h>
#include "builtin.h" #include "builtin.h"
#include "perf.h" #include "perf.h"
#include "namespaces.h"
#include "util/cache.h" #include "util/cache.h"
#include "util/debug.h" #include "util/debug.h"
#include "util/header.h" #include "util/header.h"
...@@ -165,33 +166,41 @@ static int build_id_cache__add_kcore(const char *filename, bool force) ...@@ -165,33 +166,41 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
return 0; return 0;
} }
static int build_id_cache__add_file(const char *filename) static int build_id_cache__add_file(const char *filename, struct nsinfo *nsi)
{ {
char sbuild_id[SBUILD_ID_SIZE]; char sbuild_id[SBUILD_ID_SIZE];
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
int err; int err;
struct nscookie nsc;
if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { nsinfo__mountns_enter(nsi, &nsc);
err = filename__read_build_id(filename, &build_id, sizeof(build_id));
nsinfo__mountns_exit(&nsc);
if (err < 0) {
pr_debug("Couldn't read a build-id in %s\n", filename); pr_debug("Couldn't read a build-id in %s\n", filename);
return -1; return -1;
} }
build_id__sprintf(build_id, sizeof(build_id), sbuild_id); build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
err = build_id_cache__add_s(sbuild_id, filename, err = build_id_cache__add_s(sbuild_id, filename, nsi,
false, false); false, false);
pr_debug("Adding %s %s: %s\n", sbuild_id, filename, pr_debug("Adding %s %s: %s\n", sbuild_id, filename,
err ? "FAIL" : "Ok"); err ? "FAIL" : "Ok");
return err; return err;
} }
static int build_id_cache__remove_file(const char *filename) static int build_id_cache__remove_file(const char *filename, struct nsinfo *nsi)
{ {
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
char sbuild_id[SBUILD_ID_SIZE]; char sbuild_id[SBUILD_ID_SIZE];
struct nscookie nsc;
int err; int err;
if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { nsinfo__mountns_enter(nsi, &nsc);
err = filename__read_build_id(filename, &build_id, sizeof(build_id));
nsinfo__mountns_exit(&nsc);
if (err < 0) {
pr_debug("Couldn't read a build-id in %s\n", filename); pr_debug("Couldn't read a build-id in %s\n", filename);
return -1; return -1;
} }
...@@ -204,13 +213,13 @@ static int build_id_cache__remove_file(const char *filename) ...@@ -204,13 +213,13 @@ static int build_id_cache__remove_file(const char *filename)
return err; return err;
} }
static int build_id_cache__purge_path(const char *pathname) static int build_id_cache__purge_path(const char *pathname, struct nsinfo *nsi)
{ {
struct strlist *list; struct strlist *list;
struct str_node *pos; struct str_node *pos;
int err; int err;
err = build_id_cache__list_build_ids(pathname, &list); err = build_id_cache__list_build_ids(pathname, nsi, &list);
if (err) if (err)
goto out; goto out;
...@@ -256,24 +265,30 @@ static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *f ...@@ -256,24 +265,30 @@ static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *f
return 0; return 0;
} }
static int build_id_cache__update_file(const char *filename) static int build_id_cache__update_file(const char *filename, struct nsinfo *nsi)
{ {
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
char sbuild_id[SBUILD_ID_SIZE]; char sbuild_id[SBUILD_ID_SIZE];
struct nscookie nsc;
int err = 0; int err;
if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { nsinfo__mountns_enter(nsi, &nsc);
err = filename__read_build_id(filename, &build_id, sizeof(build_id));
nsinfo__mountns_exit(&nsc);
if (err < 0) {
pr_debug("Couldn't read a build-id in %s\n", filename); pr_debug("Couldn't read a build-id in %s\n", filename);
return -1; return -1;
} }
err = 0;
build_id__sprintf(build_id, sizeof(build_id), sbuild_id); build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
if (build_id_cache__cached(sbuild_id)) if (build_id_cache__cached(sbuild_id))
err = build_id_cache__remove_s(sbuild_id); err = build_id_cache__remove_s(sbuild_id);
if (!err) if (!err)
err = build_id_cache__add_s(sbuild_id, filename, false, false); err = build_id_cache__add_s(sbuild_id, filename, nsi, false,
false);
pr_debug("Updating %s %s: %s\n", sbuild_id, filename, pr_debug("Updating %s %s: %s\n", sbuild_id, filename,
err ? "FAIL" : "Ok"); err ? "FAIL" : "Ok");
...@@ -286,6 +301,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -286,6 +301,7 @@ int cmd_buildid_cache(int argc, const char **argv)
struct strlist *list; struct strlist *list;
struct str_node *pos; struct str_node *pos;
int ret = 0; int ret = 0;
int ns_id = -1;
bool force = false; bool force = false;
char const *add_name_list_str = NULL, char const *add_name_list_str = NULL,
*remove_name_list_str = NULL, *remove_name_list_str = NULL,
...@@ -299,6 +315,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -299,6 +315,7 @@ int cmd_buildid_cache(int argc, const char **argv)
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
}; };
struct perf_session *session = NULL; struct perf_session *session = NULL;
struct nsinfo *nsi = NULL;
const struct option buildid_cache_options[] = { const struct option buildid_cache_options[] = {
OPT_STRING('a', "add", &add_name_list_str, OPT_STRING('a', "add", &add_name_list_str,
...@@ -315,6 +332,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -315,6 +332,7 @@ int cmd_buildid_cache(int argc, const char **argv)
OPT_STRING('u', "update", &update_name_list_str, "file list", OPT_STRING('u', "update", &update_name_list_str, "file list",
"file(s) to update"), "file(s) to update"),
OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_INCR('v', "verbose", &verbose, "be more verbose"),
OPT_INTEGER(0, "target-ns", &ns_id, "target pid for namespace context"),
OPT_END() OPT_END()
}; };
const char * const buildid_cache_usage[] = { const char * const buildid_cache_usage[] = {
...@@ -330,6 +348,9 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -330,6 +348,9 @@ int cmd_buildid_cache(int argc, const char **argv)
!missing_filename && !update_name_list_str)) !missing_filename && !update_name_list_str))
usage_with_options(buildid_cache_usage, buildid_cache_options); usage_with_options(buildid_cache_usage, buildid_cache_options);
if (ns_id > 0)
nsi = nsinfo__new(ns_id);
if (missing_filename) { if (missing_filename) {
file.path = missing_filename; file.path = missing_filename;
file.force = force; file.force = force;
...@@ -348,7 +369,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -348,7 +369,7 @@ int cmd_buildid_cache(int argc, const char **argv)
list = strlist__new(add_name_list_str, NULL); list = strlist__new(add_name_list_str, NULL);
if (list) { if (list) {
strlist__for_each_entry(pos, list) strlist__for_each_entry(pos, list)
if (build_id_cache__add_file(pos->s)) { if (build_id_cache__add_file(pos->s, nsi)) {
if (errno == EEXIST) { if (errno == EEXIST) {
pr_debug("%s already in the cache\n", pr_debug("%s already in the cache\n",
pos->s); pos->s);
...@@ -366,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -366,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv)
list = strlist__new(remove_name_list_str, NULL); list = strlist__new(remove_name_list_str, NULL);
if (list) { if (list) {
strlist__for_each_entry(pos, list) strlist__for_each_entry(pos, list)
if (build_id_cache__remove_file(pos->s)) { if (build_id_cache__remove_file(pos->s, nsi)) {
if (errno == ENOENT) { if (errno == ENOENT) {
pr_debug("%s wasn't in the cache\n", pr_debug("%s wasn't in the cache\n",
pos->s); pos->s);
...@@ -384,7 +405,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -384,7 +405,7 @@ int cmd_buildid_cache(int argc, const char **argv)
list = strlist__new(purge_name_list_str, NULL); list = strlist__new(purge_name_list_str, NULL);
if (list) { if (list) {
strlist__for_each_entry(pos, list) strlist__for_each_entry(pos, list)
if (build_id_cache__purge_path(pos->s)) { if (build_id_cache__purge_path(pos->s, nsi)) {
if (errno == ENOENT) { if (errno == ENOENT) {
pr_debug("%s wasn't in the cache\n", pr_debug("%s wasn't in the cache\n",
pos->s); pos->s);
...@@ -405,7 +426,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -405,7 +426,7 @@ int cmd_buildid_cache(int argc, const char **argv)
list = strlist__new(update_name_list_str, NULL); list = strlist__new(update_name_list_str, NULL);
if (list) { if (list) {
strlist__for_each_entry(pos, list) strlist__for_each_entry(pos, list)
if (build_id_cache__update_file(pos->s)) { if (build_id_cache__update_file(pos->s, nsi)) {
if (errno == ENOENT) { if (errno == ENOENT) {
pr_debug("%s wasn't in the cache\n", pr_debug("%s wasn't in the cache\n",
pos->s); pos->s);
...@@ -424,6 +445,7 @@ int cmd_buildid_cache(int argc, const char **argv) ...@@ -424,6 +445,7 @@ int cmd_buildid_cache(int argc, const char **argv)
out: out:
perf_session__delete(session); perf_session__delete(session);
nsinfo__zput(nsi);
return ret; return ret;
} }
...@@ -416,7 +416,7 @@ static int del_perf_probe_caches(struct strfilter *filter) ...@@ -416,7 +416,7 @@ static int del_perf_probe_caches(struct strfilter *filter)
} }
strlist__for_each_entry(nd, bidlist) { strlist__for_each_entry(nd, bidlist) {
cache = probe_cache__new(nd->s); cache = probe_cache__new(nd->s, NULL);
if (!cache) if (!cache)
continue; continue;
if (probe_cache__filter_purge(cache, filter) < 0 || if (probe_cache__filter_purge(cache, filter) < 0 ||
......
...@@ -33,7 +33,7 @@ static int build_id_cache__add_file(const char *filename) ...@@ -33,7 +33,7 @@ static int build_id_cache__add_file(const char *filename)
} }
build_id__sprintf(build_id, sizeof(build_id), sbuild_id); build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
err = build_id_cache__add_s(sbuild_id, filename, false, false); err = build_id_cache__add_s(sbuild_id, filename, NULL, false, false);
if (err < 0) if (err < 0)
pr_debug("Failed to add build id cache of %s\n", filename); pr_debug("Failed to add build id cache of %s\n", filename);
return err; return err;
...@@ -54,7 +54,7 @@ static char *get_self_path(void) ...@@ -54,7 +54,7 @@ static char *get_self_path(void)
static int search_cached_probe(const char *target, static int search_cached_probe(const char *target,
const char *group, const char *event) const char *group, const char *event)
{ {
struct probe_cache *cache = probe_cache__new(target); struct probe_cache *cache = probe_cache__new(target, NULL);
int ret = 0; int ret = 0;
if (!cache) { if (!cache) {
......
...@@ -534,13 +534,14 @@ char *build_id_cache__complement(const char *incomplete_sbuild_id) ...@@ -534,13 +534,14 @@ char *build_id_cache__complement(const char *incomplete_sbuild_id)
} }
char *build_id_cache__cachedir(const char *sbuild_id, const char *name, char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso) struct nsinfo *nsi, bool is_kallsyms,
bool is_vdso)
{ {
char *realname = (char *)name, *filename; char *realname = (char *)name, *filename;
bool slash = is_kallsyms || is_vdso; bool slash = is_kallsyms || is_vdso;
if (!slash) { if (!slash) {
realname = realpath(name, NULL); realname = nsinfo__realpath(name, nsi);
if (!realname) if (!realname)
return NULL; return NULL;
} }
...@@ -556,13 +557,13 @@ char *build_id_cache__cachedir(const char *sbuild_id, const char *name, ...@@ -556,13 +557,13 @@ char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
return filename; return filename;
} }
int build_id_cache__list_build_ids(const char *pathname, int build_id_cache__list_build_ids(const char *pathname, struct nsinfo *nsi,
struct strlist **result) struct strlist **result)
{ {
char *dir_name; char *dir_name;
int ret = 0; int ret = 0;
dir_name = build_id_cache__cachedir(NULL, pathname, false, false); dir_name = build_id_cache__cachedir(NULL, pathname, nsi, false, false);
if (!dir_name) if (!dir_name)
return -ENOMEM; return -ENOMEM;
...@@ -576,16 +577,20 @@ int build_id_cache__list_build_ids(const char *pathname, ...@@ -576,16 +577,20 @@ int build_id_cache__list_build_ids(const char *pathname,
#if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT) #if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT)
static int build_id_cache__add_sdt_cache(const char *sbuild_id, static int build_id_cache__add_sdt_cache(const char *sbuild_id,
const char *realname) const char *realname,
struct nsinfo *nsi)
{ {
struct probe_cache *cache; struct probe_cache *cache;
int ret; int ret;
struct nscookie nsc;
cache = probe_cache__new(sbuild_id); cache = probe_cache__new(sbuild_id, nsi);
if (!cache) if (!cache)
return -1; return -1;
nsinfo__mountns_enter(nsi, &nsc);
ret = probe_cache__scan_sdt(cache, realname); ret = probe_cache__scan_sdt(cache, realname);
nsinfo__mountns_exit(&nsc);
if (ret >= 0) { if (ret >= 0) {
pr_debug4("Found %d SDTs in %s\n", ret, realname); pr_debug4("Found %d SDTs in %s\n", ret, realname);
if (probe_cache__commit(cache) < 0) if (probe_cache__commit(cache) < 0)
...@@ -595,11 +600,11 @@ static int build_id_cache__add_sdt_cache(const char *sbuild_id, ...@@ -595,11 +600,11 @@ static int build_id_cache__add_sdt_cache(const char *sbuild_id,
return ret; return ret;
} }
#else #else
#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0) #define build_id_cache__add_sdt_cache(sbuild_id, realname, nsi) (0)
#endif #endif
int build_id_cache__add_s(const char *sbuild_id, const char *name, int build_id_cache__add_s(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso) struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
{ {
const size_t size = PATH_MAX; const size_t size = PATH_MAX;
char *realname = NULL, *filename = NULL, *dir_name = NULL, char *realname = NULL, *filename = NULL, *dir_name = NULL,
...@@ -607,13 +612,16 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -607,13 +612,16 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
int err = -1; int err = -1;
if (!is_kallsyms) { if (!is_kallsyms) {
realname = realpath(name, NULL); if (!is_vdso)
realname = nsinfo__realpath(name, nsi);
else
realname = realpath(name, NULL);
if (!realname) if (!realname)
goto out_free; goto out_free;
} }
dir_name = build_id_cache__cachedir(sbuild_id, name, dir_name = build_id_cache__cachedir(sbuild_id, name, nsi, is_kallsyms,
is_kallsyms, is_vdso); is_vdso);
if (!dir_name) if (!dir_name)
goto out_free; goto out_free;
...@@ -634,7 +642,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -634,7 +642,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
if (access(filename, F_OK)) { if (access(filename, F_OK)) {
if (is_kallsyms) { if (is_kallsyms) {
if (copyfile("/proc/kallsyms", filename)) if (copyfile("/proc/kallsyms", filename))
goto out_free;
} else if (nsi && nsi->need_setns) {
if (copyfile_ns(name, filename, nsi))
goto out_free; goto out_free;
} else if (link(realname, filename) && errno != EEXIST && } else if (link(realname, filename) && errno != EEXIST &&
copyfile(name, filename)) copyfile(name, filename))
...@@ -657,7 +668,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -657,7 +668,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
err = 0; err = 0;
/* Update SDT cache : error is just warned */ /* Update SDT cache : error is just warned */
if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) if (realname &&
build_id_cache__add_sdt_cache(sbuild_id, realname, nsi) < 0)
pr_debug4("Failed to update/scan SDT cache for %s\n", realname); pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
out_free: out_free:
...@@ -670,14 +682,15 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -670,14 +682,15 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
} }
static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
const char *name, bool is_kallsyms, const char *name, struct nsinfo *nsi,
bool is_vdso) bool is_kallsyms, bool is_vdso)
{ {
char sbuild_id[SBUILD_ID_SIZE]; char sbuild_id[SBUILD_ID_SIZE];
build_id__sprintf(build_id, build_id_size, sbuild_id); build_id__sprintf(build_id, build_id_size, sbuild_id);
return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso); return build_id_cache__add_s(sbuild_id, name, nsi, is_kallsyms,
is_vdso);
} }
bool build_id_cache__cached(const char *sbuild_id) bool build_id_cache__cached(const char *sbuild_id)
...@@ -743,7 +756,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine) ...@@ -743,7 +756,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine)
name = nm; name = nm;
} }
return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
is_kallsyms, is_vdso); dso->nsinfo, is_kallsyms, is_vdso);
} }
static int __dsos__cache_build_ids(struct list_head *head, static int __dsos__cache_build_ids(struct list_head *head,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1) #define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)
#include "tool.h" #include "tool.h"
#include "namespaces.h"
#include <linux/types.h> #include <linux/types.h>
extern struct perf_tool build_id__mark_dso_hit_ops; extern struct perf_tool build_id__mark_dso_hit_ops;
...@@ -31,17 +32,19 @@ int perf_session__cache_build_ids(struct perf_session *session); ...@@ -31,17 +32,19 @@ int perf_session__cache_build_ids(struct perf_session *session);
char *build_id_cache__origname(const char *sbuild_id); char *build_id_cache__origname(const char *sbuild_id);
char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
char *build_id_cache__cachedir(const char *sbuild_id, const char *name, char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso); struct nsinfo *nsi, bool is_kallsyms,
bool is_vdso);
struct strlist; struct strlist;
struct strlist *build_id_cache__list_all(bool validonly); struct strlist *build_id_cache__list_all(bool validonly);
char *build_id_cache__complement(const char *incomplete_sbuild_id); char *build_id_cache__complement(const char *incomplete_sbuild_id);
int build_id_cache__list_build_ids(const char *pathname, int build_id_cache__list_build_ids(const char *pathname, struct nsinfo *nsi,
struct strlist **result); struct strlist **result);
bool build_id_cache__cached(const char *sbuild_id); bool build_id_cache__cached(const char *sbuild_id);
int build_id_cache__add_s(const char *sbuild_id, int build_id_cache__add_s(const char *sbuild_id,
const char *name, bool is_kallsyms, bool is_vdso); const char *name, struct nsinfo *nsi,
bool is_kallsyms, bool is_vdso);
int build_id_cache__remove_s(const char *sbuild_id); int build_id_cache__remove_s(const char *sbuild_id);
extern char buildid_dir[]; extern char buildid_dir[];
......
...@@ -504,7 +504,14 @@ static void check_data_close(void); ...@@ -504,7 +504,14 @@ static void check_data_close(void);
*/ */
static int open_dso(struct dso *dso, struct machine *machine) static int open_dso(struct dso *dso, struct machine *machine)
{ {
int fd = __open_dso(dso, machine); int fd;
struct nscookie nsc;
if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
nsinfo__mountns_enter(dso->nsinfo, &nsc);
fd = __open_dso(dso, machine);
if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
nsinfo__mountns_exit(&nsc);
if (fd >= 0) { if (fd >= 0) {
dso__list_add(dso); dso__list_add(dso);
...@@ -1302,6 +1309,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) ...@@ -1302,6 +1309,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
{ {
bool have_build_id = false; bool have_build_id = false;
struct dso *pos; struct dso *pos;
struct nscookie nsc;
list_for_each_entry(pos, head, node) { list_for_each_entry(pos, head, node) {
if (with_hits && !pos->hit && !dso__is_vdso(pos)) if (with_hits && !pos->hit && !dso__is_vdso(pos))
...@@ -1310,11 +1318,13 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) ...@@ -1310,11 +1318,13 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
have_build_id = true; have_build_id = true;
continue; continue;
} }
nsinfo__mountns_enter(pos->nsinfo, &nsc);
if (filename__read_build_id(pos->long_name, pos->build_id, if (filename__read_build_id(pos->long_name, pos->build_id,
sizeof(pos->build_id)) > 0) { sizeof(pos->build_id)) > 0) {
have_build_id = true; have_build_id = true;
pos->has_build_id = true; pos->has_build_id = true;
} }
nsinfo__mountns_exit(&nsc);
} }
return have_build_id; return have_build_id;
......
...@@ -2124,7 +2124,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob, ...@@ -2124,7 +2124,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,
return; return;
} }
strlist__for_each_entry(nd, bidlist) { strlist__for_each_entry(nd, bidlist) {
pcache = probe_cache__new(nd->s); pcache = probe_cache__new(nd->s, NULL);
if (!pcache) if (!pcache)
continue; continue;
list_for_each_entry(ent, &pcache->entries, node) { list_for_each_entry(ent, &pcache->entries, node) {
......
...@@ -2769,7 +2769,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, ...@@ -2769,7 +2769,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
if (ret == -EINVAL && pev->uprobes) if (ret == -EINVAL && pev->uprobes)
warn_uprobe_event_compat(tev); warn_uprobe_event_compat(tev);
if (ret == 0 && probe_conf.cache) { if (ret == 0 && probe_conf.cache) {
cache = probe_cache__new(pev->target); cache = probe_cache__new(pev->target, pev->nsi);
if (!cache || if (!cache ||
probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 || probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 ||
probe_cache__commit(cache) < 0) probe_cache__commit(cache) < 0)
...@@ -3119,7 +3119,7 @@ static int find_cached_events(struct perf_probe_event *pev, ...@@ -3119,7 +3119,7 @@ static int find_cached_events(struct perf_probe_event *pev,
int ntevs = 0; int ntevs = 0;
int ret = 0; int ret = 0;
cache = probe_cache__new(target); cache = probe_cache__new(target, pev->nsi);
/* Return 0 ("not found") if the target has no probe cache. */ /* Return 0 ("not found") if the target has no probe cache. */
if (!cache) if (!cache)
return 0; return 0;
...@@ -3209,7 +3209,7 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, ...@@ -3209,7 +3209,7 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
else else
return find_cached_events(pev, tevs, pev->target); return find_cached_events(pev, tevs, pev->target);
} }
cache = probe_cache__new(pev->target); cache = probe_cache__new(pev->target, pev->nsi);
if (!cache) if (!cache)
return 0; return 0;
......
...@@ -412,13 +412,15 @@ int probe_cache_entry__get_event(struct probe_cache_entry *entry, ...@@ -412,13 +412,15 @@ int probe_cache_entry__get_event(struct probe_cache_entry *entry,
} }
/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
static int probe_cache__open(struct probe_cache *pcache, const char *target) static int probe_cache__open(struct probe_cache *pcache, const char *target,
struct nsinfo *nsi)
{ {
char cpath[PATH_MAX]; char cpath[PATH_MAX];
char sbuildid[SBUILD_ID_SIZE]; char sbuildid[SBUILD_ID_SIZE];
char *dir_name = NULL; char *dir_name = NULL;
bool is_kallsyms = false; bool is_kallsyms = false;
int ret, fd; int ret, fd;
struct nscookie nsc;
if (target && build_id_cache__cached(target)) { if (target && build_id_cache__cached(target)) {
/* This is a cached buildid */ /* This is a cached buildid */
...@@ -431,8 +433,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) ...@@ -431,8 +433,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
target = DSO__NAME_KALLSYMS; target = DSO__NAME_KALLSYMS;
is_kallsyms = true; is_kallsyms = true;
ret = sysfs__sprintf_build_id("/", sbuildid); ret = sysfs__sprintf_build_id("/", sbuildid);
} else } else {
nsinfo__mountns_enter(nsi, &nsc);
ret = filename__sprintf_build_id(target, sbuildid); ret = filename__sprintf_build_id(target, sbuildid);
nsinfo__mountns_exit(&nsc);
}
if (ret < 0) { if (ret < 0) {
pr_debug("Failed to get build-id from %s.\n", target); pr_debug("Failed to get build-id from %s.\n", target);
...@@ -441,7 +446,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) ...@@ -441,7 +446,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
/* If we have no buildid cache, make it */ /* If we have no buildid cache, make it */
if (!build_id_cache__cached(sbuildid)) { if (!build_id_cache__cached(sbuildid)) {
ret = build_id_cache__add_s(sbuildid, target, ret = build_id_cache__add_s(sbuildid, target, nsi,
is_kallsyms, NULL); is_kallsyms, NULL);
if (ret < 0) { if (ret < 0) {
pr_debug("Failed to add build-id cache: %s\n", target); pr_debug("Failed to add build-id cache: %s\n", target);
...@@ -449,7 +454,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) ...@@ -449,7 +454,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
} }
} }
dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,
false); false);
found: found:
if (!dir_name) { if (!dir_name) {
...@@ -554,7 +559,7 @@ void probe_cache__delete(struct probe_cache *pcache) ...@@ -554,7 +559,7 @@ void probe_cache__delete(struct probe_cache *pcache)
free(pcache); free(pcache);
} }
struct probe_cache *probe_cache__new(const char *target) struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)
{ {
struct probe_cache *pcache = probe_cache__alloc(); struct probe_cache *pcache = probe_cache__alloc();
int ret; int ret;
...@@ -562,7 +567,7 @@ struct probe_cache *probe_cache__new(const char *target) ...@@ -562,7 +567,7 @@ struct probe_cache *probe_cache__new(const char *target)
if (!pcache) if (!pcache)
return NULL; return NULL;
ret = probe_cache__open(pcache, target); ret = probe_cache__open(pcache, target, nsi);
if (ret < 0) { if (ret < 0) {
pr_debug("Cache open error: %d\n", ret); pr_debug("Cache open error: %d\n", ret);
goto out_err; goto out_err;
...@@ -974,7 +979,7 @@ int probe_cache__show_all_caches(struct strfilter *filter) ...@@ -974,7 +979,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)
return -EINVAL; return -EINVAL;
} }
strlist__for_each_entry(nd, bidlist) { strlist__for_each_entry(nd, bidlist) {
pcache = probe_cache__new(nd->s); pcache = probe_cache__new(nd->s, NULL);
if (!pcache) if (!pcache)
continue; continue;
if (!list_empty(&pcache->entries)) { if (!list_empty(&pcache->entries)) {
......
...@@ -51,7 +51,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist); ...@@ -51,7 +51,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist);
int probe_cache_entry__get_event(struct probe_cache_entry *entry, int probe_cache_entry__get_event(struct probe_cache_entry *entry,
struct probe_trace_event **tevs); struct probe_trace_event **tevs);
struct probe_cache *probe_cache__new(const char *target); struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi);
int probe_cache__add_entry(struct probe_cache *pcache, int probe_cache__add_entry(struct probe_cache *pcache,
struct perf_probe_event *pev, struct perf_probe_event *pev,
struct probe_trace_event *tevs, int ntevs); struct probe_trace_event *tevs, int ntevs);
...@@ -69,7 +69,7 @@ int probe_cache__show_all_caches(struct strfilter *filter); ...@@ -69,7 +69,7 @@ int probe_cache__show_all_caches(struct strfilter *filter);
bool probe_type_is_available(enum probe_type type); bool probe_type_is_available(enum probe_type type);
bool kretprobe_offset_is_supported(void); bool kretprobe_offset_is_supported(void);
#else /* ! HAVE_LIBELF_SUPPORT */ #else /* ! HAVE_LIBELF_SUPPORT */
static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused)
{ {
return NULL; return NULL;
} }
......
...@@ -10,6 +10,7 @@ util/ctype.c ...@@ -10,6 +10,7 @@ util/ctype.c
util/evlist.c util/evlist.c
util/evsel.c util/evsel.c
util/cpumap.c util/cpumap.c
util/namespaces.c
../lib/bitmap.c ../lib/bitmap.c
../lib/find_bit.c ../lib/find_bit.c
../lib/hweight.c ../lib/hweight.c
......
...@@ -1464,7 +1464,6 @@ static int dso__find_perf_map(char *filebuf, size_t bufsz, ...@@ -1464,7 +1464,6 @@ static int dso__find_perf_map(char *filebuf, size_t bufsz,
return rc; return rc;
} }
int dso__load(struct dso *dso, struct map *map) int dso__load(struct dso *dso, struct map *map)
{ {
char *name; char *name;
...@@ -1565,6 +1564,8 @@ int dso__load(struct dso *dso, struct map *map) ...@@ -1565,6 +1564,8 @@ int dso__load(struct dso *dso, struct map *map)
for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
struct symsrc *ss = &ss_[ss_pos]; struct symsrc *ss = &ss_[ss_pos];
bool next_slot = false; bool next_slot = false;
bool is_reg;
int sirc;
enum dso_binary_type symtab_type = binary_type_symtab[i]; enum dso_binary_type symtab_type = binary_type_symtab[i];
...@@ -1575,12 +1576,20 @@ int dso__load(struct dso *dso, struct map *map) ...@@ -1575,12 +1576,20 @@ int dso__load(struct dso *dso, struct map *map)
root_dir, name, PATH_MAX)) root_dir, name, PATH_MAX))
continue; continue;
if (!is_regular_file(name)) if (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
continue; nsinfo__mountns_exit(&nsc);
is_reg = is_regular_file(name);
sirc = symsrc__init(ss, dso, name, symtab_type);
/* Name is now the name of the next image to try */ if (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
if (symsrc__init(ss, dso, name, symtab_type) < 0) nsinfo__mountns_enter(dso->nsinfo, &nsc);
if (!is_reg || sirc < 0) {
if (sirc >= 0)
symsrc__destroy(ss);
continue; continue;
}
if (!syms_ss && symsrc__has_symtab(ss)) { if (!syms_ss && symsrc__has_symtab(ss)) {
syms_ss = ss; syms_ss = ss;
......
...@@ -143,13 +143,17 @@ struct strlist *lsdir(const char *name, ...@@ -143,13 +143,17 @@ struct strlist *lsdir(const char *name,
return list; return list;
} }
static int slow_copyfile(const char *from, const char *to) static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi)
{ {
int err = -1; int err = -1;
char *line = NULL; char *line = NULL;
size_t n; size_t n;
FILE *from_fp = fopen(from, "r"), *to_fp; FILE *from_fp, *to_fp;
struct nscookie nsc;
nsinfo__mountns_enter(nsi, &nsc);
from_fp = fopen(from, "r");
nsinfo__mountns_exit(&nsc);
if (from_fp == NULL) if (from_fp == NULL)
goto out; goto out;
...@@ -198,15 +202,21 @@ int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) ...@@ -198,15 +202,21 @@ int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
return size ? -1 : 0; return size ? -1 : 0;
} }
int copyfile_mode(const char *from, const char *to, mode_t mode) static int copyfile_mode_ns(const char *from, const char *to, mode_t mode,
struct nsinfo *nsi)
{ {
int fromfd, tofd; int fromfd, tofd;
struct stat st; struct stat st;
int err = -1; int err;
char *tmp = NULL, *ptr = NULL; char *tmp = NULL, *ptr = NULL;
struct nscookie nsc;
if (stat(from, &st)) nsinfo__mountns_enter(nsi, &nsc);
err = stat(from, &st);
nsinfo__mountns_exit(&nsc);
if (err)
goto out; goto out;
err = -1;
/* extra 'x' at the end is to reserve space for '.' */ /* extra 'x' at the end is to reserve space for '.' */
if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) {
...@@ -227,11 +237,13 @@ int copyfile_mode(const char *from, const char *to, mode_t mode) ...@@ -227,11 +237,13 @@ int copyfile_mode(const char *from, const char *to, mode_t mode)
goto out_close_to; goto out_close_to;
if (st.st_size == 0) { /* /proc? do it slowly... */ if (st.st_size == 0) { /* /proc? do it slowly... */
err = slow_copyfile(from, tmp); err = slow_copyfile(from, tmp, nsi);
goto out_close_to; goto out_close_to;
} }
nsinfo__mountns_enter(nsi, &nsc);
fromfd = open(from, O_RDONLY); fromfd = open(from, O_RDONLY);
nsinfo__mountns_exit(&nsc);
if (fromfd < 0) if (fromfd < 0)
goto out_close_to; goto out_close_to;
...@@ -248,6 +260,16 @@ int copyfile_mode(const char *from, const char *to, mode_t mode) ...@@ -248,6 +260,16 @@ int copyfile_mode(const char *from, const char *to, mode_t mode)
return err; return err;
} }
int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi)
{
return copyfile_mode_ns(from, to, 0755, nsi);
}
int copyfile_mode(const char *from, const char *to, mode_t mode)
{
return copyfile_mode_ns(from, to, mode, NULL);
}
int copyfile(const char *from, const char *to) int copyfile(const char *from, const char *to)
{ {
return copyfile_mode(from, to, 0755); return copyfile_mode(from, to, 0755);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include "namespaces.h"
/* General helper functions */ /* General helper functions */
void usage(const char *err) __noreturn; void usage(const char *err) __noreturn;
...@@ -33,6 +34,7 @@ struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dire ...@@ -33,6 +34,7 @@ struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dire
bool lsdir_no_dot_filter(const char *name, struct dirent *d); bool lsdir_no_dot_filter(const char *name, struct dirent *d);
int copyfile(const char *from, const char *to); int copyfile(const char *from, const char *to);
int copyfile_mode(const char *from, const char *to, mode_t mode); int copyfile_mode(const char *from, const char *to, mode_t mode);
int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);
int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size);
ssize_t readn(int fd, void *buf, size_t n); ssize_t readn(int fd, void *buf, size_t n);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment