1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 #include "namespaces.h"
9 #include "get_current_dir_name.h"
10 #include <sys/types.h>
20 #include <linux/kernel.h>
21 #include <linux/zalloc.h>
23 static const char *perf_ns__names
[] = {
24 [NET_NS_INDEX
] = "net",
25 [UTS_NS_INDEX
] = "uts",
26 [IPC_NS_INDEX
] = "ipc",
27 [PID_NS_INDEX
] = "pid",
28 [USER_NS_INDEX
] = "user",
29 [MNT_NS_INDEX
] = "mnt",
30 [CGROUP_NS_INDEX
] = "cgroup",
33 const char *perf_ns__name(unsigned int id
)
35 if (id
>= ARRAY_SIZE(perf_ns__names
))
37 return perf_ns__names
[id
];
40 struct namespaces
*namespaces__new(struct perf_record_namespaces
*event
)
42 struct namespaces
*namespaces
;
43 u64 link_info_size
= ((event
? event
->nr_namespaces
: NR_NAMESPACES
) *
44 sizeof(struct perf_ns_link_info
));
46 namespaces
= zalloc(sizeof(struct namespaces
) + link_info_size
);
50 namespaces
->end_time
= -1;
53 memcpy(namespaces
->link_info
, event
->link_info
, link_info_size
);
58 void namespaces__free(struct namespaces
*namespaces
)
63 int nsinfo__init(struct nsinfo
*nsi
)
75 if (snprintf(oldns
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
78 if (asprintf(&newns
, "/proc/%d/ns/mnt", nsi
->pid
) == -1)
81 if (stat(oldns
, &old_stat
) < 0)
84 if (stat(newns
, &new_stat
) < 0)
87 /* Check if the mount namespaces differ, if so then indicate that we
88 * want to switch as part of looking up dso/map data.
90 if (old_stat
.st_ino
!= new_stat
.st_ino
) {
91 nsi
->need_setns
= true;
92 nsi
->mntns_path
= newns
;
96 /* If we're dealing with a process that is in a different PID namespace,
97 * attempt to work out the innermost tgid for the process.
99 if (snprintf(spath
, PATH_MAX
, "/proc/%d/status", nsi
->pid
) >= PATH_MAX
)
102 f
= fopen(spath
, "r");
106 while (getline(&statln
, &linesz
, f
) != -1) {
107 /* Use tgid if CONFIG_PID_NS is not defined. */
108 if (strstr(statln
, "Tgid:") != NULL
) {
109 nsi
->tgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
111 nsi
->nstgid
= nsi
->tgid
;
114 if (strstr(statln
, "NStgid:") != NULL
) {
115 nsi
->nstgid
= (pid_t
)strtol(strrchr(statln
, '\t'),
130 struct nsinfo
*nsinfo__new(pid_t pid
)
137 nsi
= calloc(1, sizeof(*nsi
));
142 nsi
->need_setns
= false;
143 /* Init may fail if the process exits while we're trying to look
144 * at its proc information. In that case, save the pid but
145 * don't try to enter the namespace.
147 if (nsinfo__init(nsi
) == -1)
148 nsi
->need_setns
= false;
150 refcount_set(&nsi
->refcnt
, 1);
156 struct nsinfo
*nsinfo__copy(struct nsinfo
*nsi
)
163 nnsi
= calloc(1, sizeof(*nnsi
));
165 nnsi
->pid
= nsi
->pid
;
166 nnsi
->tgid
= nsi
->tgid
;
167 nnsi
->nstgid
= nsi
->nstgid
;
168 nnsi
->need_setns
= nsi
->need_setns
;
169 if (nsi
->mntns_path
) {
170 nnsi
->mntns_path
= strdup(nsi
->mntns_path
);
171 if (!nnsi
->mntns_path
) {
176 refcount_set(&nnsi
->refcnt
, 1);
182 void nsinfo__delete(struct nsinfo
*nsi
)
184 zfree(&nsi
->mntns_path
);
188 struct nsinfo
*nsinfo__get(struct nsinfo
*nsi
)
191 refcount_inc(&nsi
->refcnt
);
195 void nsinfo__put(struct nsinfo
*nsi
)
197 if (nsi
&& refcount_dec_and_test(&nsi
->refcnt
))
201 void nsinfo__mountns_enter(struct nsinfo
*nsi
,
204 char curpath
[PATH_MAX
];
215 if (!nsi
|| !nsi
->need_setns
)
218 if (snprintf(curpath
, PATH_MAX
, "/proc/self/ns/mnt") >= PATH_MAX
)
221 oldcwd
= get_current_dir_name();
225 oldns
= open(curpath
, O_RDONLY
);
229 newns
= open(nsi
->mntns_path
, O_RDONLY
);
233 if (setns(newns
, CLONE_NEWNS
) < 0)
249 void nsinfo__mountns_exit(struct nscookie
*nc
)
251 if (nc
== NULL
|| nc
->oldns
== -1 || nc
->newns
== -1 || !nc
->oldcwd
)
254 setns(nc
->oldns
, CLONE_NEWNS
);
257 WARN_ON_ONCE(chdir(nc
->oldcwd
));
261 if (nc
->oldns
> -1) {
266 if (nc
->newns
> -1) {
272 char *nsinfo__realpath(const char *path
, struct nsinfo
*nsi
)
277 nsinfo__mountns_enter(nsi
, &nsc
);
278 rpath
= realpath(path
, NULL
);
279 nsinfo__mountns_exit(&nsc
);