diff options
author | Paul Menage <menage@google.com> | 2007-10-19 02:39:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:36 -0400 |
commit | a424316ca154317367c7ddf89997d1c80e4a8051 (patch) | |
tree | ed349926c41aad5be6d62c9074ff72a0d9ac32c2 /kernel | |
parent | 697f41610863c9264a7ae26dac9a387c9dda8c84 (diff) |
Task Control Groups: add procfs interface
Add:
/proc/cgroups - general system info
/proc/*/cgroup - per-task cgroup membership info
[a.p.zijlstra@chello.nl: cgroups: bdi init hooks]
Signed-off-by: Paul Menage <menage@google.com>
Cc: Serge E. Hallyn <serue@us.ibm.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Dave Hansen <haveblue@us.ibm.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Paul Jackson <pj@sgi.com>
Cc: Kirill Korotaev <dev@openvz.org>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: Srivatsa Vaddagiri <vatsa@in.ibm.com>
Cc: Cedric Le Goater <clg@fr.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cgroup.c | 146 |
1 files changed, 143 insertions, 3 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index cc68fe68a60e..db245f19eb8a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
35 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
36 | #include <linux/proc_fs.h> | ||
36 | #include <linux/rcupdate.h> | 37 | #include <linux/rcupdate.h> |
37 | #include <linux/sched.h> | 38 | #include <linux/sched.h> |
38 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
@@ -247,13 +248,15 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode); | |||
247 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry); | 248 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry); |
248 | static int cgroup_populate_dir(struct cgroup *cont); | 249 | static int cgroup_populate_dir(struct cgroup *cont); |
249 | static struct inode_operations cgroup_dir_inode_operations; | 250 | static struct inode_operations cgroup_dir_inode_operations; |
251 | static struct file_operations proc_cgroupstats_operations; | ||
252 | |||
253 | static struct backing_dev_info cgroup_backing_dev_info = { | ||
254 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | ||
255 | }; | ||
250 | 256 | ||
251 | static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb) | 257 | static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb) |
252 | { | 258 | { |
253 | struct inode *inode = new_inode(sb); | 259 | struct inode *inode = new_inode(sb); |
254 | static struct backing_dev_info cgroup_backing_dev_info = { | ||
255 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | ||
256 | }; | ||
257 | 260 | ||
258 | if (inode) { | 261 | if (inode) { |
259 | inode->i_mode = mode; | 262 | inode->i_mode = mode; |
@@ -1600,6 +1603,11 @@ int __init cgroup_init(void) | |||
1600 | { | 1603 | { |
1601 | int err; | 1604 | int err; |
1602 | int i; | 1605 | int i; |
1606 | struct proc_dir_entry *entry; | ||
1607 | |||
1608 | err = bdi_init(&cgroup_backing_dev_info); | ||
1609 | if (err) | ||
1610 | return err; | ||
1603 | 1611 | ||
1604 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | 1612 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { |
1605 | struct cgroup_subsys *ss = subsys[i]; | 1613 | struct cgroup_subsys *ss = subsys[i]; |
@@ -1611,10 +1619,142 @@ int __init cgroup_init(void) | |||
1611 | if (err < 0) | 1619 | if (err < 0) |
1612 | goto out; | 1620 | goto out; |
1613 | 1621 | ||
1622 | entry = create_proc_entry("cgroups", 0, NULL); | ||
1623 | if (entry) | ||
1624 | entry->proc_fops = &proc_cgroupstats_operations; | ||
1625 | |||
1614 | out: | 1626 | out: |
1627 | if (err) | ||
1628 | bdi_destroy(&cgroup_backing_dev_info); | ||
1629 | |||
1615 | return err; | 1630 | return err; |
1616 | } | 1631 | } |
1617 | 1632 | ||
1633 | /* | ||
1634 | * proc_cgroup_show() | ||
1635 | * - Print task's cgroup paths into seq_file, one line for each hierarchy | ||
1636 | * - Used for /proc/<pid>/cgroup. | ||
1637 | * - No need to task_lock(tsk) on this tsk->cgroup reference, as it | ||
1638 | * doesn't really matter if tsk->cgroup changes after we read it, | ||
1639 | * and we take cgroup_mutex, keeping attach_task() from changing it | ||
1640 | * anyway. No need to check that tsk->cgroup != NULL, thanks to | ||
1641 | * the_top_cgroup_hack in cgroup_exit(), which sets an exiting tasks | ||
1642 | * cgroup to top_cgroup. | ||
1643 | */ | ||
1644 | |||
1645 | /* TODO: Use a proper seq_file iterator */ | ||
1646 | static int proc_cgroup_show(struct seq_file *m, void *v) | ||
1647 | { | ||
1648 | struct pid *pid; | ||
1649 | struct task_struct *tsk; | ||
1650 | char *buf; | ||
1651 | int retval; | ||
1652 | struct cgroupfs_root *root; | ||
1653 | |||
1654 | retval = -ENOMEM; | ||
1655 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
1656 | if (!buf) | ||
1657 | goto out; | ||
1658 | |||
1659 | retval = -ESRCH; | ||
1660 | pid = m->private; | ||
1661 | tsk = get_pid_task(pid, PIDTYPE_PID); | ||
1662 | if (!tsk) | ||
1663 | goto out_free; | ||
1664 | |||
1665 | retval = 0; | ||
1666 | |||
1667 | mutex_lock(&cgroup_mutex); | ||
1668 | |||
1669 | for_each_root(root) { | ||
1670 | struct cgroup_subsys *ss; | ||
1671 | struct cgroup *cont; | ||
1672 | int subsys_id; | ||
1673 | int count = 0; | ||
1674 | |||
1675 | /* Skip this hierarchy if it has no active subsystems */ | ||
1676 | if (!root->actual_subsys_bits) | ||
1677 | continue; | ||
1678 | for_each_subsys(root, ss) | ||
1679 | seq_printf(m, "%s%s", count++ ? "," : "", ss->name); | ||
1680 | seq_putc(m, ':'); | ||
1681 | get_first_subsys(&root->top_cgroup, NULL, &subsys_id); | ||
1682 | cont = task_cgroup(tsk, subsys_id); | ||
1683 | retval = cgroup_path(cont, buf, PAGE_SIZE); | ||
1684 | if (retval < 0) | ||
1685 | goto out_unlock; | ||
1686 | seq_puts(m, buf); | ||
1687 | seq_putc(m, '\n'); | ||
1688 | } | ||
1689 | |||
1690 | out_unlock: | ||
1691 | mutex_unlock(&cgroup_mutex); | ||
1692 | put_task_struct(tsk); | ||
1693 | out_free: | ||
1694 | kfree(buf); | ||
1695 | out: | ||
1696 | return retval; | ||
1697 | } | ||
1698 | |||
1699 | static int cgroup_open(struct inode *inode, struct file *file) | ||
1700 | { | ||
1701 | struct pid *pid = PROC_I(inode)->pid; | ||
1702 | return single_open(file, proc_cgroup_show, pid); | ||
1703 | } | ||
1704 | |||
1705 | struct file_operations proc_cgroup_operations = { | ||
1706 | .open = cgroup_open, | ||
1707 | .read = seq_read, | ||
1708 | .llseek = seq_lseek, | ||
1709 | .release = single_release, | ||
1710 | }; | ||
1711 | |||
1712 | /* Display information about each subsystem and each hierarchy */ | ||
1713 | static int proc_cgroupstats_show(struct seq_file *m, void *v) | ||
1714 | { | ||
1715 | int i; | ||
1716 | struct cgroupfs_root *root; | ||
1717 | |||
1718 | mutex_lock(&cgroup_mutex); | ||
1719 | seq_puts(m, "Hierarchies:\n"); | ||
1720 | for_each_root(root) { | ||
1721 | struct cgroup_subsys *ss; | ||
1722 | int first = 1; | ||
1723 | seq_printf(m, "%p: bits=%lx cgroups=%d (", root, | ||
1724 | root->subsys_bits, root->number_of_cgroups); | ||
1725 | for_each_subsys(root, ss) { | ||
1726 | seq_printf(m, "%s%s", first ? "" : ", ", ss->name); | ||
1727 | first = false; | ||
1728 | } | ||
1729 | seq_putc(m, ')'); | ||
1730 | if (root->sb) { | ||
1731 | seq_printf(m, " s_active=%d", | ||
1732 | atomic_read(&root->sb->s_active)); | ||
1733 | } | ||
1734 | seq_putc(m, '\n'); | ||
1735 | } | ||
1736 | seq_puts(m, "Subsystems:\n"); | ||
1737 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | ||
1738 | struct cgroup_subsys *ss = subsys[i]; | ||
1739 | seq_printf(m, "%d: name=%s hierarchy=%p\n", | ||
1740 | i, ss->name, ss->root); | ||
1741 | } | ||
1742 | mutex_unlock(&cgroup_mutex); | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static int cgroupstats_open(struct inode *inode, struct file *file) | ||
1747 | { | ||
1748 | return single_open(file, proc_cgroupstats_show, 0); | ||
1749 | } | ||
1750 | |||
1751 | static struct file_operations proc_cgroupstats_operations = { | ||
1752 | .open = cgroupstats_open, | ||
1753 | .read = seq_read, | ||
1754 | .llseek = seq_lseek, | ||
1755 | .release = single_release, | ||
1756 | }; | ||
1757 | |||
1618 | /** | 1758 | /** |
1619 | * cgroup_fork - attach newly forked task to its parents cgroup. | 1759 | * cgroup_fork - attach newly forked task to its parents cgroup. |
1620 | * @tsk: pointer to task_struct of forking parent process. | 1760 | * @tsk: pointer to task_struct of forking parent process. |