2
* Copyright IBM Corporation. 2007
4
* Authors: Balbir Singh <balbir@linux.vnet.ibm.com>
5
* Dhaval Giani <dhaval@linux.vnet.ibm.com>
7
* This program is free software; you can redistribute it and/or modify it
8
* under the terms of version 2.1 of the GNU Lesser General Public License
9
* as published by the Free Software Foundation.
11
* This program is distributed in the hope that it would be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
* 1. Implement our own hashing scheme
17
* 2. Add namespace support
18
* 3. Add support for parsing cgroup filesystem and creating a
21
* Code initiated and designed by Balbir Singh. All faults are most likely
24
* Cleanup and changes to use the "official" structures and functions made
25
* by Dhaval Giani. All faults will still be Balbir's mistake :)
32
#include <libcgroup.h>
33
#include <libcgroup-internal.h>
43
#include <sys/mount.h>
45
#include <sys/types.h>
47
#define MAX_CGROUPS 1024
50
extern int yyparse(void);
53
* The basic global data structures.
55
* config_mount_table -> Where what controller is mounted
56
* table_index -> Where in the table are we.
57
* config_table_lock -> Serializing access to config_mount_table.
58
* cgroup_table -> Which cgroups have to be created.
59
* cgroup_table_index -> Where in the cgroup_table we are.
61
static struct cg_mount_table_s config_mount_table[CG_CONTROLLER_MAX];
62
static int config_table_index;
63
static pthread_rwlock_t config_table_lock = PTHREAD_RWLOCK_INITIALIZER;
64
static struct cgroup config_cgroup_table[MAX_CGROUPS];
65
int cgroup_table_index;
68
* Needed for the type while mounting cgroupfs.
70
static const char cgroup_filesystem[] = "cgroup";
73
* NOTE: All these functions return 1 on success
74
* and not 0 as is the library convention
78
* This call just sets the name of the cgroup. It will
79
* always be called in the end, because the parser will
82
int cgroup_config_insert_cgroup(char *cg_name)
84
struct cgroup *config_cgroup =
85
&config_cgroup_table[cgroup_table_index];
87
strncpy(config_cgroup->name, cg_name, FILENAME_MAX);
89
* Since this will be the last part to be parsed.
97
* This function sets the various controller's control
98
* files. It will always append values for cgroup_table_index
99
* entry in the cgroup_table. The index is incremented in
100
* cgroup_config_insert_cgroup
102
int cgroup_config_parse_controller_options(char *controller, char *name_value)
106
struct cgroup_controller *cgc;
108
struct cgroup *config_cgroup =
109
&config_cgroup_table[cgroup_table_index];
110
char *nm_pairs, *nv_buf;
112
cgroup_dbg("Adding controller %s, value %s\n", controller, name_value);
113
cgc = cgroup_add_controller(config_cgroup, controller);
119
* Did we just specify the controller to create the correct
120
* set of directories, without setting any values?
125
nm_pairs = strtok_r(name_value, ":", &nv_buf);
126
cgroup_dbg("[1] name value pair being processed is %s\n", nm_pairs);
128
name = strtok_r(nm_pairs, " ", &buffer);
133
value = strtok_r(NULL, " ", &buffer);
138
cgroup_dbg("name is %s, value is %s\n", name, value);
139
error = cgroup_add_value_string(cgc, name, value);
144
while ((nm_pairs = strtok_r(NULL, ":", &nv_buf))) {
145
cgroup_dbg("[2] name value pair being processed is %s\n",
147
name = strtok_r(nm_pairs, " ", &buffer);
152
value = strtok_r(NULL, " ", &buffer);
157
cgroup_dbg("name is %s, value is %s\n", name, value);
158
error = cgroup_add_value_string(cgc, name, value);
172
cgroup_delete_cgroup(config_cgroup, 1);
173
cgroup_table_index--;
178
* Sets the tasks file's uid and gid
180
int cgroup_config_group_task_perm(char *perm_type, char *value)
182
struct passwd *pw, *pw_buffer;
183
struct group *group, *group_buffer;
185
long val = atoi(value);
186
char buffer[CGROUP_BUFFER_LEN];
187
struct cgroup *config_cgroup =
188
&config_cgroup_table[cgroup_table_index];
190
if (!strcmp(perm_type, "uid")) {
192
pw = (struct passwd *) malloc(sizeof(struct passwd));
195
goto group_task_error;
197
error = getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN,
199
if (pw_buffer == NULL) {
201
goto group_task_error;
207
config_cgroup->tasks_uid = val;
210
if (!strcmp(perm_type, "gid")) {
212
group = (struct group *) malloc(sizeof(struct group));
215
goto group_task_error;
217
error = getgrnam_r(value, group, buffer,
218
CGROUP_BUFFER_LEN, &group_buffer);
220
if (group_buffer == NULL) {
222
goto group_task_error;
228
config_cgroup->tasks_gid = val;
238
cgroup_delete_cgroup(config_cgroup, 1);
239
cgroup_table_index--;
244
* Set the control file's uid/gid
246
int cgroup_config_group_admin_perm(char *perm_type, char *value)
248
struct passwd *pw, *pw_buffer;
249
struct group *group, *group_buffer;
251
struct cgroup *config_cgroup =
252
&config_cgroup_table[cgroup_table_index];
253
long val = atoi(value);
254
char buffer[CGROUP_BUFFER_LEN];
256
if (!strcmp(perm_type, "uid")) {
258
pw = (struct passwd *) malloc(sizeof(struct passwd));
263
error = getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN,
265
if (pw_buffer == NULL) {
273
config_cgroup->control_uid = val;
276
if (!strcmp(perm_type, "gid")) {
278
group = (struct group *) malloc(sizeof(struct group));
283
error = getgrnam_r(value, group, buffer,
284
CGROUP_BUFFER_LEN, &group_buffer);
286
if (group_buffer == NULL) {
294
config_cgroup->control_gid = val;
304
cgroup_delete_cgroup(config_cgroup, 1);
305
cgroup_table_index--;
310
* The moment we have found the controller's information
311
* insert it into the config_mount_table.
313
int cgroup_config_insert_into_mount_table(char *name, char *mount_point)
317
if (config_table_index >= CG_CONTROLLER_MAX)
320
pthread_rwlock_wrlock(&config_table_lock);
323
* Merge controller names with the same mount point
325
for (i = 0; i < config_table_index; i++) {
326
if (strcmp(config_mount_table[i].path, mount_point) == 0) {
327
char *cname = config_mount_table[i].name;
328
strncat(cname, ",", FILENAME_MAX - strlen(cname) - 1);
330
FILENAME_MAX - strlen(cname) - 1);
335
strcpy(config_mount_table[config_table_index].name, name);
336
strcpy(config_mount_table[config_table_index].path, mount_point);
337
config_table_index++;
339
pthread_rwlock_unlock(&config_table_lock);
346
* Cleanup all the data from the config_mount_table
348
void cgroup_config_cleanup_mount_table(void)
350
memset(&config_mount_table, 0,
351
sizeof(struct cg_mount_table_s) * CG_CONTROLLER_MAX);
355
* Start mounting the mount table.
357
int cgroup_config_mount_fs()
363
for (i = 0; i < config_table_index; i++) {
364
struct cg_mount_table_s *curr = &(config_mount_table[i]);
366
ret = stat(curr->path, &buff);
368
if (ret < 0 && errno != ENOENT) {
373
if (errno == ENOENT) {
374
ret = cg_mkdir_p(curr->path);
377
} else if (!S_ISDIR(buff.st_mode)) {
383
ret = mount(cgroup_filesystem, curr->path, cgroup_filesystem,
393
* Actually create the groups once the parsing has been finished.
395
int cgroup_config_create_groups()
400
for (i = 0; i < cgroup_table_index; i++) {
401
struct cgroup *cgroup = &config_cgroup_table[i];
402
error = cgroup_create_cgroup(cgroup, 0);
403
cgroup_dbg("creating group %s, error %d\n", cgroup->name,
412
* Destroy the cgroups
414
int cgroup_config_destroy_groups(void)
419
for (i = 0; i < cgroup_table_index; i++) {
420
struct cgroup *cgroup = &config_cgroup_table[i];
421
error = cgroup_delete_cgroup(cgroup, 0);
429
* Unmount the controllers
431
int cgroup_config_unmount_controllers(void)
436
for (i = 0; i < config_table_index; i++) {
438
* We ignore failures and ensure that all mounted
439
* containers are unmounted
441
error = umount(config_mount_table[i].path);
443
cgroup_dbg("Unmount failed\n");
444
error = rmdir(config_mount_table[i].path);
446
cgroup_dbg("rmdir failed\n");
453
* The main function which does all the setup of the data structures
454
* and finally creates the cgroups
456
int cgroup_config_load_config(const char *pathname)
459
yyin = fopen(pathname, "r");
462
cgroup_dbg("Failed to open file %s\n", pathname);
467
if (yyparse() != 0) {
468
cgroup_dbg("Failed to parse file %s\n", pathname);
470
return ECGROUPPARSEFAIL;
473
error = cgroup_config_mount_fs();
477
error = cgroup_init();
481
error = cgroup_config_create_groups();
482
cgroup_dbg("creating all cgroups now, error=%d\n", error);
489
cgroup_config_destroy_groups();
491
cgroup_config_unmount_controllers();
496
static int cgroup_cleanup_cgroup_controller_files(struct cgroup_file_info info,
497
char *root_path, char *ctrl)
501
char *rel_path = NULL;
506
rel_path = info.full_path + strlen(root_path) - 1;
508
if (!strncmp(rel_path, "/", strlen(rel_path)))
511
error = cgroup_get_task_begin(rel_path, ctrl,
514
if (error && error != ECGEOF)
517
while (error != ECGEOF) {
518
ret = cgroup_attach_task_pid(NULL, pid);
521
cgroup_get_task_end(&task_handle);
524
error = cgroup_get_task_next(&task_handle, &pid);
526
if (error && error != ECGEOF) {
527
cgroup_get_task_end(&task_handle);
532
cgroup_get_task_end(&task_handle);
534
error = rmdir(info.full_path);
543
static int cgroup_config_unload_controller(struct cgroup_mount_point mount_info)
545
struct cgroup_file_info info;
549
char *root_path = NULL;
551
error = cgroup_walk_tree_begin(mount_info.name, "/", 0, &tree_handle,
554
if (error && error != ECGEOF)
557
root_path = strdup(info.full_path);
560
cgroup_walk_tree_end(&tree_handle);
565
ret = cgroup_walk_tree_set_flags(&tree_handle,
566
CGROUP_WALK_TYPE_POST_DIR);
569
cgroup_walk_tree_end(&tree_handle);
573
while (error != ECGEOF) {
574
if (info.type == CGROUP_FILE_TYPE_DIR) {
575
ret = cgroup_cleanup_cgroup_controller_files(info,
576
root_path, mount_info.name);
579
cgroup_walk_tree_end(&tree_handle);
584
error = cgroup_walk_tree_next(0, &tree_handle, &info, lvl);
586
if (error && error != ECGEOF) {
588
cgroup_walk_tree_end(&tree_handle);
592
cgroup_walk_tree_end(&tree_handle);
593
error = umount(mount_info.path);
601
error = rmdir(mount_info.path);
613
int cgroup_unload_cgroups(void)
618
char *curr_path = NULL;
619
struct cgroup_mount_point info;
621
error = cgroup_init();
628
error = cgroup_get_controller_begin(&ctrl_handle, &info);
631
if (error && error != ECGEOF) {
636
while (error != ECGEOF) {
637
if (!curr_path || strcmp(info.path, curr_path) != 0) {
641
curr_path = strdup(info.path);
645
ret = cgroup_config_unload_controller(info);
651
error = cgroup_get_controller_next(&ctrl_handle, &info);
653
if (error && error != ECGEOF) {
662
cgroup_get_controller_end(&ctrl_handle);
667
cgroup_get_controller_end(&ctrl_handle);