* Dhaval Giani <[email protected]> [2010-01-04 18:04:44]:

> 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;
mount_path is a better name

> +     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;

What's the magic here? could use some comments here. I think I
understand it today, but a month from now and I'll have to reread
the entire routine.

> +
> +             /*
> +              * 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
> + */

Should this be called by user space applications? What does it
do, can we have some docbook style comments and some more details
on the goals of the routine and the postconditions, please?


> +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];
> +

Is this per thread? why? If an application like a webserver
has 1000 threads, do we get one copy of the namespace
per thread? We don't support per-thread configurations, do we?

>  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
> 
> 
> 

-- 
        Balbir

------------------------------------------------------------------------------
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