----- Original Message -----
> From: "Jan Chaloupka" <jchal...@redhat.com>
> To: libcg-devel@lists.sourceforge.net
> Cc: jchal...@redhat.com, varek...@redhat.com
> Sent: Monday, July 14, 2014 8:23:56 AM
> Subject: [PATCH 1/2] api.c: Adding support for loading configuration files 
> from cgrules.d directory
> 
> Implementation of loading rules from /etc/cgrules.d/. Explanation is in the
> cover letter. New function cgroup_parse_rules_file created,
> calling cgroup_parse_rules. cgroup_parse_rules is invoked only in
> cgroup_change_cgroup_flags, cgroup_init_rules_cache and
> cgroup_reload_cached_rules functions. For them the change in
> cgroup_parse_rules
> implementation is transpart.
> 
> Tested with two configuration files in /etc/cgrules.d/ and all rules
> in /etc/cgrules.conf commented out:
> 
> $ cat /etc/cgrules.conf
> #*:ls       cpu             strom/%u
> #*:sleep    memory          les/%g
> 
> $ cat /etc/cgrules.d/cgrules1.conf
> *:ls       cpu             strom/%u
> 
> $ cat /etc/cgrules.d/cgrules2.conf
> *:sleep    memory          les/%g
> 
> plus cgconfig.[c|d/*] files:
> $ cat /etc/cgconfig.conf
> mount {
>         cpuset  = /cgroup/cpuset;
>         cpu     = /cgroup/cpu;
>         cpuacct = /cgroup/cpuacct;
>         memory  = /cgroup/memory;
>         devices = /cgroup/devices;
>         freezer = /cgroup/freezer;
>         net_cls = /cgroup/net_cls;
>         blkio   = /cgroup/blkio;
> }
> 
> $ cat /etc/cgconfig.d/small.conf
> template strom/%u {
>         cpu {}
> }
> 
> group vetev {
>         cpu {}
> }
> 
> $ cat /etc/cgconfig.d/medium.conf
> template les/%g {
>         memory {}
> }
> 
> group drevo/listi {
>         memory {}
> }
> 
> Tested to cache reload as well by sending SIGUSR2 signal to running
> cgrulesengd process. After first reload I commented out all rules => no
> rules match after invoking ls command. After second reload I uncommented
> out ls rule => rule match after invoking ls command. After third reload
> I uncommented out ls and sleep rule => debug output of cgrulesengd shows
> both rules loaded in the cache
> 
> Changelog:
> * CGROUP_PARSE_STATE_UNLOCK removed
> * reformulation of comment to "Cannot read directory. However,
>   CGRULES_CONF_FILE is succesfully parsed. Thus return as a success for
>   back compatibility."
> * errno = 0 removed, once it is not zero, function returns, so need to set
>   it to 0 in every iteration
> * fprintf replaced by cgroup_err
> * added missing unlocks + new label unlock_list for all returns
> 
> This
> - * finds a rule matching the given UID or GID.  It will store this rule in
> rl,
> + * finds a rule matching the given UID or GID.  It will store this rule in
> trl,
> is valid correction. "It will store this rule in rl" talks about cache being
> disabled. In this case, it is  stored into trl.
> 
> Signed-off-by: Jan Chaloupka <jchal...@redhat.com>
Acked-by: Ivana Hutarova Varekova <varek...@redhat.com>
> ---
>  src/api.c                |  159
>  +++++++++++++++++++++++++++++++++++++++++++---
>  src/libcgroup-internal.h |    1
>  2 files changed, 148 insertions(+), 12 deletions(-)
> 
> diff --git a/src/api.c b/src/api.c
> index 0b3d8a0..5751b8f 100644
> --- a/src/api.c
> +++ b/src/api.c
> @@ -473,17 +473,19 @@ static char *cg_skip_unused_charactors_in_rule(char
> *rule)
>   * The cache parameter alters the behavior of this function.  If true, this
>   * function will read the entire configuration file and store the results in
>   * rl (global rules list).  If false, this function will only parse until it
> - * finds a rule matching the given UID or GID.  It will store this rule in
> rl,
> + * finds a rule matching the given UID or GID.  It will store this rule in
> trl,
>   * as well as any children rules (rules that begin with a %) that it has.
>   *
>   * This function is NOT thread safe!
> + *   @param filename configuration file to parse
>   *   @param cache True to cache rules, else false
>   *   @param muid If cache is false, the UID to match against
>   *   @param mgid If cache is false, the GID to match against
>   *   @return 0 on success, -1 if no cache and match found, > 0 on error.
>   * TODO: Make this function thread safe!
> + *
>   */
> -static int cgroup_parse_rules(bool cache, uid_t muid,
> +static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
>                                         gid_t mgid, const char *mprocname)
>  {
>       /* File descriptor for the configuration file */
> @@ -544,21 +546,19 @@ static int cgroup_parse_rules(bool cache, uid_t muid,
>       else
>               lst = &trl;
>  
> -     /* If our list already exists, clean it. */
> -     if (lst->head)
> -             cgroup_free_rule_list(lst);
> -
>       /* Open the configuration file. */
> -     pthread_rwlock_wrlock(&rl_lock);
> -     fp = fopen(CGRULES_CONF_FILE, "re");
> +     fp = fopen(filename, "re");
>       if (!fp) {
>               cgroup_warn("Warning: failed to open configuration file %s: 
> %s\n",
> -                             CGRULES_CONF_FILE, strerror(errno));
> -             goto unlock;
> +                             filename, strerror(errno));
> +
> +             ret = ECGRULESPARSEFAIL;  /* originally ret = 0, but */
> +                                       /* this is parse fail, not success */
> +             goto finish;
>       }
>  
>       /* Now, parse the configuration file one line at a time. */
> -     cgroup_dbg("Parsing configuration file.\n");
> +     cgroup_dbg("Parsing configuration file %s.\n", filename);
>       while (fgets(buff, sizeof(buff), fp) != NULL) {
>               linenum++;
>  
> @@ -804,8 +804,143 @@ parsefail:
>  
>  close:
>       fclose(fp);
> -unlock:
> +finish:
> +     return ret;
> +}
> +
> +/**
> + * Parse CGRULES_CONF_FILE and all files in CGRULES_CONF_FILE_DIR.
> + * If CGRULES_CONF_FILE_DIR does not exists or can not be read,
> + * parse only CGRULES_CONF_FILE. This way we keep the back compatibility.
> + *
> + * Original description of this function moved to cgroup_parse_rules_file.
> + * Also cloned and all occurences of file changed to files.
> + *
> + * Parse the configuration files that maps UID/GIDs to cgroups.  If ever the
> + * configuration files are modified, applications should call this function
> to
> + * load the new configuration rules.  The function caller is responsible for
> + * calling free() on each rule in the list.
> + *
> + * The cache parameter alters the behavior of this function.  If true, this
> + * function will read the entire content of all configuration files and
> store
> + * the results in rl (global rules list).  If false, this function will only
> + * parse until it finds a file and a rule matching the given UID or GID.
> + * The remaining files are skipped. It will store this rule in trl,
> + * as well as any children rules (rules that begin with a %) that it has.
> + *
> + * Files can be read in an random order so the first match must not be
> + * dependent on it. Thus construct the rules the way not to break
> + * this assumption.
> + *
> + * This function is NOT thread safe!
> + *   @param cache True to cache rules, else false
> + *   @param muid If cache is false, the UID to match against
> + *   @param mgid If cache is false, the GID to match against
> + *   @return 0 on success, -1 if no cache and match found, > 0 on error.
> + * TODO: Make this function thread safe!
> + */
> +static int cgroup_parse_rules(bool cache, uid_t muid,
> +                                       gid_t mgid, const char *mprocname)
> +{
> +     int ret;
> +
> +     /* Pointer to the list that we're using */
> +     struct cgroup_rule_list *lst = NULL;
> +
> +     /* Directory variables */
> +     DIR *d;
> +     struct dirent *item;
> +     const char *dirname = CGRULES_CONF_DIR;
> +     char *tmp;
> +     int sret;
> +
> +     /* Determine which list we're using. */
> +     if (cache)
> +             lst = &rl;
> +     else
> +             lst = &trl;
> +
> +     /* If our list already exists, clean it. */
> +     if (lst->head)
> +             cgroup_free_rule_list(lst);
> +
> +     pthread_rwlock_wrlock(&rl_lock);
> +
> +     /* Parse CGRULES_CONF_FILE configuration file (back compatibility). */
> +     ret = cgroup_parse_rules_file(CGRULES_CONF_FILE,
> +             cache, muid, mgid, mprocname);
> +
> +     /*
> +      * if match (ret = -1), stop parsing other files, just return
> +      * or ret > 0 => error
> +      */
> +     if (ret != 0) {
> +             pthread_rwlock_unlock(&rl_lock);
> +             return ret;
> +     }
> +
> +     /* Continue parsing */
> +     d = opendir(dirname);
> +     if (!d) {
> +             cgroup_warn("Warning: Failed to open directory %s: %s\n",
> +                             dirname, strerror(errno));
> +
> +             /*
> +              * Cannot read directory. However, CGRULES_CONF_FILE is
> +              * succesfully parsed. Thus return as a success
> +              * for back compatibility.
> +              */
> +             pthread_rwlock_unlock(&rl_lock);
> +
> +             return 0;
> +     }
> +
> +     /* read all files from CGRULES_CONF_FILE_DIR */
> +     do {
> +             item = readdir(d);
> +             if (item && (item->d_type == DT_REG
> +                             || item->d_type == DT_LNK)) {
> +
> +                     sret = asprintf(&tmp, "%s/%s", dirname, item->d_name);
> +                     if (sret < 0) {
> +                             cgroup_err("Out of memory\n");
> +
> +                             /*
> +                              * Cannot read directory. However, 
> CGRULES_CONF_FILE is
> +                              * succesfully parsed. Thus return as a success
> +                              * for back compatibility.
> +                              */
> +                             ret = 0;
> +                             goto unlock_list;
> +                     }
> +
> +                     cgroup_dbg("Parsing cgrules file: %s\n", tmp);
> +                     ret = cgroup_parse_rules_file(tmp,
> +                             cache, muid, mgid, mprocname);
> +
> +                     free(tmp);
> +
> +                     /* match with cache disabled? */
> +                     if (ret != 0)
> +                             goto unlock_list;
> +             }
> +             if (!item && errno) {
> +                     cgroup_warn("Warning: cannot read %s: %s\n",
> +                                     dirname, strerror(errno));
> +                     /*
> +                      * Cannot read an item. But continue for
> +                      * back compatibility as a success.
> +                      */
> +                     ret = 0;
> +                     goto unlock_list;
> +             }
> +     } while (item != NULL);
> +
> +unlock_list:
> +     closedir(d);
> +
>       pthread_rwlock_unlock(&rl_lock);
> +
>       return ret;
>  }
>  
> diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
> index c128788..9875dd9 100644
> --- a/src/libcgroup-internal.h
> +++ b/src/libcgroup-internal.h
> @@ -53,6 +53,7 @@ __BEGIN_DECLS
>  #define CGCONFIG_CONF_DIR               "/etc/cgconfig.d"
>  
>  #define CGRULES_CONF_FILE       "/etc/cgrules.conf"
> +#define CGRULES_CONF_DIR        "/etc/cgrules.d"
>  #define CGRULES_MAX_FIELDS_PER_LINE          3
>  
>  #define CGROUP_BUFFER_LEN (5 * FILENAME_MAX)
> 
> 

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to