Cgroup: add cgroup members's exit data statistics
Subsystems (3)
PATCH 1/1 Cgroup: add cgroup members's exit data statistics
From: Marco Stornelli <[email protected]>
This patch adds the possibility for an application to receive statistics information only for processes belonging to a cgroup. The mechanism is the same of the cpu's exit data statistics. With this patch, instead of waiting on a specific cpumask, an application can wait for exit data on a specific container. Through this patch it's possible to have a simple death notifier mechanism. We can select the processes to watch and wait for their death. A death notify mechanism is especially useful for embedded systems.
Signed-off-by Marco Stornelli <[email protected]>
---
Documentation/accounting/getdelays.c +42 -5
@@ -77,9 +77,11 @@ static void usage(void) "[-m cpumask] [-t tgid] [-p pid]\n");fprintf (stderr," -d: print delayacct stats\n" );fprintf (stderr," -i: print IO accounting (works only with -p)\n" ); +fprintf (stderr," -q: print context switch accounting\n" );fprintf (stderr," -l: listen forever\n" );fprintf (stderr," -v: debug on\n" ); -fprintf (stderr," -C: container path\n" ); +fprintf (stderr," -C: container path (container statistics)\n" ); +fprintf (stderr," -N: container path (death notify)\n" ); }/*
@@ -263,13 +265,14 @@ int main(int argc, char *argv[])char *logfile =NULL ;int loop =0 ;int containerset =0 ; +int containernotify =0 ;char containerpath[1024 ];int cfd =0 ;struct msgtemplate msg;while (1 ) { - c =getopt (argc, argv,"qdiw:r:m:t:p:vlC:" ); + c =getopt (argc, argv,"qdiw:r:m:t:p:vlC:N:" );if (c <0 )break ;
@@ -290,6 +293,10 @@ int main(int argc, char *argv[]) containerset =1 ;strncpy (containerpath, optarg,strlen (optarg) +1 );break ; +case 'N' : + containernotify =1 ; +strncpy (containerpath, optarg,strlen (optarg) +1 ); +break ;case 'w' : logfile =strdup (optarg);printf ("write to file %s\n" , logfile);
@@ -364,8 +371,13 @@ int main(int argc, char *argv[]) } } -if (tid && containerset) { -fprintf (stderr,"Select either -t or -C, not both\n" ); +if (tid && (containerset || containernotify)) { +fprintf (stderr,"Select either -t or -C or -N\n" ); + goto err; + } + +if (containerset && containernotify) { +fprintf (stderr,"Select either -C or -N, not both\n" ); goto err; }
@@ -392,7 +404,23 @@ int main(int argc, char *argv[]) goto err; } } -if (!maskset && !tid && !containerset) { + +if (containernotify) { + cfd =open (containerpath,O_RDONLY ); +if (cfd <0 ) { +perror ("error opening container file" ); + goto err; + } + rc =send_cmd (nl_sd, id, mypid,CGROUPSTATS_CMD_GET , +CGROUPSTATS_CMD_ATTR_REGISTER_FD , + &cfd,sizeof (__u32)); +if (rc <0 ) { +perror ("error sending cgroupstats command" ); + goto err; + } + } + +if (!maskset && !tid && !containerset && !containernotify) {usage (); goto err; }
@@ -400,6 +428,7 @@ int main(int argc, char *argv[]) do { int i; + PRINTF("Recv...\n"); rep_len = recv(nl_sd, &msg, sizeof(msg), 0); PRINTF("received %d bytes\n", rep_len);
@@ -495,6 +524,14 @@ done:if (rc <0 )err (rc,"error sending deregister cpumask\n" ); } +if (containernotify) { + rc =send_cmd (nl_sd, id, mypid,CGROUPSTATS_CMD_GET , +CGROUPSTATS_CMD_ATTR_DEREGISTER_FD , + &cfd,sizeof (__u32)); +printf ("Sent deregister container, retval %d\n" , rc); +if (rc <0 ) +err (rc,"error sending deregister container\n" ); + } err:close (nl_sd);if (fd)
kernel/taskstats.c +167 -3
238 lines not on this page · raw message
kernel/cgroup.c +38 -0
@@ -2040,6 +2040,44 @@ static int pid_array_load(pid_t *pidarra }/** +* cgroup_verify_pid - it verifies if a pid is in a cgroup +* @dentry: A dentry entry belonging to the cgroup for which stats have +* been requested. +* +* Return value can be < 0 for error, 0 not pid not found, > 0 pid found +*/ +int cgroup_verify_pid (pid_t pid,struct dentry *dentry) +{ +int ret = -EINVAL ; +struct cgroup *cgrp; +struct cgroup_iter it; +struct task_struct *tsk; + +/* +* Validate dentry by checking the superblock operations, +* and make sure it's a directory. +*/ +if (dentry->d_sb->s_op != &cgroup_ops || + !S_ISDIR (dentry->d_inode->i_mode)) + goto err; + + ret =0 ; + cgrp = dentry->d_fsdata; + +cgroup_iter_start (cgrp, &it); +while ((tsk =cgroup_iter_next (cgrp, &it))) { +if (tsk->pid == pid) { +cgroup_iter_end (cgrp, &it); +return 1 ; + } + } +cgroup_iter_end (cgrp, &it); + +err: +return ret; +} + +/** * cgroupstats_build - build and fill cgroupstats * @stats: cgroupstats to fill information into * @dentry: A dentry entry belonging to the cgroup for which stats have
include/linux/cgroup.h +5 -0
@@ -32,6 +32,7 @@ extern void cgroup_fork(struct task_struextern void cgroup_fork_callbacks (struct task_struct *p);extern void cgroup_post_fork (struct task_struct *p);extern void cgroup_exit (struct task_struct *p,int run_callbacks); +extern int cgroup_verify_pid (pid_t pid,struct dentry *dentry);extern int cgroupstats_build (struct cgroupstats *stats,struct dentry *dentry);
@@ -450,6 +451,10 @@ static inline void cgroup_exit(struct tastatic inline void cgroup_lock (void ) {}static inline void cgroup_unlock (void ) {} +static inline int cgroup_verify_pid (pid_t pid,struct dentry *dentry) +{ +return -EINVAL ; +}static inline int cgroupstats_build (struct cgroupstats *stats,struct dentry *dentry) {
include/linux/cgroupstats.h +2 -0
@@ -63,6 +63,8 @@ enum {enum {CGROUPSTATS_CMD_ATTR_UNSPEC =0 ,CGROUPSTATS_CMD_ATTR_FD , +CGROUPSTATS_CMD_ATTR_REGISTER_FD , +CGROUPSTATS_CMD_ATTR_DEREGISTER_FD , __CGROUPSTATS_CMD_ATTR_MAX, };
include/linux/taskstats.h +3 -0
@@ -37,6 +37,9 @@#define TS_COMM_LEN 32/* should be >= TASK_COMM_LEN * in linux/sched.h */ +#define CPU_TARGET 0x1 +#define CGROUP_TARGET 0x2 +struct taskstats {/* The version number of this struct. This field is always set to