diff options
-rw-r--r-- | include/libcgroup.h | 3 | ||||
-rw-r--r-- | src/api.c | 10 | ||||
-rw-r--r-- | src/config.c | 193 | ||||
-rw-r--r-- | src/libcgroup-internal.h | 12 |
4 files changed, 215 insertions, 3 deletions
diff --git a/include/libcgroup.h b/include/libcgroup.h index b58b2bb..d54d9c6 100644 --- a/include/libcgroup.h +++ b/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 @@ -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) diff --git a/src/config.c b/src/config.c index 7435795..f89ef36 100644 --- a/src/config.c +++ b/src/config.c @@ -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) diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h index 81a7b98..b9ef442 100644 --- a/src/libcgroup-internal.h +++ b/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 |