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 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 <[email protected]>

---
 include/libcgroup.h      |    3 
 src/api.c                |   10 +-
 src/config.c             |  177 +++++++++++++++++++++++++++++++++++++++++++++++
 src/libcgroup-internal.h |   12 +++
 4 files changed, 199 insertions(+), 3 deletions(-)

Index: libcg/src/config.c
===================================================================
--- libcg.orig/src/config.c
+++ libcg/src/config.c
@@ -482,6 +482,153 @@ int cgroup_config_unmount_controllers(vo
        return 0;
 }
 
+static int config_validate_namespaces(void)
+{
+       int i;
+       char *namespace = NULL;
+       char *mount = 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 = cg_mount_table[i].path;
+
+               if (!mount) {
+                       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;
+                       }
+               }
+
+               j = i + 1;
+
+               /*
+                * Search through the mount table to locate which subsystems
+                * are mounted together.
+                */
+               while (!strncmp(cg_mount_table[j].path, mount, 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
+ */
+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 +636,8 @@ int cgroup_config_unmount_controllers(vo
 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 +652,21 @@ int cgroup_config_load_config(const char
                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 +675,19 @@ int cgroup_config_load_config(const char
        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: libcg/src/libcgroup-internal.h
===================================================================
--- libcg.orig/src/libcgroup-internal.h
+++ libcg/src/libcgroup-internal.h
@@ -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
Index: libcg/src/api.c
===================================================================
--- libcg.orig/src/api.c
+++ libcg/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: libcg/include/libcgroup.h
===================================================================
--- libcg.orig/include/libcgroup.h
+++ libcg/include/libcgroup.h
@@ -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



------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Libcg-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to