summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBalbir Singh <balbir@linux.vnet.ibm.com>2008-04-05 13:33:32 +0000
committerBalbir Singh <balbir@linux.vnet.ibm.com>2008-04-05 13:33:32 +0000
commitf3994cbdfdfdf0d182197e00e8ada9d581e23309 (patch)
tree86adef3313f8238228cb0acec99f100a138f5adb
parent9d0502e7c67c556de0ea175dcc4b22f5e6ecc806 (diff)
downloadlibcg-f3994cbdfdfdf0d182197e00e8ada9d581e23309.tar.gz
libcg-f3994cbdfdfdf0d182197e00e8ada9d581e23309.tar.xz
libcg-f3994cbdfdfdf0d182197e00e8ada9d581e23309.zip
Dhaval's API changes, phase 1, prototype
git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@4 4f4bb910-9a46-0410-90c8-c897d4f1cd53
-rw-r--r--Makefile14
-rw-r--r--api.c347
-rw-r--r--libcg.h35
3 files changed, 391 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index a8ad7a1..686396e 100644
--- a/Makefile
+++ b/Makefile
@@ -14,12 +14,13 @@ YACC_DEBUG=-t
DEBUG=-DDEBUG
INC=-I.
CFLAGS=-g -O2 -Wextra $(DEBUG) $(INC)
-LIBS=
+LIBS= -lcg
+LDFLAGS= -L .
-all: cgconfig
+all: cgconfig libcg.so
-cgconfig: config.c y.tab.c lex.yy.c libcg.h file-ops.c
- $(CC) $(CFLAGS) -o $@ y.tab.c lex.yy.c config.c file-ops.c $(LIBS)
+cgconfig: libcg.so config.c y.tab.c lex.yy.c libcg.h file-ops.c
+ $(CXX) $(CFLAGS) -o $@ y.tab.c lex.yy.c config.c file-ops.c $(LDFLAGS) $(LIBS)
y.tab.c: parse.y lex.yy.c
byacc -v -d parse.y
@@ -27,5 +28,8 @@ y.tab.c: parse.y lex.yy.c
lex.yy.c: lex.l
flex lex.l
+libcg.so: api.c libcg.h
+ $(CXX) $(CFLAGS) -shared -fPIC -o $@ api.c
+
clean:
- \rm -f y.tab.c y.tab.h lex.yy.c y.output cgconfig
+ \rm -f y.tab.c y.tab.h lex.yy.c y.output cgconfig libcg.so
diff --git a/api.c b/api.c
new file mode 100644
index 0000000..f842040
--- /dev/null
+++ b/api.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright IBM Corporation. 2007
+ *
+ * Author: Dhaval Giani <dhaval@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * TODOs:
+ * 1. Convert comments to Docbook style.
+ * 2. Add more APIs for the control groups.
+ * 3. Handle the configuration related APIs.
+ * 4. Error handling.
+ *
+ * Code initiated and designed by Dhaval Giani. All faults are most likely
+ * his mistake.
+ */
+
+#include <errno.h>
+#include <libcg.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static char MOUNT_POINT[FILENAME_MAX];
+
+int cg_init()
+{
+ FILE *proc_mount;
+ struct mntent *ent;
+
+ proc_mount = fopen("/proc/mounts", "r");
+ ent = getmntent(proc_mount);
+
+ while (strcmp(ent->mnt_fsname,"cgroup") != 0) {
+ ent = getmntent(proc_mount);
+ if (ent == NULL)
+ return ECGROUPNOTMOUNTED;
+ }
+ strcpy(MOUNT_POINT, ent->mnt_dir);
+ return 0;
+}
+
+static int cg_test_mounted_fs()
+{
+ FILE *proc_mount;
+ struct mntent *ent;
+
+ proc_mount = fopen("/proc/mounts", "r");
+ if (proc_mount == NULL) {
+ return -1;
+ }
+ ent = getmntent(proc_mount);
+
+ while (strcmp(ent->mnt_fsname, "cgroup") !=0) {
+ ent = getmntent(proc_mount);
+ if (ent == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+static inline pid_t cg_gettid()
+{
+ return syscall(__NR_gettid);
+}
+
+/*
+ */
+int cg_attach_task_pid(char *cgroup, pid_t tid)
+{
+ char path[FILENAME_MAX];
+ FILE *tasks;
+
+ if (cgroup == NULL) {
+ cgroup = (char *) malloc(sizeof(char));
+ cgroup = "\0";
+ }
+
+ strcpy(path, MOUNT_POINT);
+ strcat(path, "/");
+ strcat(path, cgroup);
+ strcat(path, "/tasks");
+
+ tasks = fopen(path, "w");
+ if (!tasks) {
+ switch (errno) {
+ case EPERM:
+ return ECGROUPNOTOWNER;
+ default:
+ return ECGROUPNOTALLOWED;
+ }
+ }
+ fprintf(tasks, "%d", tid);
+
+ return 0;
+
+}
+
+/*
+ * Used to attach the task to a control group.
+ *
+ * WARNING: Will change to use struct cgroup when it is implemented.
+ */
+int cg_attach_task(char *cgroup)
+{
+ pid_t tid = cg_gettid();
+ int error;
+
+ error = cg_attach_task_pid(cgroup, tid);
+
+ return error;
+}
+
+/*
+ * create_control_group()
+ * This is the basic function used to create the control group. This function
+ * just makes the group. It does not set any permissions, or any control values.
+ * The argument path is the fully qualified path name to make it generic.
+ */
+static int cg_create_control_group(char *path)
+{
+ int error;
+ if (!cg_test_mounted_fs())
+ return ECGROUPNOTMOUNTED;
+ error = mkdir(path, 0700);
+ if (!error) {
+ switch(errno) {
+ case EPERM:
+ return ECGROUPNOTOWNER;
+ default:
+ return ECGROUPNOTALLOWED;
+ }
+ }
+ return error;
+}
+
+/*
+ * set_control_value()
+ * This is the low level function for putting in a value in a control file.
+ * This function takes in the complete path and sets the value in val in that
+ * file.
+ *
+ * TODO:
+ * At this point I am not sure what all values the control file can take. So
+ * I put in an int arg. But this has to be made much more robust.
+ */
+static int cg_set_control_value(char *path, char *val)
+{
+ int error;
+ FILE *control_file;
+ if (!cg_test_mounted_fs())
+ return ECGROUPNOTMOUNTED;
+
+ control_file = fopen(path, "a");
+
+ if (!control_file) {
+ if (errno == EPERM) {
+ /*
+ * We need to set the correct error value, does the
+ * group exist but we don't have the subsystem
+ * mounted at that point, or is it that the group
+ * does not exist. So we check if the tasks file
+ * exist. Before that, we need to extract the path.
+ */
+ int len = strlen(path);
+
+ while (*(path+len) != '/')
+ len--;
+ *(path+len+1) = '\0';
+ strcat(path, "tasks");
+ control_file = fopen(path, "r");
+ if (!control_file) {
+ if (errno == ENOENT)
+ return ECGROUPSUBSYSNOTMOUNTED;
+ }
+ return ECGROUPNOTALLOWED;
+ }
+ }
+
+ fprintf(control_file, "%s", val);
+ return 0;
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int modify_cgroup(struct cgroup *original, struct cgroup *final);
+ *
+ * where original is the cgroup which is to be modified and final is how it
+ * should look.
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+
+int cg_modify_cgroup(char *cgroup, struct control_value *values[], int n)
+{
+ char path[FILENAME_MAX], base[FILENAME_MAX];
+ int i;
+ int error;
+
+ strcpy(base, MOUNT_POINT);
+ strcat(base, "/");
+ strcat(base, cgroup);
+ strcat(base, "/");
+
+ for (i = 0; i < n; i++, strcpy(path, base)) {
+ strcat(path, values[i]->name);
+ error = cg_set_control_value(path, values[i]->value);
+ if (error)
+ goto err;
+ }
+ return 0;
+err:
+ return error;
+
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int create_cgroup(struct cgroup *group);
+ *
+ * where group is the group to be created
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+int cg_create_cgroup(char *cgroup, struct control_value *values[], int n)
+{
+ char path[FILENAME_MAX], base[FILENAME_MAX];
+ int i;
+ int error;
+
+ if (MOUNT_POINT == NULL)
+ return ECGROUPNOTMOUNTED;
+
+ strcpy(path, MOUNT_POINT);
+ strcat(path, "/");
+ strcat(path, cgroup);
+
+ error = cg_create_control_group(path);
+ strcat(path, "/");
+ strcpy(base, path);
+
+ for (i = 0; i < n; i++, strcpy(path, base)) {
+ strcat(path, values[i]->name);
+ error = cg_set_control_value(path, values[i]->value);
+ if (!error)
+ return error;
+ }
+ return error;
+}
+
+/*
+ * WARNING: This API is not final. It WILL change format to use
+ * struct cgroup. This API will then become internal and be called something
+ * else.
+ *
+ * I am still not happy with how the data structure is looking at the moment,
+ * plus there are a couple of additional details to be worked out. Please
+ * do not rely on this API.
+ *
+ * Be prepared to change the implementation later once it shifts to
+ * struct cgroup in the real alpha release.
+ *
+ * The final version is expected to be
+ *
+ * int delete_cgroup(struct cgroup *group);
+ *
+ * where group is the group to be deleted.
+ *
+ * Also this version is still at one level since we do not have
+ * multi-hierarchy support in kernel. The real alpha release should have this
+ * issue sorted out as well.
+ */
+int cg_delete_cgroup(char *cgroup)
+{
+ FILE *delete_tasks, *base_tasks;
+ int tids;
+ char path[FILENAME_MAX];
+ int error;
+
+ strcpy(path, MOUNT_POINT);
+ strcat(path,"/tasks");
+
+ base_tasks = fopen(path, "w");
+
+ strcpy(path, MOUNT_POINT);
+ strcat(path, "/");
+ strcat(path, cgroup);
+ strcat(path,"/tasks");
+
+ delete_tasks = fopen(path, "r");
+
+ while (!feof(delete_tasks)) {
+ fscanf(delete_tasks, "%d", &tids);
+ fprintf(base_tasks, "%d", tids);
+ }
+
+ strcpy(path, MOUNT_POINT);
+ strcat(path, "/");
+ strcat(path, cgroup);
+
+ error = rmdir(path);
+
+ if (!error) {
+ return ECGROUPNOTALLOWED;
+ }
+
+ return error;
+}
diff --git a/libcg.h b/libcg.h
index 8fcda81..91496ca 100644
--- a/libcg.h
+++ b/libcg.h
@@ -16,11 +16,21 @@
#ifndef _LIBCG_H
#define _LIBCG_H
+#include <features.h>
+
+__BEGIN_DECLS
+
#include <grp.h>
+#include <stdio.h>
#include <sys/stat.h>
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
+
+#ifndef __USE_GNU
#define __USE_GNU
+#endif
/* Maximum number of mount points/controllers */
#define MAX_MNT_ELEMENTS 8
@@ -92,6 +102,16 @@ enum cg_msg_type {
CG_MSG_DONE,
};
+enum cg_errors {
+ ECGROUPNOTCOMPILED=50000,
+ ECGROUPNOTMOUNTED,
+ ECGROUPNOTEXIST,
+ ECGROUPNOTCREATED,
+ ECGROUPSUBSYSNOTMOUNTED,
+ ECGROUPNOTOWNER,
+ ECGROUPNOTALLOWED, // This is the stock error. Default error.
+};
+
#define CG_MAX_MSG_SIZE 256
#define CG_SERVER_MSG_PATH "/tmp/control_group"
#define CG_BACKLOG 5
@@ -118,4 +138,19 @@ int cg_mount_controllers(void);
int cg_unmount_controllers(void);
int cg_load_config(const char *pathname);
void cg_unload_current_config(void);
+
+/* Functions and structures that can be used by the application*/
+struct control_value {
+ char name[FILENAME_MAX];
+ char *value;
+};
+
+int cg_init(void);
+int cg_attach_task(char *cgroup);
+int cg_modify_cgroup(char *cgroup, struct control_value *values[], int n);
+int cg_create_cgroup(char *cgroup, struct control_value *values[], int n);
+int cg_delete_cgroup(char *cgroup);
+
+__END_DECLS
+
#endif /* _LIBCG_H */