summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libcgroup.h3
-rw-r--r--src/api.c10
-rw-r--r--src/config.c193
-rw-r--r--src/libcgroup-internal.h12
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
diff --git a/src/api.c b/src/api.c
index 967a48e..5d31c37 100644
--- a/src/api.c
+++ b/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)
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