summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>2009-06-26 14:50:54 +0900
committerDhaval Giani <dhaval@linux.vnet.ibm.com>2009-06-29 16:47:32 +0530
commitafbbee67863b4debf4ec849ff3d6a3f1f21b73ef (patch)
tree63abe776b5ff43301e3db38c4c1a482c100bb541
parent2d10aa26dc974ab2f838bc170a7ff1608f0cf8a6 (diff)
downloadlibcg-afbbee67863b4debf4ec849ff3d6a3f1f21b73ef.tar.gz
libcg-afbbee67863b4debf4ec849ff3d6a3f1f21b73ef.tar.xz
libcg-afbbee67863b4debf4ec849ff3d6a3f1f21b73ef.zip
Add the handler of unchanged process to cgrulesengd daemon.
Hi, Changelog of v6: ================ * No change. Changelog of v5: ================ * No change. Changelog of v4: ================ * Add the comment "FIXME: Change the temporary file to configurable one." * Define the number of allocation. Changelog of v3: ================ * Set the value 0x1 to CGROUP_DAEMON_UNCHANGE_CHILDREN flag. Changelog of v2: ================ * New patch. Description: ============ This patch adds the handler of unchanged process to the cgrulesengd daemon. By this patch, the daemon does not change a process which is executed by 'cgexec' command, because it is possible to notify the unchanged process to the daemon by using "unix domain socket". Thanks Ken'ichi Ohmichi Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
-rw-r--r--include/libcgroup.h8
-rw-r--r--src/daemon/cgrulesengd.c203
2 files changed, 206 insertions, 5 deletions
diff --git a/include/libcgroup.h b/include/libcgroup.h
index a9799ab..8707412 100644
--- a/include/libcgroup.h
+++ b/include/libcgroup.h
@@ -52,6 +52,10 @@ __BEGIN_DECLS
#define CGRULE_INVALID (-1)
#define CGRULE_WILD (-2)
+/* FIXME: Change the temporary file to configurable one. */
+#define CGRULE_CGRED_TEMP_FILE "/tmp/cgred"
+#define CGRULE_SUCCESS_STORE_PID "SUCCESS_STORE_PID"
+
/* Flags for cgroup_change_cgroup_uid_gid() */
enum cgflags {
CGFLAG_USECACHE = 0x01,
@@ -108,6 +112,10 @@ enum cgroup_file_type {
CGROUP_FILE_TYPE_OTHER, /* Directory */
};
+enum cgroup_daemon_type {
+ CGROUP_DAEMON_UNCHANGE_CHILDREN = 0x1,
+};
+
struct cgroup_file_info {
enum cgroup_file_type type;
const char *path;
diff --git a/src/daemon/cgrulesengd.c b/src/daemon/cgrulesengd.c
index c83532d..2ca6631 100644
--- a/src/daemon/cgrulesengd.c
+++ b/src/daemon/cgrulesengd.c
@@ -49,9 +49,13 @@
#include <getopt.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>
+#include <linux/un.h>
+
+#define NUM_PER_REALLOCATIOM (100)
/* Log file, NULL if logging to file is disabled */
FILE* logfile;
@@ -165,7 +169,7 @@ static int cgre_store_parent_info(pid_t pid)
uptime_ns = ((__u64)tp.tv_sec * 1000 * 1000 * 1000 ) + tp.tv_nsec;
if (array_pi.index >= array_pi.num_allocation) {
- array_pi.num_allocation += 100;
+ array_pi.num_allocation += NUM_PER_REALLOCATIOM;
array_pi.parent_info = realloc(array_pi.parent_info,
sizeof(info) * array_pi.num_allocation);
if (!array_pi.parent_info) {
@@ -226,6 +230,90 @@ static int cgre_was_parent_changed_when_forking(const struct proc_event *ev)
return 0;
}
+struct unchanged_pid {
+ pid_t pid;
+ int flags;
+} unchanged_pid_t;
+
+struct array_unchanged {
+ int index;
+ int num_allocation;
+ struct unchanged_pid *proc;
+};
+
+struct array_unchanged array_unch;
+
+static int cgre_store_unchanged_process(pid_t pid, int flags)
+{
+ int i;
+
+ for (i = 0; i < array_unch.index; i++) {
+ if (array_unch.proc[i].pid != pid)
+ continue;
+ /* pid is stored already. */
+ return 0;
+ }
+ if (array_unch.index >= array_unch.num_allocation) {
+ array_unch.num_allocation += NUM_PER_REALLOCATIOM;
+ array_unch.proc = realloc(array_unch.proc,
+ sizeof(unchanged_pid_t) * array_unch.num_allocation);
+ if (!array_unch.proc) {
+ flog(LOG_WARNING, "Failed to allocate memory");
+ return 1;
+ }
+ }
+ array_unch.proc[array_unch.index].pid = pid;
+ array_unch.proc[array_unch.index].flags = flags;
+ array_unch.index++;
+ flog(LOG_DEBUG, "Store the unchanged process (PID: %d, FLAGS: %d)",
+ pid, flags);
+ return 0;
+}
+
+static void cgre_remove_unchanged_process(pid_t pid)
+{
+ int i, j;
+
+ for (i = 0; i < array_unch.index; i++) {
+ if (array_unch.proc[i].pid != pid)
+ continue;
+ for (j = i; j < array_unch.index - 1; j++)
+ memcpy(&array_unch.proc[j],
+ &array_unch.proc[j + 1],
+ sizeof(struct unchanged_pid));
+ array_unch.index--;
+ flog(LOG_DEBUG, "Remove the unchanged process (PID: %d)", pid);
+ break;
+ }
+ return;
+}
+
+static int cgre_is_unchanged_process(pid_t pid)
+{
+ int i;
+
+ for (i = 0; i < array_unch.index; i++) {
+ if (array_unch.proc[i].pid != pid)
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+static int cgre_is_unchanged_child(pid_t pid)
+{
+ int i;
+
+ for (i = 0; i < array_unch.index; i++) {
+ if (array_unch.proc[i].pid != pid)
+ continue;
+ if (array_unch.proc[i].flags & CGROUP_DAEMON_UNCHANGE_CHILDREN)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
static int cgre_change_cgroup(const uid_t uid, const gid_t gid, char *procname,
const pid_t pid)
{
@@ -258,6 +346,7 @@ static int cgre_change_cgroup(const uid_t uid, const gid_t gid, char *procname,
int cgre_process_event(const struct proc_event *ev, const int type)
{
char *procname;
+ pid_t ppid, cpid;
pid_t pid = 0, log_pid = 0;
uid_t euid, log_uid = 0;
gid_t egid, log_gid = 0;
@@ -270,6 +359,14 @@ int cgre_process_event(const struct proc_event *ev, const int type)
pid = ev->event_data.id.process_pid;
break;
case PROC_EVENT_FORK:
+ ppid = ev->event_data.fork.parent_pid;
+ cpid = ev->event_data.fork.child_pid;
+ if (cgre_is_unchanged_child(ppid)) {
+ if (cgre_store_unchanged_process(cpid,
+ CGROUP_DAEMON_UNCHANGE_CHILDREN))
+ return 1;
+ }
+
/*
* If this process was forked while changing parent's cgroup,
* this process's cgroup also should be changed.
@@ -278,7 +375,16 @@ int cgre_process_event(const struct proc_event *ev, const int type)
return 0;
pid = ev->event_data.fork.child_pid;
break;
+ case PROC_EVENT_EXIT:
+ cgre_remove_unchanged_process(ev->event_data.exit.process_pid);
+ return 0;
case PROC_EVENT_EXEC:
+ /*
+ * If the unchanged process, the daemon should not change the
+ * cgroup of the process.
+ */
+ if (cgre_is_unchanged_process(ev->event_data.exec.process_pid))
+ return 0;
pid = ev->event_data.exec.process_pid;
break;
default:
@@ -380,6 +486,9 @@ int cgre_handle_msg(struct cn_msg *cn_hdr)
case PROC_EVENT_FORK:
ret = cgre_process_event(ev, PROC_EVENT_FORK);
break;
+ case PROC_EVENT_EXIT:
+ ret = cgre_process_event(ev, PROC_EVENT_EXIT);
+ break;
case PROC_EVENT_EXEC:
flog(LOG_DEBUG, "EXEC Event: PID = %d, tGID = %d",
ev->event_data.exec.process_pid,
@@ -439,15 +548,59 @@ int cgre_receive_netlink_msg(int sk_nl)
return 0;
}
+void cgre_receive_unix_domain_msg(int sk_unix)
+{
+ int flags;
+ int fd_client;
+ pid_t pid;
+ struct sockaddr_un caddr;
+ socklen_t caddr_len;
+ struct stat buff_stat;
+ char path[FILENAME_MAX];
+
+ caddr_len = sizeof(caddr);
+ fd_client = accept(sk_unix, (struct sockaddr *)&caddr, &caddr_len);
+ if (fd_client < 0) {
+ cgroup_dbg("accept error");
+ return;
+ }
+ if (read(fd_client, &pid, sizeof(pid)) < 0) {
+ cgroup_dbg("read error");
+ goto close;
+ }
+ sprintf(path, "/proc/%d", pid);
+ if (stat(path, &buff_stat)) {
+ cgroup_dbg("There is not such process (PID: %d)", pid);
+ goto close;
+ }
+ if (read(fd_client, &flags, sizeof(flags)) < 0) {
+ cgroup_dbg("read error");
+ goto close;
+ }
+ if (cgre_store_unchanged_process(pid, flags))
+ goto close;
+
+ if (write(fd_client, CGRULE_SUCCESS_STORE_PID,
+ sizeof(CGRULE_SUCCESS_STORE_PID)) < 0) {
+ cgroup_dbg("write error");
+ goto close;
+ }
+close:
+ close(fd_client);
+ return;
+}
+
int cgre_create_netlink_socket_process_msg()
{
- int sk_nl;
+ int sk_nl = 0, sk_unix = 0, sk_max;
struct sockaddr_nl my_nla;
char buff[BUFF_SIZE];
int rc = -1;
struct nlmsghdr *nl_hdr;
struct cn_msg *cn_hdr;
enum proc_cn_mcast_op *mcop_msg;
+ struct sockaddr_un saddr;
+ fd_set fds, readfds;
/*
* Create an endpoint for communication. Use the kernel user
@@ -499,13 +652,53 @@ int cgre_create_netlink_socket_process_msg()
}
cgroup_dbg("sent\n");
+ /*
+ * Setup Unix domain socket.
+ */
+ sk_unix = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sk_unix < 0) {
+ cgroup_dbg("socket sk_unix error");
+ goto close_and_exit;
+ }
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sun_family = AF_UNIX;
+ strcpy(saddr.sun_path, CGRULE_CGRED_TEMP_FILE);
+ unlink(CGRULE_CGRED_TEMP_FILE);
+ if (bind(sk_unix, (struct sockaddr *)&saddr,
+ sizeof(saddr.sun_family) + strlen(CGRULE_CGRED_TEMP_FILE)) < 0) {
+ cgroup_dbg("binding sk_unix error");
+ goto close_and_exit;
+ }
+ if (listen(sk_unix, 1) < 0) {
+ cgroup_dbg("listening sk_unix error");
+ goto close_and_exit;
+ }
+ FD_ZERO(&readfds);
+ FD_SET(sk_nl, &readfds);
+ FD_SET(sk_unix, &readfds);
+ if (sk_nl < sk_unix)
+ sk_max = sk_unix;
+ else
+ sk_max = sk_nl;
for(;;) {
- if (cgre_receive_netlink_msg(sk_nl))
- break;
+ memcpy(&fds, &readfds, sizeof(fd_set));
+ if (select(sk_max + 1, &fds, NULL, NULL, NULL) < 0) {
+ cgroup_dbg("selecting error");
+ goto close_and_exit;
+ }
+ if (FD_ISSET(sk_nl, &fds)) {
+ if (cgre_receive_netlink_msg(sk_nl))
+ break;
+ }
+ if (FD_ISSET(sk_unix, &fds))
+ cgre_receive_unix_domain_msg(sk_unix);
}
close_and_exit:
- close(sk_nl);
+ if (sk_nl)
+ close(sk_nl);
+ if (sk_unix)
+ close(sk_unix);
return rc;
}