summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author\"Ken'ichi Ohmichi\ <oomichi@mxs.nes.nec.co.jp>2009-05-08 01:46:02 +0530
committerBalbir Singh <balbir@linux.vnet.ibm.com>2009-05-08 01:46:02 +0530
commit8953fc07c0498d1ddd9a04dc549ffb85862f4c5f (patch)
tree173db54f5d559bccf423b79c9464bd4d29ede084
parent485fe65a0daa23899d1e4c02620036a265560a57 (diff)
downloadlibcg-8953fc07c0498d1ddd9a04dc549ffb85862f4c5f.tar.gz
libcg-8953fc07c0498d1ddd9a04dc549ffb85862f4c5f.tar.xz
libcg-8953fc07c0498d1ddd9a04dc549ffb85862f4c5f.zip
Changelog v2:
* Use clock_gettime(2) for getting timestamp since a system boot. * Change parent_info's memory to dynamic allocation. This patch is for changing the cgroup of a forked process while parent changing. This patch adds the following sequence: 1. Store both the timestamp and the process-id when changing the cgroup. 2. If receiving a PROC_EVENT_FORK packet, check its parent-pid and its timestamp. 3. If its parent-pid and the stored process-id are same and its timestamp is older than the stored timestamp, change the cgroup of forked process. Thanks Ken'ichi Ohmichi Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
-rw-r--r--src/daemon/Makefile.am2
-rw-r--r--src/daemon/cgrulesengd.c104
2 files changed, 105 insertions, 1 deletions
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 17d31d9..f0c9b92 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -2,5 +2,5 @@ INCLUDES = -I $(top_srcdir)/include
sbin_PROGRAMS = cgrulesengd
cgrulesengd_SOURCES = cgrulesengd.c cgrulesengd.h
-cgrulesengd_LDADD = $(top_srcdir)/src/.libs/libcgroup.la
+cgrulesengd_LDADD = $(top_srcdir)/src/.libs/libcgroup.la -lrt
cgrulesengd_LDFLAGS = -L$(top_srcdir)/src/.libs
diff --git a/src/daemon/cgrulesengd.c b/src/daemon/cgrulesengd.c
index 74d12e1..07d4a5d 100644
--- a/src/daemon/cgrulesengd.c
+++ b/src/daemon/cgrulesengd.c
@@ -180,6 +180,91 @@ static int cgre_get_euid_egid_from_status(pid_t pid, uid_t *euid, gid_t *egid)
return 0;
}
+struct parent_info {
+ __u64 timestamp;
+ pid_t pid;
+};
+struct array_parent_info {
+ int index;
+ int num_allocation;
+ struct parent_info **parent_info;
+};
+struct array_parent_info array_pi;
+
+static int cgre_store_parent_info(pid_t pid)
+{
+ __u64 uptime_ns;
+ struct timespec tp;
+ struct parent_info *info;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) {
+ flog(LOG_WARNING, "Failed to get time");
+ return 1;
+ }
+ 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.parent_info = realloc(array_pi.parent_info,
+ sizeof(info) * array_pi.num_allocation);
+ if (!array_pi.parent_info) {
+ flog(LOG_WARNING, "Failed to allocate memory");
+ return 1;
+ }
+ }
+ info = calloc(1, sizeof(struct parent_info));
+ if (!info) {
+ flog(LOG_WARNING, "Failed to allocate memory");
+ return 1;
+ }
+ info->timestamp = uptime_ns;
+ info->pid = pid;
+
+ array_pi.parent_info[array_pi.index] = info;
+ array_pi.index++;
+
+ return 0;
+}
+
+static void cgre_remove_old_parent_info(__u64 key_timestamp)
+{
+ int i, j;
+
+ for (i = 0; i < array_pi.index; i++) {
+ if (key_timestamp < array_pi.parent_info[i]->timestamp)
+ continue;
+ free(array_pi.parent_info[i]);
+ for (j = i; j < array_pi.index - 1; j++)
+ array_pi.parent_info[j] = array_pi.parent_info[j + 1];
+ array_pi.index--;
+ i--;
+ }
+ return;
+}
+
+static int cgre_was_parent_changed_when_forking(const struct proc_event *ev)
+{
+ int i;
+ pid_t parent_pid;
+ __u64 timestamp_child;
+ __u64 timestamp_parent;
+
+ parent_pid = ev->event_data.fork.parent_pid;
+ timestamp_child = ev->timestamp_ns;
+
+ cgre_remove_old_parent_info(timestamp_child);
+
+ for (i = 0; i < array_pi.index; i++) {
+ if (parent_pid != array_pi.parent_info[i]->pid)
+ continue;
+ timestamp_parent = array_pi.parent_info[i]->timestamp;
+ if (timestamp_child > timestamp_parent)
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
/**
* Process an event from the kernel, and determine the correct UID/GID/PID to
* pass to libcgroup. Then, libcgroup will decide the cgroup to move the PID
@@ -201,6 +286,15 @@ int cgre_process_event(const struct proc_event *ev, const int type)
case PROC_EVENT_GID:
pid = ev->event_data.id.process_pid;
break;
+ case PROC_EVENT_FORK:
+ /*
+ * If this process was forked while changing parent's cgroup,
+ * this process's cgroup also should be changed.
+ */
+ if (!cgre_was_parent_changed_when_forking(ev))
+ return 0;
+ pid = ev->event_data.fork.child_pid;
+ break;
default:
break;
}
@@ -229,6 +323,12 @@ int cgre_process_event(const struct proc_event *ev, const int type)
ev->event_data.id.e.egid,
pid, CGFLAG_USECACHE);
break;
+ case PROC_EVENT_FORK:
+ log_uid = euid;
+ log_gid = egid;
+ ret = cgroup_change_cgroup_uid_gid_flags(euid,
+ egid, pid, CGFLAG_USECACHE);
+ break;
default:
break;
}
@@ -242,6 +342,7 @@ int cgre_process_event(const struct proc_event *ev, const int type)
" FAILED! (Error Code: %d)", log_pid, log_uid, log_gid,
ret);
} else {
+ ret = cgre_store_parent_info(pid);
flog(LOG_INFO, "Cgroup change for PID: %d, UID: %d, GID: %d OK",
log_pid, log_uid, log_gid);
}
@@ -282,6 +383,9 @@ int cgre_handle_msg(struct cn_msg *cn_hdr)
ev->event_data.id.e.egid);
ret = cgre_process_event(ev, PROC_EVENT_GID);
break;
+ case PROC_EVENT_FORK:
+ ret = cgre_process_event(ev, PROC_EVENT_FORK);
+ break;
default:
break;
}