aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/namespaces.c
diff options
context:
space:
mode:
authorKrister Johansen <kjlx@templeofstupid.com>2017-07-05 21:48:08 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2017-07-18 22:14:09 -0400
commit843ff37bb59edbe51d64e77ba1b3245a15a4dd9f (patch)
tree7c1e50cb4b60af9776364ec65118c9a0db0cbcdf /tools/perf/util/namespaces.c
parent86bcdb5a43997bb02ba25a76482c7bfc652ba45b (diff)
perf symbols: Find symbols in different mount namespace
Teach perf how to resolve symbols from binaries that are in a different mount namespace from the tool. This allows perf to generate meaningful stack traces even if the binary resides in a different mount namespace from the tool. 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-2-git-send-email-kjlx@templeofstupid.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/namespaces.c')
-rw-r--r--tools/perf/util/namespaces.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
index 67dcbcc73c7d..bcc6bb19cf10 100644
--- a/tools/perf/util/namespaces.c
+++ b/tools/perf/util/namespaces.c
@@ -9,9 +9,13 @@
9#include "namespaces.h" 9#include "namespaces.h"
10#include "util.h" 10#include "util.h"
11#include "event.h" 11#include "event.h"
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <sched.h>
12#include <stdlib.h> 15#include <stdlib.h>
13#include <stdio.h> 16#include <stdio.h>
14#include <string.h> 17#include <string.h>
18#include <unistd.h>
15 19
16struct namespaces *namespaces__new(struct namespaces_event *event) 20struct namespaces *namespaces__new(struct namespaces_event *event)
17{ 21{
@@ -35,3 +39,126 @@ void namespaces__free(struct namespaces *namespaces)
35{ 39{
36 free(namespaces); 40 free(namespaces);
37} 41}
42
43void nsinfo__init(struct nsinfo *nsi)
44{
45 char oldns[PATH_MAX];
46 char *newns = NULL;
47 struct stat old_stat;
48 struct stat new_stat;
49
50 if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
51 return;
52
53 if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
54 return;
55
56 if (stat(oldns, &old_stat) < 0)
57 goto out;
58
59 if (stat(newns, &new_stat) < 0)
60 goto out;
61
62 /* Check if the mount namespaces differ, if so then indicate that we
63 * want to switch as part of looking up dso/map data.
64 */
65 if (old_stat.st_ino != new_stat.st_ino) {
66 nsi->need_setns = true;
67 nsi->mntns_path = newns;
68 newns = NULL;
69 }
70
71out:
72 free(newns);
73}
74
75struct nsinfo *nsinfo__new(pid_t pid)
76{
77 struct nsinfo *nsi = calloc(1, sizeof(*nsi));
78
79 if (nsi != NULL) {
80 nsi->pid = pid;
81 nsi->need_setns = false;
82 nsinfo__init(nsi);
83 refcount_set(&nsi->refcnt, 1);
84 }
85
86 return nsi;
87}
88
89void nsinfo__delete(struct nsinfo *nsi)
90{
91 zfree(&nsi->mntns_path);
92 free(nsi);
93}
94
95struct nsinfo *nsinfo__get(struct nsinfo *nsi)
96{
97 if (nsi)
98 refcount_inc(&nsi->refcnt);
99 return nsi;
100}
101
102void nsinfo__put(struct nsinfo *nsi)
103{
104 if (nsi && refcount_dec_and_test(&nsi->refcnt))
105 nsinfo__delete(nsi);
106}
107
108void nsinfo__mountns_enter(struct nsinfo *nsi, struct nscookie *nc)
109{
110 char curpath[PATH_MAX];
111 int oldns = -1;
112 int newns = -1;
113
114 if (nc == NULL)
115 return;
116
117 nc->oldns = -1;
118 nc->newns = -1;
119
120 if (!nsi || !nsi->need_setns)
121 return;
122
123 if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
124 return;
125
126 oldns = open(curpath, O_RDONLY);
127 if (oldns < 0)
128 return;
129
130 newns = open(nsi->mntns_path, O_RDONLY);
131 if (newns < 0)
132 goto errout;
133
134 if (setns(newns, CLONE_NEWNS) < 0)
135 goto errout;
136
137 nc->oldns = oldns;
138 nc->newns = newns;
139 return;
140
141errout:
142 if (oldns > -1)
143 close(oldns);
144 if (newns > -1)
145 close(newns);
146}
147
148void nsinfo__mountns_exit(struct nscookie *nc)
149{
150 if (nc == NULL || nc->oldns == -1 || nc->newns == -1)
151 return;
152
153 setns(nc->oldns, CLONE_NEWNS);
154
155 if (nc->oldns > -1) {
156 close(nc->oldns);
157 nc->oldns = -1;
158 }
159
160 if (nc->newns > -1) {
161 close(nc->newns);
162 nc->newns = -1;
163 }
164}