----- Original Message ----- > From: "Jan Chaloupka" <jchal...@redhat.com> > To: libcg-devel@lists.sourceforge.net > Cc: an...@digirati.com.br, jchal...@redhat.com, varek...@redhat.com > Sent: Friday, 4 July, 2014 1:35:37 PM > Subject: [PATCH 1/2] api.c: Adding support for loading configuration files > from cgrules.d directory > > This series of patches implements loading configuration files from > /etc/cgrules.d directory. First, /etc/cgrules.conf is parsed. After > successful parse, files from /etc/cgrules.d directory are parsed. Because > these files can be read in an arbitrary order, attention to rules in these > files must be taken. Potential conflicts are explained in cgrules.d (5) man > page in the second patch. In a case of missing or empty /etc/cgrules.d > directory, /etc/cgrules.conf is still parsed. Thus honouring a back > compatibility. Original cgroup_parse_rules function has the same signature. > Only its description is modified. New function cgroup_parse_rules_file is > presented. Its body is identical to the original cgroup_parse_rules, except > to removing cache erasing and locking mechanism, which has been moved back > to cgroup_parse_rules. cgroup_parse_rules consists of a call to > cgroup_parse_rules with CGRULES_CONF_FILE file (back compatibility) plus > opening and reading of files from CGRULES_CONF_DIR d! > irectory. Please send a cover letter in a separate e-mail
> > cgroup_parse_rules is called 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 > > Signed-off-by: Jan Chaloupka <jchal...@redhat.com> > --- > src/api.c | 156 > ++++++++++++++++++++++++++++++++++++++++++---- > src/libcgroup-internal.h | 1 > 2 files changed, 145 insertions(+), 12 deletions(-) > > diff --git a/src/api.c b/src/api.c > index 0b3d8a0..61974c9 100644 > --- a/src/api.c > +++ b/src/api.c > @@ -464,6 +464,8 @@ static char *cg_skip_unused_charactors_in_rule(char > *rule) > return itr; > } > > +#define CGROUP_PARSE_STATE_UNLOCK -1 > + as you already wrote please remove ^ > /** > * Parse the configuration file that maps UID/GIDs to cgroups. If ever the > * configuration file is modified, applications should call this function to > @@ -473,17 +475,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, depends on cache settings > * 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 +548,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 +806,138 @@ 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 but CGRULES_CONF_FILE parse. > + * Return as a success for back compatibility. > + */ please reformulate this comment > + pthread_rwlock_unlock(&rl_lock); > + > + return 0; > + } > + > + /* read all files from CGRULES_CONF_FILE_DIR */ > + do { > + errno = 0; is this necessary > + 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) { > + fprintf(stderr, "Out of memory\n"); please, use cgroup logging function cgroup_err here > + exit(1); missing unlock here don't use exit, use return > + } > + > + 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) { > + closedir(d); > + pthread_rwlock_unlock(&rl_lock); > + > + return ret; > + } > + } > + 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. > + */ > + closedir(d); missing unlockhere > + return 0; > + } > + } while (item != NULL); > + > + 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) > > ------------------------------------------------------------------------------ Open source business process management suite built on Java and Eclipse Turn processes into business applications with Bonita BPM Community Edition Quickly connect people, data, and systems into organized workflows Winner of BOSSIE, CODIE, OW2 and Gartner awards http://p.sf.net/sfu/Bonitasoft _______________________________________________ Libcg-devel mailing list Libcg-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libcg-devel