]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/cgroup.c
add missing template in Makefile
[mirror_lxc.git] / src / lxc / cgroup.c
CommitLineData
576f946d 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
27#include <errno.h>
28#include <mntent.h>
29#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/param.h>
35#include <sys/inotify.h>
36#include <netinet/in.h>
37#include <net/if.h>
38
e2bcd7db 39#include "error.h"
881450bb 40#include "config.h"
36eb9bde 41
36eb9bde 42#include <lxc/log.h>
00b3c2e2
CLG
43#include <lxc/cgroup.h>
44#include <lxc/start.h>
36eb9bde
CLG
45
46lxc_log_define(lxc_cgroup, lxc);
576f946d 47
5193cc3d 48#define MTAB "/proc/mounts"
576f946d 49
a6ddef61
MN
50static char nsgroup_path[MAXPATHLEN];
51
5193cc3d
DL
52enum {
53 CGROUP_NS_CGROUP = 1,
54 CGROUP_CLONE_CHILDREN,
55};
56
576f946d 57static int get_cgroup_mount(const char *mtab, char *mnt)
58{
59 struct mntent *mntent;
60 FILE *file = NULL;
61 int err = -1;
62
63 file = setmntent(mtab, "r");
64 if (!file) {
36eb9bde 65 SYSERROR("failed to open %s", mtab);
5193cc3d 66 return -1;
576f946d 67 }
68
69 while ((mntent = getmntent(file))) {
0d9f8e18
DL
70
71 /* there is a cgroup mounted named "lxc" */
72 if (!strcmp(mntent->mnt_fsname, "lxc") &&
73 !strcmp(mntent->mnt_type, "cgroup")) {
74 strcpy(mnt, mntent->mnt_dir);
75 err = 0;
76 break;
77 }
78
79 /* fallback to the first non-lxc cgroup found */
80 if (!strcmp(mntent->mnt_type, "cgroup") && err) {
81 strcpy(mnt, mntent->mnt_dir);
82 err = 0;
83 }
576f946d 84 };
85
1ac470c0
DL
86 DEBUG("using cgroup mounted at '%s'", mnt);
87
576f946d 88 fclose(file);
5193cc3d
DL
89
90 return err;
91}
92
93static int get_cgroup_flags(const char *mtab, int *flags)
94{
95 struct mntent *mntent;
96 FILE *file = NULL;
97 int err = -1;
98
99 file = setmntent(mtab, "r");
100 if (!file) {
101 SYSERROR("failed to open %s", mtab);
102 return -1;
103 }
104
105 *flags = 0;
106
107 while ((mntent = getmntent(file))) {
108
109 /* there is a cgroup mounted named "lxc" */
110 if (!strcmp(mntent->mnt_fsname, "lxc") &&
111 !strcmp(mntent->mnt_type, "cgroup")) {
112
113 if (hasmntopt(mntent, "ns"))
114 *flags |= CGROUP_NS_CGROUP;
115
116 if (hasmntopt(mntent, "clone_children"))
117 *flags |= CGROUP_CLONE_CHILDREN;
118
119 err = 0;
120 break;
121 }
122
123 /* fallback to the first non-lxc cgroup found */
124 if (!strcmp(mntent->mnt_type, "cgroup") && err) {
125
126 if (hasmntopt(mntent, "ns"))
127 *flags |= CGROUP_NS_CGROUP;
128
129 if (hasmntopt(mntent, "clone_children"))
130 *flags |= CGROUP_CLONE_CHILDREN;
131
132 err = 0;
133 }
134 };
135
136 DEBUG("cgroup flags is 0x%x", *flags);
137
138 fclose(file);
139
576f946d 140 return err;
141}
142
8edcba11 143static int cgroup_rename_nsgroup(const char *mnt, const char *name, pid_t pid)
6203de18
DL
144{
145 char oldname[MAXPATHLEN];
6203de18 146
ef342abb 147 snprintf(oldname, MAXPATHLEN, "%s/%d", mnt, pid);
6203de18 148
ef342abb
DL
149 if (rename(oldname, name)) {
150 SYSERROR("failed to rename cgroup %s->%s", oldname, name);
151 return -1;
0dd4566e
DL
152 }
153
ef342abb 154 DEBUG("'%s' renamed to '%s'", oldname, name);
758437c5 155
ef342abb 156 return 0;
6203de18
DL
157}
158
fd4f5a56
DL
159static int cgroup_enable_clone_children(const char *path)
160{
161 FILE *f;
162 int ret = 0;
163
164 f = fopen(path, "w");
165 if (!f) {
166 SYSERROR("failed to open '%s'", path);
167 return -1;
168 }
169
170 if (fprintf(f, "1") < 1) {
171 ERROR("failed to write flag to '%s'", path);
172 ret = -1;
173 }
174
175 fclose(f);
176
177 return ret;
178}
179
180static int cgroup_attach(const char *path, pid_t pid)
181{
182 FILE *f;
183 char tasks[MAXPATHLEN];
184 int ret = 0;
185
186 snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
187
188 f = fopen(tasks, "w");
189 if (!f) {
190 SYSERROR("failed to open '%s'", tasks);
191 return -1;
192 }
193
194 if (fprintf(f, "%d", pid) <= 0) {
195 SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
196 ret = -1;
197 }
198
199 fclose(f);
200
201 return ret;
202}
203
ef342abb 204int lxc_cgroup_create(const char *name, pid_t pid)
576f946d 205{
ef342abb
DL
206 char cgmnt[MAXPATHLEN];
207 char cgname[MAXPATHLEN];
fd4f5a56 208 char clonechild[MAXPATHLEN];
5193cc3d 209 int flags;
422afdd2 210
ef342abb 211 if (get_cgroup_mount(MTAB, cgmnt)) {
422afdd2
MN
212 ERROR("cgroup is not mounted");
213 return -1;
2b4e286d 214 }
4e2121f5 215
ef342abb 216 snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, name);
1ac470c0 217
ef342abb
DL
218 /*
219 * There is a previous cgroup, assume it is empty,
220 * otherwise that fails
221 */
222 if (!access(cgname, F_OK) && rmdir(cgname)) {
223 SYSERROR("failed to remove previous cgroup '%s'", cgname);
224 return -1;
225 }
576f946d 226
5193cc3d
DL
227 if (get_cgroup_flags(MTAB, &flags)) {
228 SYSERROR("failed to get cgroup flags");
229 return -1;
230 }
fd4f5a56 231
5193cc3d
DL
232 /* We have the deprecated ns_cgroup subsystem */
233 if (flags & CGROUP_NS_CGROUP) {
fd4f5a56 234 WARN("using deprecated ns_cgroup");
8edcba11 235 return cgroup_rename_nsgroup(cgmnt, cgname, pid);
fd4f5a56
DL
236 }
237
5193cc3d
DL
238 /* we check if the kernel has clone_children, at this point if there
239 * no clone_children neither ns_cgroup, that means the cgroup is mounted
240 * without the ns_cgroup and it has not the compatibility flag
241 */
242 if (access(clonechild, F_OK)) {
243 ERROR("no ns_cgroup option specified");
244 return -1;
245 }
246
247 snprintf(clonechild, MAXPATHLEN, "%s/cgroup.clone_children", cgmnt);
248
fd4f5a56
DL
249 /* we enable the clone_children flag of the cgroup */
250 if (cgroup_enable_clone_children(clonechild)) {
251 SYSERROR("failed to enable 'clone_children flag");
252 return -1;
253 }
254
255 /* Let's create the cgroup */
256 if (mkdir(cgname, 0700)) {
257 SYSERROR("failed to create '%s' directory", cgname);
258 return -1;
259 }
260
261 /* Let's add the pid to the 'tasks' file */
262 if (cgroup_attach(cgname, pid)) {
263 SYSERROR("failed to attach pid '%d' to '%s'", pid, cgname);
264 rmdir(cgname);
265 return -1;
266 }
267
268 return 0;
36b86299
DL
269}
270
271int lxc_cgroup_destroy(const char *name)
272{
ef342abb
DL
273 char cgmnt[MAXPATHLEN];
274 char cgname[MAXPATHLEN];
275
276 if (get_cgroup_mount(MTAB, cgmnt)) {
277 ERROR("cgroup is not mounted");
278 return -1;
279 }
280
281 snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, name);
429a84f4 282 if (rmdir(cgname)) {
ef342abb
DL
283 SYSERROR("failed to remove cgroup '%s'", cgname);
284 return -1;
285 }
286
287 DEBUG("'%s' unlinked", cgname);
288
289 return 0;
36b86299
DL
290}
291
14ad6bfd 292int lxc_cgroup_path_get(char **path, const char *name)
a6ddef61
MN
293{
294 char cgroup[MAXPATHLEN];
295
296 *path = &nsgroup_path[0];
297
298 /*
299 * report nsgroup_path string if already set
300 */
301 if (**path != 0)
302 return 0;
303
304 if (get_cgroup_mount(MTAB, cgroup)) {
305 ERROR("cgroup is not mounted");
306 return -1;
307 }
308
309 snprintf(nsgroup_path, MAXPATHLEN, "%s/%s", cgroup, name);
310 return 0;
311}
312
576f946d 313int lxc_cgroup_set(const char *name, const char *subsystem, const char *value)
314{
4eec6850 315 int fd, ret;
a6ddef61 316 char *nsgroup;
576f946d 317 char path[MAXPATHLEN];
318
a6ddef61
MN
319 ret = lxc_cgroup_path_get(&nsgroup, name);
320 if (ret)
321 return -1;
322
323 snprintf(path, MAXPATHLEN, "%s/%s", nsgroup, subsystem);
576f946d 324
325 fd = open(path, O_WRONLY);
8b92dc3a
MN
326 if (fd < 0) {
327 ERROR("open %s : %s", path, strerror(errno));
576f946d 328 return -1;
8b92dc3a 329 }
576f946d 330
4eec6850
MN
331 ret = write(fd, value, strlen(value));
332 if (ret < 0) {
8b92dc3a 333 ERROR("write %s : %s", path, strerror(errno));
576f946d 334 goto out;
8b92dc3a 335 }
576f946d 336
337 ret = 0;
338out:
339 close(fd);
340 return ret;
341}
342
343int lxc_cgroup_get(const char *name, const char *subsystem,
344 char *value, size_t len)
345{
8b92dc3a 346 int fd, ret = -1;
a6ddef61 347 char *nsgroup;
576f946d 348 char path[MAXPATHLEN];
349
a6ddef61
MN
350 ret = lxc_cgroup_path_get(&nsgroup, name);
351 if (ret)
352 return -1;
353
354 snprintf(path, MAXPATHLEN, "%s/%s", nsgroup, subsystem);
576f946d 355
356 fd = open(path, O_RDONLY);
8b92dc3a
MN
357 if (fd < 0) {
358 ERROR("open %s : %s", path, strerror(errno));
576f946d 359 return -1;
8b92dc3a 360 }
576f946d 361
70f7755e
DL
362 ret = read(fd, value, len);
363 if (ret < 0)
8b92dc3a 364 ERROR("read %s : %s", path, strerror(errno));
70f7755e 365
576f946d 366 close(fd);
367 return ret;
368}
e0f888d9
DL
369
370int lxc_cgroup_nrtasks(const char *name)
371{
372 char *nsgroup;
373 char path[MAXPATHLEN];
374 int pid, ret, count = 0;
375 FILE *file;
376
377 ret = lxc_cgroup_path_get(&nsgroup, name);
378 if (ret)
379 return -1;
380
381 snprintf(path, MAXPATHLEN, "%s/tasks", nsgroup);
382
383 file = fopen(path, "r");
384 if (!file) {
385 SYSERROR("fopen '%s' failed", path);
386 return -1;
387 }
388
389 while (fscanf(file, "%d", &pid) != EOF)
390 count++;
391
392 fclose(file);
393
394 return count;
395}