Skip to content

Commit bf2e710

Browse files
kmjohansenacmel
authored andcommitted
perf maps: Lookup maps in both intitial mountns and inner mountns.
If a process is in a mountns and has symbols in /tmp/perf-<pid>.map, look first in the namespace using the tgid for the pidns that the process might be in. If the map isn't found there, try looking in the mountns where perf is running, and use the tgid that's appropriate for perf's pid namespace. If all else fails, use the original pid. This allows us to locate a symbol map file in the mount namespace, if it was generated there. However, we also try the tool's /tmp in case it's there instead. Signed-off-by: Krister Johansen <kjlx@templeofstupid.com> Tested-by: Brendan 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-3-git-send-email-kjlx@templeofstupid.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 843ff37 commit bf2e710

File tree

6 files changed

+160
-27
lines changed

6 files changed

+160
-27
lines changed

tools/perf/util/machine.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ int machine__process_mmap2_event(struct machine *machine,
13921392

13931393
map = map__new(machine, event->mmap2.start,
13941394
event->mmap2.len, event->mmap2.pgoff,
1395-
event->mmap2.pid, event->mmap2.maj,
1395+
event->mmap2.maj,
13961396
event->mmap2.min, event->mmap2.ino,
13971397
event->mmap2.ino_generation,
13981398
event->mmap2.prot,
@@ -1450,7 +1450,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
14501450

14511451
map = map__new(machine, event->mmap.start,
14521452
event->mmap.len, event->mmap.pgoff,
1453-
event->mmap.pid, 0, 0, 0, 0, 0, 0,
1453+
0, 0, 0, 0, 0, 0,
14541454
event->mmap.filename,
14551455
type, thread);
14561456

tools/perf/util/map.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,13 @@ void map__init(struct map *map, enum map_type type,
146146
}
147147

148148
struct map *map__new(struct machine *machine, u64 start, u64 len,
149-
u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
149+
u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
150150
u64 ino_gen, u32 prot, u32 flags, char *filename,
151151
enum map_type type, struct thread *thread)
152152
{
153153
struct map *map = malloc(sizeof(*map));
154+
struct nsinfo *nsi = NULL;
155+
struct nsinfo *nnsi;
154156

155157
if (map != NULL) {
156158
char newfilename[PATH_MAX];
@@ -168,9 +170,11 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
168170
map->ino_generation = ino_gen;
169171
map->prot = prot;
170172
map->flags = flags;
173+
nsi = nsinfo__get(thread->nsinfo);
171174

172-
if ((anon || no_dso) && type == MAP__FUNCTION) {
173-
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
175+
if ((anon || no_dso) && nsi && type == MAP__FUNCTION) {
176+
snprintf(newfilename, sizeof(newfilename),
177+
"/tmp/perf-%d.map", nsi->pid);
174178
filename = newfilename;
175179
}
176180

@@ -180,6 +184,16 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
180184
}
181185

182186
if (vdso) {
187+
/* The vdso maps are always on the host and not the
188+
* container. Ensure that we don't use setns to look
189+
* them up.
190+
*/
191+
nnsi = nsinfo__copy(nsi);
192+
if (nnsi) {
193+
nsinfo__put(nsi);
194+
nnsi->need_setns = false;
195+
nsi = nnsi;
196+
}
183197
pgoff = 0;
184198
dso = machine__findnew_vdso(machine, thread);
185199
} else
@@ -201,11 +215,12 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
201215
if (type != MAP__FUNCTION)
202216
dso__set_loaded(dso, map->type);
203217
}
204-
dso->nsinfo = nsinfo__get(thread->nsinfo);
218+
dso->nsinfo = nsi;
205219
dso__put(dso);
206220
}
207221
return map;
208222
out_delete:
223+
nsinfo__put(nsi);
209224
free(map);
210225
return NULL;
211226
}

tools/perf/util/map.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ struct thread;
141141
void map__init(struct map *map, enum map_type type,
142142
u64 start, u64 end, u64 pgoff, struct dso *dso);
143143
struct map *map__new(struct machine *machine, u64 start, u64 len,
144-
u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
144+
u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
145145
u64 ino_gen, u32 prot, u32 flags,
146146
char *filename, enum map_type type, struct thread *thread);
147147
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);

tools/perf/util/namespaces.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,23 @@ void namespaces__free(struct namespaces *namespaces)
4040
free(namespaces);
4141
}
4242

43-
void nsinfo__init(struct nsinfo *nsi)
43+
int nsinfo__init(struct nsinfo *nsi)
4444
{
4545
char oldns[PATH_MAX];
46+
char spath[PATH_MAX];
4647
char *newns = NULL;
48+
char *statln = NULL;
4749
struct stat old_stat;
4850
struct stat new_stat;
51+
FILE *f = NULL;
52+
size_t linesz = 0;
53+
int rv = -1;
4954

5055
if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
51-
return;
56+
return rv;
5257

5358
if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
54-
return;
59+
return rv;
5560

5661
if (stat(oldns, &old_stat) < 0)
5762
goto out;
@@ -68,24 +73,89 @@ void nsinfo__init(struct nsinfo *nsi)
6873
newns = NULL;
6974
}
7075

76+
/* If we're dealing with a process that is in a different PID namespace,
77+
* attempt to work out the innermost tgid for the process.
78+
*/
79+
if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
80+
goto out;
81+
82+
f = fopen(spath, "r");
83+
if (f == NULL)
84+
goto out;
85+
86+
while (getline(&statln, &linesz, f) != -1) {
87+
/* Use tgid if CONFIG_PID_NS is not defined. */
88+
if (strstr(statln, "Tgid:") != NULL) {
89+
nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
90+
NULL, 10);
91+
nsi->nstgid = nsi->tgid;
92+
}
93+
94+
if (strstr(statln, "NStgid:") != NULL) {
95+
nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
96+
NULL, 10);
97+
break;
98+
}
99+
}
100+
rv = 0;
101+
71102
out:
103+
if (f != NULL)
104+
(void) fclose(f);
105+
free(statln);
72106
free(newns);
107+
return rv;
73108
}
74109

75110
struct nsinfo *nsinfo__new(pid_t pid)
76111
{
77-
struct nsinfo *nsi = calloc(1, sizeof(*nsi));
112+
struct nsinfo *nsi;
78113

114+
if (pid == 0)
115+
return NULL;
116+
117+
nsi = calloc(1, sizeof(*nsi));
79118
if (nsi != NULL) {
80119
nsi->pid = pid;
120+
nsi->tgid = pid;
121+
nsi->nstgid = pid;
81122
nsi->need_setns = false;
82-
nsinfo__init(nsi);
123+
/* Init may fail if the process exits while we're trying to look
124+
* at its proc information. In that case, save the pid but
125+
* don't try to enter the namespace.
126+
*/
127+
if (nsinfo__init(nsi) == -1)
128+
nsi->need_setns = false;
129+
83130
refcount_set(&nsi->refcnt, 1);
84131
}
85132

86133
return nsi;
87134
}
88135

136+
struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
137+
{
138+
struct nsinfo *nnsi;
139+
140+
nnsi = calloc(1, sizeof(*nnsi));
141+
if (nnsi != NULL) {
142+
nnsi->pid = nsi->pid;
143+
nnsi->tgid = nsi->tgid;
144+
nnsi->nstgid = nsi->nstgid;
145+
nnsi->need_setns = nsi->need_setns;
146+
if (nsi->mntns_path) {
147+
nnsi->mntns_path = strdup(nsi->mntns_path);
148+
if (!nnsi->mntns_path) {
149+
free(nnsi);
150+
return NULL;
151+
}
152+
}
153+
refcount_set(&nnsi->refcnt, 1);
154+
}
155+
156+
return nnsi;
157+
}
158+
89159
void nsinfo__delete(struct nsinfo *nsi)
90160
{
91161
zfree(&nsi->mntns_path);
@@ -105,7 +175,8 @@ void nsinfo__put(struct nsinfo *nsi)
105175
nsinfo__delete(nsi);
106176
}
107177

108-
void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc)
178+
void nsinfo__mountns_enter(struct nsinfo *nsi,
179+
struct nscookie *nc)
109180
{
110181
char curpath[PATH_MAX];
111182
int oldns = -1;

tools/perf/util/namespaces.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ void namespaces__free(struct namespaces *namespaces);
2626

2727
struct nsinfo {
2828
pid_t pid;
29+
pid_t tgid;
30+
pid_t nstgid;
2931
bool need_setns;
3032
char *mntns_path;
3133
refcount_t refcnt;
@@ -36,8 +38,9 @@ struct nscookie {
3638
int newns;
3739
};
3840

39-
void nsinfo__init(struct nsinfo *nsi);
41+
int nsinfo__init(struct nsinfo *nsi);
4042
struct nsinfo *nsinfo__new(pid_t pid);
43+
struct nsinfo *nsinfo__copy(struct nsinfo *nsi);
4144
void nsinfo__delete(struct nsinfo *nsi);
4245

4346
struct nsinfo *nsinfo__get(struct nsinfo *nsi);

tools/perf/util/symbol.c

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "strlist.h"
2020
#include "intlist.h"
2121
#include "namespaces.h"
22-
#include "vdso.h"
2322
#include "header.h"
2423
#include "path.h"
2524
#include "sane_ctype.h"
@@ -1327,14 +1326,15 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
13271326
return __dso__load_kallsyms(dso, filename, map, false);
13281327
}
13291328

1330-
static int dso__load_perf_map(struct dso *dso, struct map *map)
1329+
static int dso__load_perf_map(const char *map_path, struct dso *dso,
1330+
struct map *map)
13311331
{
13321332
char *line = NULL;
13331333
size_t n;
13341334
FILE *file;
13351335
int nr_syms = 0;
13361336

1337-
file = fopen(dso->long_name, "r");
1337+
file = fopen(map_path, "r");
13381338
if (file == NULL)
13391339
goto out_failure;
13401340

@@ -1426,6 +1426,45 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
14261426
}
14271427
}
14281428

1429+
/* Checks for the existence of the perf-<pid>.map file in two different
1430+
* locations. First, if the process is a separate mount namespace, check in
1431+
* that namespace using the pid of the innermost pid namespace. If's not in a
1432+
* namespace, or the file can't be found there, try in the mount namespace of
1433+
* the tracing process using our view of its pid.
1434+
*/
1435+
static int dso__find_perf_map(char *filebuf, size_t bufsz,
1436+
struct nsinfo **nsip)
1437+
{
1438+
struct nscookie nsc;
1439+
struct nsinfo *nsi;
1440+
struct nsinfo *nnsi;
1441+
int rc = -1;
1442+
1443+
nsi = *nsip;
1444+
1445+
if (nsi->need_setns) {
1446+
snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid);
1447+
nsinfo__mountns_enter(nsi, &nsc);
1448+
rc = access(filebuf, R_OK);
1449+
nsinfo__mountns_exit(&nsc);
1450+
if (rc == 0)
1451+
return rc;
1452+
}
1453+
1454+
nnsi = nsinfo__copy(nsi);
1455+
if (nnsi) {
1456+
nsinfo__put(nsi);
1457+
1458+
nnsi->need_setns = false;
1459+
snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid);
1460+
*nsip = nnsi;
1461+
rc = 0;
1462+
}
1463+
1464+
return rc;
1465+
}
1466+
1467+
14291468
int dso__load(struct dso *dso, struct map *map)
14301469
{
14311470
char *name;
@@ -1437,18 +1476,23 @@ int dso__load(struct dso *dso, struct map *map)
14371476
struct symsrc ss_[2];
14381477
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
14391478
bool kmod;
1479+
bool perfmap;
14401480
unsigned char build_id[BUILD_ID_SIZE];
14411481
struct nscookie nsc;
1482+
char newmapname[PATH_MAX];
1483+
const char *map_path = dso->long_name;
1484+
1485+
perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0;
1486+
if (perfmap) {
1487+
if (dso->nsinfo && (dso__find_perf_map(newmapname,
1488+
sizeof(newmapname), &dso->nsinfo) == 0)) {
1489+
map_path = newmapname;
1490+
}
1491+
}
14421492

14431493
nsinfo__mountns_enter(dso->nsinfo, &nsc);
14441494
pthread_mutex_lock(&dso->lock);
14451495

1446-
/* The vdso files always live in the host container, so don't go looking
1447-
* for them in the container's mount namespace.
1448-
*/
1449-
if (dso__is_vdso(dso))
1450-
nsinfo__mountns_exit(&nsc);
1451-
14521496
/* check again under the dso->lock */
14531497
if (dso__loaded(dso, map->type)) {
14541498
ret = 1;
@@ -1471,19 +1515,19 @@ int dso__load(struct dso *dso, struct map *map)
14711515

14721516
dso->adjust_symbols = 0;
14731517

1474-
if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
1518+
if (perfmap) {
14751519
struct stat st;
14761520

1477-
if (lstat(dso->name, &st) < 0)
1521+
if (lstat(map_path, &st) < 0)
14781522
goto out;
14791523

14801524
if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
14811525
pr_warning("File %s not owned by current user or root, "
1482-
"ignoring it (use -f to override).\n", dso->name);
1526+
"ignoring it (use -f to override).\n", map_path);
14831527
goto out;
14841528
}
14851529

1486-
ret = dso__load_perf_map(dso, map);
1530+
ret = dso__load_perf_map(map_path, dso, map);
14871531
dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
14881532
DSO_BINARY_TYPE__NOT_FOUND;
14891533
goto out;

0 commit comments

Comments
 (0)