diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cgroup.c | 55 | ||||
-rw-r--r-- | kernel/taskstats.c | 67 |
2 files changed, 122 insertions, 0 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index d65a1246829f..ca38db223f84 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -44,6 +44,9 @@ | |||
44 | #include <linux/string.h> | 44 | #include <linux/string.h> |
45 | #include <linux/sort.h> | 45 | #include <linux/sort.h> |
46 | #include <linux/kmod.h> | 46 | #include <linux/kmod.h> |
47 | #include <linux/delayacct.h> | ||
48 | #include <linux/cgroupstats.h> | ||
49 | |||
47 | #include <asm/atomic.h> | 50 | #include <asm/atomic.h> |
48 | 51 | ||
49 | static DEFINE_MUTEX(cgroup_mutex); | 52 | static DEFINE_MUTEX(cgroup_mutex); |
@@ -1766,6 +1769,58 @@ static int pid_array_load(pid_t *pidarray, int npids, struct cgroup *cont) | |||
1766 | return n; | 1769 | return n; |
1767 | } | 1770 | } |
1768 | 1771 | ||
1772 | /** | ||
1773 | * Build and fill cgroupstats so that taskstats can export it to user | ||
1774 | * space. | ||
1775 | * | ||
1776 | * @stats: cgroupstats to fill information into | ||
1777 | * @dentry: A dentry entry belonging to the cgroup for which stats have | ||
1778 | * been requested. | ||
1779 | */ | ||
1780 | int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry) | ||
1781 | { | ||
1782 | int ret = -EINVAL; | ||
1783 | struct cgroup *cont; | ||
1784 | struct cgroup_iter it; | ||
1785 | struct task_struct *tsk; | ||
1786 | /* | ||
1787 | * Validate dentry by checking the superblock operations | ||
1788 | */ | ||
1789 | if (dentry->d_sb->s_op != &cgroup_ops) | ||
1790 | goto err; | ||
1791 | |||
1792 | ret = 0; | ||
1793 | cont = dentry->d_fsdata; | ||
1794 | rcu_read_lock(); | ||
1795 | |||
1796 | cgroup_iter_start(cont, &it); | ||
1797 | while ((tsk = cgroup_iter_next(cont, &it))) { | ||
1798 | switch (tsk->state) { | ||
1799 | case TASK_RUNNING: | ||
1800 | stats->nr_running++; | ||
1801 | break; | ||
1802 | case TASK_INTERRUPTIBLE: | ||
1803 | stats->nr_sleeping++; | ||
1804 | break; | ||
1805 | case TASK_UNINTERRUPTIBLE: | ||
1806 | stats->nr_uninterruptible++; | ||
1807 | break; | ||
1808 | case TASK_STOPPED: | ||
1809 | stats->nr_stopped++; | ||
1810 | break; | ||
1811 | default: | ||
1812 | if (delayacct_is_task_waiting_on_io(tsk)) | ||
1813 | stats->nr_io_wait++; | ||
1814 | break; | ||
1815 | } | ||
1816 | } | ||
1817 | cgroup_iter_end(cont, &it); | ||
1818 | |||
1819 | rcu_read_unlock(); | ||
1820 | err: | ||
1821 | return ret; | ||
1822 | } | ||
1823 | |||
1769 | static int cmppid(const void *a, const void *b) | 1824 | static int cmppid(const void *a, const void *b) |
1770 | { | 1825 | { |
1771 | return *(pid_t *)a - *(pid_t *)b; | 1826 | return *(pid_t *)a - *(pid_t *)b; |
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 7d4d7f9c1bb2..9f360f68aad6 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -22,6 +22,10 @@ | |||
22 | #include <linux/delayacct.h> | 22 | #include <linux/delayacct.h> |
23 | #include <linux/cpumask.h> | 23 | #include <linux/cpumask.h> |
24 | #include <linux/percpu.h> | 24 | #include <linux/percpu.h> |
25 | #include <linux/cgroupstats.h> | ||
26 | #include <linux/cgroup.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/file.h> | ||
25 | #include <net/genetlink.h> | 29 | #include <net/genetlink.h> |
26 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
27 | 31 | ||
@@ -49,6 +53,11 @@ __read_mostly = { | |||
49 | [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING }, | 53 | [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING }, |
50 | [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },}; | 54 | [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },}; |
51 | 55 | ||
56 | static struct nla_policy | ||
57 | cgroupstats_cmd_get_policy[CGROUPSTATS_CMD_ATTR_MAX+1] __read_mostly = { | ||
58 | [CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 }, | ||
59 | }; | ||
60 | |||
52 | struct listener { | 61 | struct listener { |
53 | struct list_head list; | 62 | struct list_head list; |
54 | pid_t pid; | 63 | pid_t pid; |
@@ -372,6 +381,51 @@ err: | |||
372 | return NULL; | 381 | return NULL; |
373 | } | 382 | } |
374 | 383 | ||
384 | static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | ||
385 | { | ||
386 | int rc = 0; | ||
387 | struct sk_buff *rep_skb; | ||
388 | struct cgroupstats *stats; | ||
389 | struct nlattr *na; | ||
390 | size_t size; | ||
391 | u32 fd; | ||
392 | struct file *file; | ||
393 | int fput_needed; | ||
394 | |||
395 | na = info->attrs[CGROUPSTATS_CMD_ATTR_FD]; | ||
396 | if (!na) | ||
397 | return -EINVAL; | ||
398 | |||
399 | fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); | ||
400 | file = fget_light(fd, &fput_needed); | ||
401 | if (file) { | ||
402 | size = nla_total_size(sizeof(struct cgroupstats)); | ||
403 | |||
404 | rc = prepare_reply(info, CGROUPSTATS_CMD_NEW, &rep_skb, | ||
405 | size); | ||
406 | if (rc < 0) | ||
407 | goto err; | ||
408 | |||
409 | na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS, | ||
410 | sizeof(struct cgroupstats)); | ||
411 | stats = nla_data(na); | ||
412 | memset(stats, 0, sizeof(*stats)); | ||
413 | |||
414 | rc = cgroupstats_build(stats, file->f_dentry); | ||
415 | if (rc < 0) | ||
416 | goto err; | ||
417 | |||
418 | fput_light(file, fput_needed); | ||
419 | return send_reply(rep_skb, info->snd_pid); | ||
420 | } | ||
421 | |||
422 | err: | ||
423 | if (file) | ||
424 | fput_light(file, fput_needed); | ||
425 | nlmsg_free(rep_skb); | ||
426 | return rc; | ||
427 | } | ||
428 | |||
375 | static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | 429 | static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info) |
376 | { | 430 | { |
377 | int rc = 0; | 431 | int rc = 0; |
@@ -522,6 +576,12 @@ static struct genl_ops taskstats_ops = { | |||
522 | .policy = taskstats_cmd_get_policy, | 576 | .policy = taskstats_cmd_get_policy, |
523 | }; | 577 | }; |
524 | 578 | ||
579 | static struct genl_ops cgroupstats_ops = { | ||
580 | .cmd = CGROUPSTATS_CMD_GET, | ||
581 | .doit = cgroupstats_user_cmd, | ||
582 | .policy = cgroupstats_cmd_get_policy, | ||
583 | }; | ||
584 | |||
525 | /* Needed early in initialization */ | 585 | /* Needed early in initialization */ |
526 | void __init taskstats_init_early(void) | 586 | void __init taskstats_init_early(void) |
527 | { | 587 | { |
@@ -546,8 +606,15 @@ static int __init taskstats_init(void) | |||
546 | if (rc < 0) | 606 | if (rc < 0) |
547 | goto err; | 607 | goto err; |
548 | 608 | ||
609 | rc = genl_register_ops(&family, &cgroupstats_ops); | ||
610 | if (rc < 0) | ||
611 | goto err_cgroup_ops; | ||
612 | |||
549 | family_registered = 1; | 613 | family_registered = 1; |
614 | printk("registered taskstats version %d\n", TASKSTATS_GENL_VERSION); | ||
550 | return 0; | 615 | return 0; |
616 | err_cgroup_ops: | ||
617 | genl_unregister_ops(&family, &taskstats_ops); | ||
551 | err: | 618 | err: |
552 | genl_unregister_family(&family); | 619 | genl_unregister_family(&family); |
553 | return rc; | 620 | return rc; |