Commit a424316ca154317367c7ddf89997d1c80e4a8051

Authored by Paul Menage
Committed by Linus Torvalds
1 parent 697f416108

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>

Showing 3 changed files with 152 additions and 3 deletions Side-by-side Diff

... ... @@ -67,6 +67,7 @@
67 67 #include <linux/mount.h>
68 68 #include <linux/security.h>
69 69 #include <linux/ptrace.h>
  70 +#include <linux/cgroup.h>
70 71 #include <linux/cpuset.h>
71 72 #include <linux/audit.h>
72 73 #include <linux/poll.h>
... ... @@ -2133,6 +2134,9 @@
2133 2134 #ifdef CONFIG_CPUSETS
2134 2135 REG("cpuset", S_IRUGO, cpuset),
2135 2136 #endif
  2137 +#ifdef CONFIG_CGROUPS
  2138 + REG("cgroup", S_IRUGO, cgroup),
  2139 +#endif
2136 2140 INF("oom_score", S_IRUGO, oom_score),
2137 2141 REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
2138 2142 #ifdef CONFIG_AUDITSYSCALL
... ... @@ -2418,6 +2422,9 @@
2418 2422 #endif
2419 2423 #ifdef CONFIG_CPUSETS
2420 2424 REG("cpuset", S_IRUGO, cpuset),
  2425 +#endif
  2426 +#ifdef CONFIG_CGROUPS
  2427 + REG("cgroup", S_IRUGO, cgroup),
2421 2428 #endif
2422 2429 INF("oom_score", S_IRUGO, oom_score),
2423 2430 REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
include/linux/cgroup.h
... ... @@ -29,6 +29,8 @@
29 29 extern void cgroup_fork_callbacks(struct task_struct *p);
30 30 extern void cgroup_exit(struct task_struct *p, int run_callbacks);
31 31  
  32 +extern struct file_operations proc_cgroup_operations;
  33 +
32 34 /* Per-subsystem/per-cgroup state maintained by the system. */
33 35 struct cgroup_subsys_state {
34 36 /* The cgroup that this subsystem is attached to. Useful
... ... @@ -33,6 +33,7 @@
33 33 #include <linux/mutex.h>
34 34 #include <linux/mount.h>
35 35 #include <linux/pagemap.h>
  36 +#include <linux/proc_fs.h>
36 37 #include <linux/rcupdate.h>
37 38 #include <linux/sched.h>
38 39 #include <linux/seq_file.h>
39 40  
40 41  
... ... @@ -247,13 +248,15 @@
247 248 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
248 249 static int cgroup_populate_dir(struct cgroup *cont);
249 250 static struct inode_operations cgroup_dir_inode_operations;
  251 +static struct file_operations proc_cgroupstats_operations;
250 252  
  253 +static struct backing_dev_info cgroup_backing_dev_info = {
  254 + .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
  255 +};
  256 +
251 257 static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
252 258 {
253 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 261 if (inode) {
259 262 inode->i_mode = mode;
260 263  
... ... @@ -1600,7 +1603,12 @@
1600 1603 {
1601 1604 int err;
1602 1605 int i;
  1606 + struct proc_dir_entry *entry;
1603 1607  
  1608 + err = bdi_init(&cgroup_backing_dev_info);
  1609 + if (err)
  1610 + return err;
  1611 +
1604 1612 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
1605 1613 struct cgroup_subsys *ss = subsys[i];
1606 1614 if (!ss->early_init)
1607 1615  
1608 1616  
... ... @@ -1611,9 +1619,141 @@
1611 1619 if (err < 0)
1612 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 1626 out:
  1627 + if (err)
  1628 + bdi_destroy(&cgroup_backing_dev_info);
  1629 +
1615 1630 return err;
1616 1631 }
  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 +};
1617 1757  
1618 1758 /**
1619 1759 * cgroup_fork - attach newly forked task to its parents cgroup.