]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Multiple mount point support. Patches built on top of Dhaval'a patches.
authorBalbir Singh <balbir@linux.vnet.ibm.com>
Sat, 17 May 2008 16:06:20 +0000 (16:06 +0000)
committerBalbir Singh <balbir@linux.vnet.ibm.com>
Sat, 17 May 2008 16:06:20 +0000 (16:06 +0000)
Works for me on my testing. NOTE: The testing is insufficient as we
only test cg_control_create_cgroup() and not delete_cgroup() or
attach_task(). Sudhir's new test cases should really help

Several coding style fixes and changes, enhancements to make the code
work.

NOTE: Since this is development release -DDEBUG is back in the makefile.
Once this is committed, I'll bump up the version to 0.05 if no one objects.

Test report
-----------
debug log from the library

matched cpuacct:cpuacct
Found cgroup option rw,relatime,cpuacct,  count 0
matched cpu:cpu
Found cgroup option rw,relatime,cpu,  count 1
tuid 0, tgid 0, cuid 1000, cgid 1000
path is /tmp/container_cpu/database/
path is /tmp/container_cpuacct/database/

NOTE: The database directory was created as expected on both mount points
/tmp/container_cpu and /tmp/container_cpuacct

balbir@localhost:~/deliverables/nextgen/libcg/branches/balbir/tests$ ls -al /tmp/container_cpuacct/
total 424
drwxrwxrwt  5 root   root        0 2008-05-17 21:27 .
drwxrwxrwt 32 root   root   425984 2008-05-17 21:26 ..
drwxr-xr-x  2 root   root        0 2008-05-17 17:09 class1
drwxr-xr-x  2 balbir balbir      0 2008-05-17 17:09 class2
-rw-r--r--  1 root   root        0 2008-05-17 17:09 cpuacct.usage
drwxr-xr-x  2 balbir balbir      0 2008-05-17 21:27 database
-rw-r--r--  1 root   root        0 2008-05-17 17:09 notify_on_release
-rw-r--r--  1 root   root        0 2008-05-17 17:09 releasable
-rw-r--r--  1 root   root        0 2008-05-17 17:09 release_agent
-rwxrwxrwx  1 root   root        0 2008-05-17 17:09 tasks

balbir@localhost:~/deliverables/nextgen/libcg/branches/balbir/tests$ ls -al /tmp/container_cpu
total 424
drwxrwxrwt  5 root   root        0 2008-05-17 21:27 .
drwxrwxrwt 32 root   root   425984 2008-05-17 21:26 ..
drwxr-xr-x  2 root   root        0 2008-05-17 17:09 class1
drwxr-xr-x  2 balbir balbir      0 2008-05-17 17:09 class2
-rw-r--r--  1 root   root        0 2008-05-17 17:09 cpu.rt_runtime_us
-rw-r--r--  1 root   root        0 2008-05-17 17:09 cpu.shares
drwxr-xr-x  2 balbir balbir      0 2008-05-17 21:27 database
-rw-r--r--  1 root   root        0 2008-05-17 17:09 notify_on_release
-rw-r--r--  1 root   root        0 2008-05-17 17:09 releasable
-rw-r--r--  1 root   root        0 2008-05-17 17:09 release_agent
-rwxrwxrwx  1 root   root        0 2008-05-17 21:10 tasks

Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@30 4f4bb910-9a46-0410-90c8-c897d4f1cd53

Makefile
api.c
libcg.h
tests/libcg_ba.cpp

index 40737d3a224c914b935b3ac4ab46abfeded0871b..5e19a79ce35e1f5b242662020add28dc4949dc25 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@
 YACC_DEBUG=-t
 DEBUG=-DDEBUG
 INC=-I.
-CFLAGS=-g -O2 -Wextra $(INC) 
+CFLAGS=-g -O2 -Wextra $(INC) $(DEBUG)
 LIBS= -lcg
 LDFLAGS= -L .
 INSTALLPREFIX=
diff --git a/api.c b/api.c
index f88be3f47dfd41f48f44a080412fa93f3b57992f..c0c779b167dc408683b22f78e77e100e245dbaca 100644 (file)
--- a/api.c
+++ b/api.c
  */
 const static char cg_version[] = "0.01";
 
-/*
- * Only one mount point is currently supported. This will be enhanced to
- * support several hierarchies in the future
- */
-static char MOUNT_POINT[FILENAME_MAX];
-
 static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group)
 {
        int ret = 0;
@@ -104,6 +98,38 @@ int cg_init()
        struct mntent *ent, *found_ent = NULL;
        int found_mnt = 0;
        int ret = 0;
+       char *mntent_tok;
+       static char *controllers[CG_CONTROLLER_MAX];
+       FILE *proc_cgroup;
+       char subsys_name[FILENAME_MAX];
+       int hierarchy, num_cgroups, enabled;
+       int i=0;
+       char *mntopt;
+       int err;
+
+       proc_cgroup = fopen("/proc/cgroups", "r");
+
+       if (!proc_cgroup)
+               return EIO;
+
+       /*
+        * The first line of the file has stuff we are not interested in.
+        * So just read it and discard the information.
+        *
+        * XX: fix the size for fgets
+        */
+       fgets(subsys_name, FILENAME_MAX, proc_cgroup);
+       while (!feof(proc_cgroup)) {
+               err = fscanf(proc_cgroup, "%s %d %d %d", subsys_name,
+                               &hierarchy, &num_cgroups, &enabled);
+               if (err < 0)
+                       break;
+               controllers[i] = (char *)malloc(strlen(subsys_name));
+               strcpy(controllers[i], subsys_name);
+               i++;
+       }
+       controllers[i] = NULL;
+       fclose(proc_cgroup);
 
        proc_mount = fopen("/proc/mounts", "r");
        if (proc_mount == NULL) {
@@ -111,36 +137,64 @@ int cg_init()
        }
 
        while ((ent = getmntent(proc_mount)) != NULL) {
-               if (!strncmp(ent->mnt_fsname,"cgroup", strlen("cgroup"))) {
-                       found_ent = ent;
-                       found_mnt++;
-                       dbg("Found cgroup option %s, count %d\n",
-                               found_ent->mnt_opts, found_mnt);
+               if (!strncmp(ent->mnt_type, "cgroup", strlen("cgroup"))) {
+                       for (i = 0; controllers[i] != NULL; i++) {
+                               mntopt = hasmntopt(ent, controllers[i]);
+                               if (mntopt &&
+                                       strcmp(mntopt, controllers[i]) == 0) {
+                                       dbg("matched %s:%s\n", mntopt,
+                                               controllers[i]);
+                                       strcpy(cg_mount_table[found_mnt].name,
+                                               controllers[i]);
+                                       strcpy(cg_mount_table[found_mnt].path,
+                                               ent->mnt_dir);
+                                       dbg("Found cgroup option %s, "
+                                               " count %d\n",
+                                               ent->mnt_opts, found_mnt);
+                                       found_mnt++;
+                               }
+                       }
                }
        }
 
-       /*
-        * Currently we require that all controllers be bound together
-        */
-       if (!found_mnt)
-               ret = ECGROUPNOTMOUNTED;
-       else if (found_mnt > 1)
-               ret = ECGROUPMULTIMOUNTED;
-       else {
-               /*
-                * NOTE: FILENAME_MAX ensures that we don't need to worry
-                * about crossing MOUNT_POINT size. For the paranoid, yes
-                * this is a potential security hole - Balbir
-                * Dhaval - fix these things.
-                */
-               strcpy(MOUNT_POINT, found_ent->mnt_dir);
-               strcat(MOUNT_POINT, "/");
+       if (!found_mnt) {
+               cg_mount_table[0].name[0] = '\0';
+               return ECGROUPNOTMOUNTED;
        }
 
+       found_mnt++;
+       cg_mount_table[found_mnt].name[0] = '\0';
+
+
        fclose(proc_mount);
        return ret;
 }
 
+static char **get_mounted_controllers(char *mountpoint)
+{
+       char **controllers;
+       int i, j;
+
+       i = 0;
+       j = 0;
+
+       controllers = (char **) malloc(sizeof(char *) * CG_CONTROLLER_MAX);
+
+       for (i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name != NULL;
+                                                                       i++) {
+               if (strcmp(cg_mount_table[i].name, mountpoint) == 0) {
+                       controllers[j] = (char *)malloc(sizeof(char) *
+                                                               FILENAME_MAX);
+                       strcpy(controllers[j], cg_mount_table[i].name);
+                       j++;
+               }
+       }
+       controllers[j] = (char *)malloc(sizeof(char) * FILENAME_MAX);
+       controllers[j][0] = '\0';
+
+       return controllers;
+}
+
 static int cg_test_mounted_fs()
 {
        FILE *proc_mount;
@@ -152,7 +206,7 @@ static int cg_test_mounted_fs()
        }
        ent = getmntent(proc_mount);
 
-       while (strcmp(ent->mnt_fsname, "cgroup") !=0) {
+       while (strcmp(ent->mnt_type, "cgroup") !=0) {
                ent = getmntent(proc_mount);
                if (ent == NULL)
                        return 0;
@@ -166,12 +220,19 @@ static inline pid_t cg_gettid()
        return syscall(__NR_gettid);
 }
 
-static char* cg_build_path(char *name, char *path)
+static char* cg_build_path(char *name, char *path, char *type)
 {
-       strcpy(path, MOUNT_POINT);
-       strcat(path, name);
-       strcat(path, "/");
-       return path;
+       int i;
+       for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) {
+               if (strcmp(cg_mount_table[i].name, type) == 0) {
+                       strcpy(path, cg_mount_table[i].path);
+                       strcat(path, "/");
+                       strcat(path, name);
+                       strcat(path, "/");
+                       return path;
+               }
+       }
+       return NULL;
 }
 
 /** cg_attach_task_pid is used to assign tasks to a cgroup.
@@ -186,27 +247,50 @@ int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid)
 {
        char path[FILENAME_MAX];
        FILE *tasks;
+       int i;
 
-       if (cgroup == NULL)
-               strcpy(path, MOUNT_POINT);
-       else {
-               cg_build_path(cgroup->name, path);
-       }
-
-       strcat(path, "/tasks");
-
-       tasks = fopen(path, "w");
-       if (!tasks) {
-               switch (errno) {
-               case EPERM:
-                       return ECGROUPNOTOWNER;
-               default:
-                       return ECGROUPNOTALLOWED;
+       if(!cgroup)
+       {
+               for(i = 0; i < CG_CONTROLLER_MAX &&
+                               cg_mount_table[i].name[0]!='\0'; i++) {
+                       if (!cg_build_path(cgroup->name, path, NULL))
+                               continue;
+                       strcat(path, "/tasks");
+
+                       tasks = fopen(path, "w");
+                       if (!tasks) {
+                               switch (errno) {
+                               case EPERM:
+                                       return ECGROUPNOTOWNER;
+                               default:
+                                       return ECGROUPNOTALLOWED;
+                               }
+                       }
+                       fprintf(tasks, "%d", tid);
+                       fclose(tasks);
+               }
+       } else {
+               for( i = 0; i <= CG_CONTROLLER_MAX &&
+                               cgroup->controller[i] != NULL ; i++) {
+                       if (!cg_build_path(cgroup->name, path,
+                                       cgroup->controller[i]->name))
+                               continue;
+
+                       strcat(path, "/tasks");
+
+                       tasks = fopen(path, "w");
+                       if (!tasks) {
+                               switch (errno) {
+                               case EPERM:
+                                       return ECGROUPNOTOWNER;
+                               default:
+                                       return ECGROUPNOTALLOWED;
+                               }
+                       }
+                       fprintf(tasks, "%d", tid);
+                       fclose(tasks);
                }
        }
-       fprintf(tasks, "%d", tid);
-       fclose(tasks);
-
        return 0;
 
 }
@@ -316,11 +400,12 @@ int cg_modify_cgroup(struct cgroup *cgroup)
        int i;
        int error;
 
-       cg_build_path(cgroup->name, base);
-
        for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i];
                                                i++, strcpy(path, base)) {
                int j;
+               if (!cg_build_path(cgroup->name, base,
+                       cgroup->controller[i]->name))
+                       continue;
                for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j];
                                                j++, strcpy(path, base)) {
                        strcat(path, cgroup->controller[i]->values[j]->name);
@@ -345,8 +430,8 @@ err:
 int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
 {
        char *fts_path[2], base[FILENAME_MAX], *path;
-       int i;
-       int error;
+       int i, j, k;
+       int error = 0;
 
        fts_path[0] = (char *)malloc(FILENAME_MAX);
        if (!fts_path[0])
@@ -354,40 +439,49 @@ int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
        fts_path[1] = NULL;
        path = fts_path[0];
 
-       cg_build_path(cgroup->name, path);
-       error = cg_create_control_group(path);
-       if (error)
-               goto err;
+       /*
+        * XX: One important test to be done is to check, if you have multiple
+        * subsystems mounted at one point, all of them *have* be on the cgroup
+        * data structure. If not, we fail.
+        */
+       for (k = 0; k < CG_CONTROLLER_MAX && cgroup->controller[k]; k++) {
+               path[0] = '\0';
 
-       strcpy(base, path);
+               if (!cg_build_path(cgroup->name, path,
+                               cgroup->controller[k]->name))
+                       continue;
 
-       if (!ignore_ownership)
-               cg_chown_recursive(fts_path, cgroup->control_uid,
-                                       cgroup->control_gid);
-       if (error)
-               goto err;
+               dbg("path is %s\n", path);
+               error = cg_create_control_group(path);
+               if (error)
+                       goto err;
 
-       for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i];
-                                               i++, strcpy(path, base)) {
-               int j;
-               for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j];
-                                               j++, strcpy(path, base)) {
-                       strcat(path, cgroup->controller[i]->values[j]->name);
-                       error = cg_set_control_value(path,
-                               cgroup->controller[i]->values[j]->value);
+               strcpy(base, path);
+
+               if (!ignore_ownership)
+                       error = cg_chown_recursive(fts_path,
+                               cgroup->control_uid, cgroup->control_gid);
 
+               if (error)
+                       goto err;
+
+               for (j = 0; j < CG_NV_MAX && cgroup->controller[k]->values[j];
+                                       j++, strcpy(path, base)) {
+                       strcat(path, cgroup->controller[k]->values[j]->name);
+                       error = cg_set_control_value(path,
+                               cgroup->controller[k]->values[j]->value);
                        /*
-                        * Should we undo, what we've done in the loops above?
-                        */
+                        * Should we undo, what we've done in the loops above?
+                        */
                        if (error)
                                goto err;
                }
-       }
-
-       if (!ignore_ownership) {
-               strcpy(path, base);
-               strcat(path, "/tasks");
-               chown(path, cgroup->tasks_uid, cgroup->tasks_gid);
+               if (!ignore_ownership) {
+                       strcpy(path, base);
+                       strcat(path, "/tasks");
+                       chown(path, cgroup->tasks_uid, cgroup->tasks_gid);
+               }
        }
 err:
        free(path);
@@ -401,40 +495,55 @@ err:
  */
 int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
 {
-       FILE *delete_tasks, *base_tasks;
+       FILE *delete_tasks, *base_tasks = NULL;
        int tids;
        char path[FILENAME_MAX];
        int error = ECGROUPNOTALLOWED;
+       int i;
 
-       strcpy(path, MOUNT_POINT);
-       strcat(path,"tasks");
+       for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller; i++) {
+               if (!cg_build_path(cgroup->name, path,
+                                       cgroup->controller[i]->name))
+                       continue;
+               strcat(path, "../tasks");
 
-       base_tasks = fopen(path, "w");
-       if (!base_tasks)
-               goto base_open_err;
+               base_tasks = fopen(path, "w");
+               if (!base_tasks)
+                       goto base_open_err;
 
-       cg_build_path(cgroup->name, path);
-       strcat(path,"tasks");
+               if (!cg_build_path(cgroup->name, path,
+                                       cgroup->controller[i]->name))
+                       continue;
 
-       delete_tasks = fopen(path, "r");
-       if (!delete_tasks)
-               goto del_open_err;
+               strcat(path, "tasks");
 
-       while (!feof(delete_tasks)) {
-               fscanf(delete_tasks, "%d", &tids);
-               fprintf(base_tasks, "%d", tids);
-       }
+               delete_tasks = fopen(path, "r");
+               if (!delete_tasks)
+                       goto del_open_err;
+
+               while (!feof(delete_tasks)) {
+                       fscanf(delete_tasks, "%d", &tids);
+                       fprintf(base_tasks, "%d", tids);
+               }
 
-       cg_build_path(cgroup->name, path);
-       error = rmdir(path);
+               if (!cg_build_path(cgroup->name, path,
+                                       cgroup->controller[i]->name))
+                       continue;
+               error = rmdir(path);
 
-       fclose(delete_tasks);
+               fclose(delete_tasks);
+       }
 del_open_err:
-       fclose(base_tasks);
+       if (base_tasks)
+               fclose(base_tasks);
 base_open_err:
        if (ignore_migration) {
-               cg_build_path(cgroup->name, path);
-               error = rmdir(path);
+               for (i = 0; cgroup->controller[i] != NULL; i++) {
+                       if (!cg_build_path(cgroup->name, path,
+                                               cgroup->controller[i]->name))
+                               continue;
+                       error = rmdir(path);
+               }
        }
        return error;
 }
diff --git a/libcg.h b/libcg.h
index 7dfe9a49c4e9088c868037009feeae114215100f..c807cfaa7ae3f49d3a7cb68e43bcd364b769a606 100644 (file)
--- a/libcg.h
+++ b/libcg.h
@@ -160,6 +160,11 @@ struct cgroup {
        gid_t control_gid;
 };
 
+struct cg_mount_table_s {
+       char name[FILENAME_MAX];
+       char path[FILENAME_MAX];
+} cg_mount_table[CG_CONTROLLER_MAX];
+
 int cg_init(void);
 int cg_attach_task(struct cgroup *cgroup);
 int cg_modify_cgroup(struct cgroup *cgroup);
index b8df520b22aae0bfa3e65f0b0c87259b4c5952ac..967b1ff3da4e54b784242b1d6b146c4fd83f24ee 100644 (file)
@@ -22,6 +22,8 @@ using namespace std;
 #include <sys/types.h>
 #include <pwd.h>
 #include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 
 namespace cgtest {
 
@@ -91,6 +93,20 @@ struct cgroup *cg::makenode(const string &name, const string &task_uid,
                                        calloc(1, sizeof(struct control_value));
        strcpy(ccg->controller[0]->values[0]->name,"cpu.shares");
        strcpy(ccg->controller[0]->values[0]->value, "100");
+
+       ccg->controller[1] = (struct controller *)
+                               calloc(1, sizeof(struct controller));
+       strcpy(ccg->controller[1]->name, "memory");
+       ccg->controller[1]->values[0] = (struct control_value *)
+                                       calloc(1, sizeof(struct control_value));
+       strcpy(ccg->controller[1]->values[0]->name,"memory.limit_in_bytes");
+       strcpy(ccg->controller[1]->values[0]->value, "102400");
+
+       strcpy(ccg->controller[2]->name, "cpuacct");
+       ccg->controller[2]->values[0] = (struct control_value *)
+                                       calloc(1, sizeof(struct control_value));
+       strcpy(ccg->controller[2]->values[0]->name,"cpuacct.usage");
+       strcpy(ccg->controller[2]->values[0]->value, "0");
        ccg->tasks_uid = tuid;
        ccg->tasks_gid = tgid;
        ccg->control_uid = cuid;