aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2011-05-26 19:25:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-26 20:12:34 -0400
commit74a1166dfe1135dcc168d35fa5261aa7e087011b (patch)
treea7add70f0344e2352b8d0d6beb10aef85c6585f7
parentf780bdb7c1c73009cb57adcf99ef50027d80bf3c (diff)
cgroups: make procs file writable
Make procs file writable to move all threads by tgid at once. Add functionality that enables users to move all threads in a threadgroup at once to a cgroup by writing the tgid to the 'cgroup.procs' file. This current implementation makes use of a per-threadgroup rwsem that's taken for reading in the fork() path to prevent newly forking threads within the threadgroup from "escaping" while the move is in progress. Signed-off-by: Ben Blum <bblum@andrew.cmu.edu> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Matt Helsley <matthltc@us.ibm.com> Reviewed-by: Paul Menage <menage@google.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: David Rientjes <rientjes@google.com> Cc: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/cgroups/cgroups.txt9
-rw-r--r--kernel/cgroup.c439
2 files changed, 401 insertions, 47 deletions
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index b3bd3bdbe202..8c4f3466c894 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -236,7 +236,8 @@ containing the following files describing that cgroup:
236 - cgroup.procs: list of tgids in the cgroup. This list is not 236 - cgroup.procs: list of tgids in the cgroup. This list is not
237 guaranteed to be sorted or free of duplicate tgids, and userspace 237 guaranteed to be sorted or free of duplicate tgids, and userspace
238 should sort/uniquify the list if this property is required. 238 should sort/uniquify the list if this property is required.
239 This is a read-only file, for now. 239 Writing a thread group id into this file moves all threads in that
240 group into this cgroup.
240 - notify_on_release flag: run the release agent on exit? 241 - notify_on_release flag: run the release agent on exit?
241 - release_agent: the path to use for release notifications (this file 242 - release_agent: the path to use for release notifications (this file
242 exists in the top cgroup only) 243 exists in the top cgroup only)
@@ -430,6 +431,12 @@ You can attach the current shell task by echoing 0:
430 431
431# echo 0 > tasks 432# echo 0 > tasks
432 433
434You can use the cgroup.procs file instead of the tasks file to move all
435threads in a threadgroup at once. Echoing the pid of any task in a
436threadgroup to cgroup.procs causes all tasks in that threadgroup to be
437be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
438in the writing task's threadgroup.
439
433Note: Since every task is always a member of exactly one cgroup in each 440Note: Since every task is always a member of exactly one cgroup in each
434mounted hierarchy, to remove a task from its current cgroup you must 441mounted hierarchy, to remove a task from its current cgroup you must
435move it into a new cgroup (possibly the root cgroup) by writing to the 442move it into a new cgroup (possibly the root cgroup) by writing to the
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 38fb0ad1cb46..5e6a9745f0e7 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1735,6 +1735,76 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
1735} 1735}
1736EXPORT_SYMBOL_GPL(cgroup_path); 1736EXPORT_SYMBOL_GPL(cgroup_path);
1737 1737
1738/*
1739 * cgroup_task_migrate - move a task from one cgroup to another.
1740 *
1741 * 'guarantee' is set if the caller promises that a new css_set for the task
1742 * will already exist. If not set, this function might sleep, and can fail with
1743 * -ENOMEM. Otherwise, it can only fail with -ESRCH.
1744 */
1745static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
1746 struct task_struct *tsk, bool guarantee)
1747{
1748 struct css_set *oldcg;
1749 struct css_set *newcg;
1750
1751 /*
1752 * get old css_set. we need to take task_lock and refcount it, because
1753 * an exiting task can change its css_set to init_css_set and drop its
1754 * old one without taking cgroup_mutex.
1755 */
1756 task_lock(tsk);
1757 oldcg = tsk->cgroups;
1758 get_css_set(oldcg);
1759 task_unlock(tsk);
1760
1761 /* locate or allocate a new css_set for this task. */
1762 if (guarantee) {
1763 /* we know the css_set we want already exists. */
1764 struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
1765 read_lock(&css_set_lock);
1766 newcg = find_existing_css_set(oldcg, cgrp, template);
1767 BUG_ON(!newcg);
1768 get_css_set(newcg);
1769 read_unlock(&css_set_lock);
1770 } else {
1771 might_sleep();
1772 /* find_css_set will give us newcg already referenced. */
1773 newcg = find_css_set(oldcg, cgrp);
1774 if (!newcg) {
1775 put_css_set(oldcg);
1776 return -ENOMEM;
1777 }
1778 }
1779 put_css_set(oldcg);
1780
1781 /* if PF_EXITING is set, the tsk->cgroups pointer is no longer safe. */
1782 task_lock(tsk);
1783 if (tsk->flags & PF_EXITING) {
1784 task_unlock(tsk);
1785 put_css_set(newcg);
1786 return -ESRCH;
1787 }
1788 rcu_assign_pointer(tsk->cgroups, newcg);
1789 task_unlock(tsk);
1790
1791 /* Update the css_set linked lists if we're using them */
1792 write_lock(&css_set_lock);
1793 if (!list_empty(&tsk->cg_list))
1794 list_move(&tsk->cg_list, &newcg->tasks);
1795 write_unlock(&css_set_lock);
1796
1797 /*
1798 * We just gained a reference on oldcg by taking it from the task. As
1799 * trading it for newcg is protected by cgroup_mutex, we're safe to drop
1800 * it here; it will be freed under RCU.
1801 */
1802 put_css_set(oldcg);
1803
1804 set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
1805 return 0;
1806}
1807
1738/** 1808/**
1739 * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp' 1809 * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp'
1740 * @cgrp: the cgroup the task is attaching to 1810 * @cgrp: the cgroup the task is attaching to
@@ -1745,11 +1815,9 @@ EXPORT_SYMBOL_GPL(cgroup_path);
1745 */ 1815 */
1746int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) 1816int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
1747{ 1817{
1748 int retval = 0; 1818 int retval;
1749 struct cgroup_subsys *ss, *failed_ss = NULL; 1819 struct cgroup_subsys *ss, *failed_ss = NULL;
1750 struct cgroup *oldcgrp; 1820 struct cgroup *oldcgrp;
1751 struct css_set *cg;
1752 struct css_set *newcg;
1753 struct cgroupfs_root *root = cgrp->root; 1821 struct cgroupfs_root *root = cgrp->root;
1754 1822
1755 /* Nothing to do if the task is already in that cgroup */ 1823 /* Nothing to do if the task is already in that cgroup */
@@ -1780,36 +1848,9 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
1780 } 1848 }
1781 } 1849 }
1782 1850
1783 task_lock(tsk); 1851 retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, false);
1784 cg = tsk->cgroups; 1852 if (retval)
1785 get_css_set(cg);
1786 task_unlock(tsk);
1787 /*
1788 * Locate or allocate a new css_set for this task,
1789 * based on its final set of cgroups
1790 */
1791 newcg = find_css_set(cg, cgrp);
1792 put_css_set(cg);
1793 if (!newcg) {
1794 retval = -ENOMEM;
1795 goto out;
1796 }
1797
1798 task_lock(tsk);
1799 if (tsk->flags & PF_EXITING) {
1800 task_unlock(tsk);
1801 put_css_set(newcg);
1802 retval = -ESRCH;
1803 goto out; 1853 goto out;
1804 }
1805 rcu_assign_pointer(tsk->cgroups, newcg);
1806 task_unlock(tsk);
1807
1808 /* Update the css_set linked lists if we're using them */
1809 write_lock(&css_set_lock);
1810 if (!list_empty(&tsk->cg_list))
1811 list_move(&tsk->cg_list, &newcg->tasks);
1812 write_unlock(&css_set_lock);
1813 1854
1814 for_each_subsys(root, ss) { 1855 for_each_subsys(root, ss) {
1815 if (ss->pre_attach) 1856 if (ss->pre_attach)
@@ -1819,9 +1860,8 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
1819 if (ss->attach) 1860 if (ss->attach)
1820 ss->attach(ss, cgrp, oldcgrp, tsk); 1861 ss->attach(ss, cgrp, oldcgrp, tsk);
1821 } 1862 }
1822 set_bit(CGRP_RELEASABLE, &oldcgrp->flags); 1863
1823 synchronize_rcu(); 1864 synchronize_rcu();
1824 put_css_set(cg);
1825 1865
1826 /* 1866 /*
1827 * wake up rmdir() waiter. the rmdir should fail since the cgroup 1867 * wake up rmdir() waiter. the rmdir should fail since the cgroup
@@ -1871,49 +1911,356 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
1871EXPORT_SYMBOL_GPL(cgroup_attach_task_all); 1911EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
1872 1912
1873/* 1913/*
1874 * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex 1914 * cgroup_attach_proc works in two stages, the first of which prefetches all
1875 * held. May take task_lock of task 1915 * new css_sets needed (to make sure we have enough memory before committing
1916 * to the move) and stores them in a list of entries of the following type.
1917 * TODO: possible optimization: use css_set->rcu_head for chaining instead
1918 */
1919struct cg_list_entry {
1920