]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
libcgroup: Setup the namespace datastructures
authorDhaval Giani <dhaval@linux.vnet.ibm.com>
Thu, 7 Jan 2010 10:54:35 +0000 (16:24 +0530)
committerDhaval Giani <dhaval@linux.vnet.ibm.com>
Thu, 7 Jan 2010 15:39:08 +0000 (21:09 +0530)
This patch handles the validation of the newer configuration files.

Some of the rules to be followed
1. We cannot have more controllers in the namespcae section than
already mounted.
2. If more than one controller are mounted at the same point, then
they will have the same namespace. In case it is not explicitly
mentioned, the subsystems at the mount point will be set to the
same namespace. This does not mean that controllers mounted at different
points need to have the same namespace.

Changes from v4:
1. Changed a variable name from mount to mount_path
2. Added more comments

Changes from v3:
1. Removed most of the strdups
2. Fixed return values for errors

Changes from v2:
1. mount and namespace keyword cannot come in the same file.

Changes from v1:
1. Fix a bug where if a namespace was not defined, we were not exiting
2. Comment the validate namespace function
3. Make some of the variables more descriptive
4. Make namespace thread specific

Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
include/libcgroup.h
src/api.c
src/config.c
src/libcgroup-internal.h

index b58b2bb710f72b5776eb904cfc56cba23611c8e3..d54d9c691fcf683080b925791f3a5d87eddd4c31 100644 (file)
@@ -89,6 +89,9 @@ enum cgroup_errors {
        ECGSENTINEL,    /* Please insert further error codes above this */
        ECGEOF,         /* End of file, iterator */
        ECGCONFIGPARSEFAIL,/* Failed to parse config file (cgconfig.conf). */
+       ECGNAMESPACEPATHS,
+       ECGNAMESPACECONTROLLER,
+       ECGMOUNTNAMESPACE,
 };
 
 #define ECGRULESPARSEFAIL      ECGROUPPARSEFAIL
index 967a48e023e3f2bda89fddcff5e389d5e587c4b5..5d31c37a5df220795e1619d27fd43efb4cca7402 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -64,9 +64,6 @@ __thread char errtext[MAXLEN];
 /* Task command name length */
 #define TASK_COMM_LEN 16
 
-struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX];
-static pthread_rwlock_t cg_mount_table_lock = PTHREAD_RWLOCK_INITIALIZER;
-
 /* Check if cgroup_init has been called or not. */
 static int cgroup_initialized;
 
@@ -82,6 +79,9 @@ static struct cgroup_rule_list trl;
 /* Lock for the list of rules (rl) */
 static pthread_rwlock_t rl_lock = PTHREAD_RWLOCK_INITIALIZER;
 
+/* Namespace */
+__thread char *cg_namespace_table[CG_CONTROLLER_MAX];
+
 char *cgroup_strerror_codes[] = {
        "Cgroup is not compiled in",
        "Cgroup is not mounted",
@@ -108,6 +108,10 @@ char *cgroup_strerror_codes[] = {
        "The config file can not be opened",
        "Sentinel"
        "End of File or iterator",
+       "Failed to parse config file",
+       "Have multiple paths for the same namespace",
+       "Controller in namespace does not exist",
+       "Cannot have mount and namespace keyword in the same configuration file",
 };
 
 static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group)
index 7435795a5bc5bda50d0fa8c6f5b5ed7daeb2563c..f89ef3692cea154d76522a5d61c693a03a3ecc43 100644 (file)
@@ -482,6 +482,169 @@ int cgroup_config_unmount_controllers(void)
        return 0;
 }
 
+static int config_validate_namespaces(void)
+{
+       int i;
+       char *namespace = NULL;
+       char *mount_path = NULL;
+       int j, subsys_count;
+       int error = 0;
+
+       pthread_rwlock_wrlock(&cg_mount_table_lock);
+       for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) {
+               /*
+                * If we get the path in the first run, then we
+                * are good, else we will need to go for two
+                * loops. This should be optimized in the future
+                */
+               mount_path = cg_mount_table[i].path;
+
+               if (!mount_path) {
+                       last_errno = errno;
+                       error = ECGOTHER;
+                       goto out_error;
+               }
+
+               /*
+                * Setup the namespace for the subsystems having the same
+                * mount point.
+                */
+               if (!cg_namespace_table[i]) {
+                       namespace = NULL;
+               } else {
+                       namespace = cg_namespace_table[i];
+                       if (!namespace) {
+                               last_errno = errno;
+                               error = ECGOTHER;
+                               goto out_error;
+                       }
+               }
+
+               /*
+                * We want to handle all the subsytems that are mounted
+                * together. So initialize j to start from the next point in
+                * the mount table.
+                */
+
+               j = i + 1;
+
+               /*
+                * Search through the mount table to locate which subsystems
+                * are mounted together.
+                */
+               while (!strncmp(cg_mount_table[j].path, mount_path, FILENAME_MAX)) {
+                       if (!namespace && cg_namespace_table[j]) {
+                               /* In case namespace is not setup, set it up */
+                               namespace = cg_namespace_table[j];
+                               if (!namespace) {
+                                       last_errno = errno;
+                                       error = ECGOTHER;
+                                       goto out_error;
+                               }
+                       }
+                       j++;
+               }
+               subsys_count = j;
+
+               /*
+                * If there is no namespace, then continue on :)
+                */
+
+               if (!namespace) {
+                       i = subsys_count -  1;
+                       continue;
+               }
+
+               /*
+                * Validate/setup the namespace
+                * If no namespace is specified, copy the namespace we have
+                * stored. If a namespace is specified, confirm if it is
+                * the same as we have stored. If not, we fail.
+                */
+               for (j = i; j < subsys_count; j++) {
+                       if (!cg_namespace_table[j]) {
+                               cg_namespace_table[j] = strdup(namespace);
+                               if (!cg_namespace_table[j]) {
+                                       last_errno = errno;
+                                       error = ECGOTHER;
+                                       goto out_error;
+                               }
+                       }
+                       else if (strcmp(namespace, cg_namespace_table[j])) {
+                               error = ECGNAMESPACEPATHS;
+                               goto out_error;
+                       }
+               }
+               /* i++ in the for loop will increment it */
+               i = subsys_count - 1;
+       }
+out_error:
+       pthread_rwlock_unlock(&cg_mount_table_lock);
+       return error;
+}
+
+/*
+ * Should always be called after cgroup_init() has been called
+ *
+ * NOT to be called outside the library. Is handled internally
+ * when we are looking to  load namespace configurations.
+ *
+ * This function will order the namespace table in the same
+ * fashion as how the mou table is setup.
+ *
+ * Also it will setup namespaces for all the controllers mounted.
+ * In case a controller does not have a namespace assigned to it, it
+ * will set it to null.
+ */
+static int config_order_namespace_table(void)
+{
+       int i = 0;
+       int error = 0;
+
+       pthread_rwlock_wrlock(&cg_mount_table_lock);
+       /*
+        * Set everything to NULL
+        */
+       for (i = 0; i < CG_CONTROLLER_MAX; i++)
+               cg_namespace_table[i] = NULL;
+
+       memset(cg_namespace_table, 0, CG_CONTROLLER_MAX * sizeof(cg_namespace_table[0]));
+
+       /*
+        * Now fill up the namespace table looking at the table we have
+        * otherwise.
+        */
+
+       for (i = 0; i < namespace_table_index; i++) {
+               int j;
+               int flag = 0;
+               for (j = 0; cg_mount_table[j].name[0] != '\0'; j++) {
+                       if (strncmp(config_namespace_table[i].name,
+                               cg_mount_table[j].name, FILENAME_MAX) == 0) {
+
+                               flag = 1;
+
+                               if (cg_namespace_table[j]) {
+                                       error = ECGNAMESPACEPATHS;
+                                       goto error_out;
+                               }
+
+                               cg_namespace_table[j] = strdup(config_namespace_table[i].path);
+                               if (!cg_namespace_table[j]) {
+                                       last_errno = errno;
+                                       error = ECGOTHER;
+                                       goto error_out;
+                               }
+                       }
+               }
+               if (!flag)
+                       return ECGNAMESPACECONTROLLER;
+       }
+error_out:
+       pthread_rwlock_unlock(&cg_mount_table_lock);
+       return error;
+}
+
 /*
  * The main function which does all the setup of the data structures
  * and finally creates the cgroups
@@ -489,6 +652,8 @@ int cgroup_config_unmount_controllers(void)
 int cgroup_config_load_config(const char *pathname)
 {
        int error;
+       int namespace_enabled = 0;
+       int mount_enabled = 0;
        yyin = fopen(pathname, "r");
 
        if (!yyin) {
@@ -503,6 +668,21 @@ int cgroup_config_load_config(const char *pathname)
                return ECGCONFIGPARSEFAIL;
        }
 
+       namespace_enabled = (config_namespace_table[0].name[0] != '\0');
+       mount_enabled = (config_mount_table[0].name[0] != '\0');
+
+       /*
+        * The configuration should have either namespace or mount.
+        * Not both and not none.
+        */
+       if (namespace_enabled == mount_enabled)
+               return ECGMOUNTNAMESPACE;
+
+       /*
+        * We do not allow both mount and namespace sections in the
+        * same configuration file. So test for that
+        */
+
        error = cgroup_config_mount_fs();
        if (error)
                goto err_mnt;
@@ -511,6 +691,19 @@ int cgroup_config_load_config(const char *pathname)
        if (error)
                goto err_mnt;
 
+       /*
+        * The very first thing is to sort the namespace table. If we fail
+        * we unmount everything and get out.
+        */
+
+       error = config_order_namespace_table();
+       if (error)
+               goto err_mnt;
+
+       error = config_validate_namespaces();
+       if (error)
+               goto err_mnt;
+
        error = cgroup_config_create_groups();
        cgroup_dbg("creating all cgroups now, error=%d\n", error);
        if (error)
index 81a7b989b0b27c74bf9a6b0e74f135b72dc55f4a..b9ef442fb46f299e5e1246123e5bdecb51438731 100644 (file)
@@ -22,6 +22,7 @@ __BEGIN_DECLS
 #include <fts.h>
 #include <libcgroup.h>
 #include <limits.h>
+#include <pthread.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -116,6 +117,17 @@ int cg_mkdir_p(const char *path);
 struct cgroup *create_cgroup_from_name_value_pairs(const char *name,
                struct control_value *name_value, int nv_number);
 
+/*
+ * Main mounting structures
+ */
+struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX];
+static pthread_rwlock_t cg_mount_table_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/*
+ * config related structures
+ */
+
+extern __thread char *cg_namespace_table[CG_CONTROLLER_MAX];
 
 /*
  * config related API