blob: bcc6bb19cf10087cf8182e8f3189ba425995beca [file] [log] [blame]
Hari Bathinif3b36142017-03-08 02:11:43 +05301/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 */
8
9#include "namespaces.h"
10#include "util.h"
11#include "event.h"
Krister Johansen843ff372017-07-05 18:48:08 -070012#include <sys/types.h>
13#include <sys/stat.h>
14#include <sched.h>
Hari Bathinif3b36142017-03-08 02:11:43 +053015#include <stdlib.h>
16#include <stdio.h>
Arnaldo Carvalho de Melo72f7c4d2017-04-19 19:06:30 -030017#include <string.h>
Krister Johansen843ff372017-07-05 18:48:08 -070018#include <unistd.h>
Hari Bathinif3b36142017-03-08 02:11:43 +053019
20struct namespaces *namespaces__new(struct namespaces_event *event)
21{
22 struct namespaces *namespaces;
23 u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
24 sizeof(struct perf_ns_link_info));
25
26 namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
27 if (!namespaces)
28 return NULL;
29
30 namespaces->end_time = -1;
31
32 if (event)
33 memcpy(namespaces->link_info, event->link_info, link_info_size);
34
35 return namespaces;
36}
37
38void namespaces__free(struct namespaces *namespaces)
39{
40 free(namespaces);
41}
Krister Johansen843ff372017-07-05 18:48:08 -070042
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}