aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorMandeep Singh Baines <msb@chromium.org>2012-01-30 15:51:56 -0500
committerTejun Heo <tj@kernel.org>2012-01-30 16:01:39 -0500
commit61d1d219c4c0761059236a46867bc49943c4d29d (patch)
tree3803019bf5a294644bc3effcd95dac928ead587d /kernel/cgroup.c
parentfb5d2b4cfc24963d0e8a7df57de1ecffa10a04cf (diff)
cgroup: remove extra calls to find_existing_css_set
In cgroup_attach_proc, we indirectly call find_existing_css_set 3 times. It is an expensive call so we want to call it a minimum of times. This patch only calls it once and stores the result so that it can be used later on when we call cgroup_task_migrate. This required modifying cgroup_task_migrate to take the new css_set (which we obtained from find_css_set) as a parameter. The nice side effect of this is that cgroup_task_migrate is now identical for cgroup_attach_task and cgroup_attach_proc. It also now returns a void since it can never fail. Changes in V5: * https://lkml.org/lkml/2012/1/20/344 (Tejun Heo) * Remove css_set_refs Changes in V4: * https://lkml.org/lkml/2011/12/22/421 (Li Zefan) * Avoid GFP_KERNEL (sleep) in rcu_read_lock by getting css_set in a separate loop not under an rcu_read_lock Changes in V3: * https://lkml.org/lkml/2011/12/22/13 (Li Zefan) * Fixed earlier bug by creating a seperate patch to remove tasklist_lock Changes in V2: * https://lkml.org/lkml/2011/12/20/372 (Tejun Heo) * Move find_css_set call into loop which creates the flex array * Author * Kill css_set_refs and use group_size instead * Fix an off-by-one error in counting css_set refs * Add a retval check in out_list_teardown Signed-off-by: Mandeep Singh Baines <msb@chromium.org> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Tejun Heo <tj@kernel.org> Cc: containers@lists.linux-foundation.org Cc: cgroups@vger.kernel.org Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Paul Menage <paul@paulmenage.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c140
1 files changed, 27 insertions, 113 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 1626152dcc1e..43a224f167b5 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1763,6 +1763,7 @@ EXPORT_SYMBOL_GPL(cgroup_path);
1763struct task_and_cgroup { 1763struct task_and_cgroup {
1764 struct task_struct *task; 1764 struct task_struct *task;
1765 struct cgroup *cgrp; 1765 struct cgroup *cgrp;
1766 struct css_set *cg;
1766}; 1767};
1767 1768
1768struct cgroup_taskset { 1769struct cgroup_taskset {
@@ -1843,11 +1844,10 @@ EXPORT_SYMBOL_GPL(cgroup_taskset_size);
1843 * will already exist. If not set, this function might sleep, and can fail with 1844 * will already exist. If not set, this function might sleep, and can fail with
1844 * -ENOMEM. Must be called with cgroup_mutex and threadgroup locked. 1845 * -ENOMEM. Must be called with cgroup_mutex and threadgroup locked.
1845 */ 1846 */
1846static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp, 1847static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
1847 struct task_struct *tsk, bool guarantee) 1848 struct task_struct *tsk, struct css_set *newcg)
1848{ 1849{
1849 struct css_set *oldcg; 1850 struct css_set *oldcg;
1850 struct css_set *newcg;
1851 1851
1852 /* 1852 /*
1853 * We are synchronized through threadgroup_lock() against PF_EXITING 1853 * We are synchronized through threadgroup_lock() against PF_EXITING
@@ -1857,23 +1857,6 @@ static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
1857 WARN_ON_ONCE(tsk->flags & PF_EXITING); 1857 WARN_ON_ONCE(tsk->flags & PF_EXITING);
1858 oldcg = tsk->cgroups; 1858 oldcg = tsk->cgroups;
1859 1859
1860 /* locate or allocate a new css_set for this task. */
1861 if (guarantee) {
1862 /* we know the css_set we want already exists. */
1863 struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
1864 read_lock(&css_set_lock);
1865 newcg = find_existing_css_set(oldcg, cgrp, template);
1866 BUG_ON(!newcg);
1867 get_css_set(newcg);
1868 read_unlock(&css_set_lock);
1869 } else {
1870 might_sleep();
1871 /* find_css_set will give us newcg already referenced. */
1872 newcg = find_css_set(oldcg, cgrp);
1873 if (!newcg)
1874 return -ENOMEM;
1875 }
1876
1877 task_lock(tsk); 1860 task_lock(tsk);
1878 rcu_assign_pointer(tsk->cgroups, newcg); 1861 rcu_assign_pointer(tsk->cgroups, newcg);
1879 task_unlock(tsk); 1862 task_unlock(tsk);
@@ -1892,7 +1875,6 @@ static int cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
1892 put_css_set(oldcg); 1875 put_css_set(oldcg);
1893 1876
1894 set_bit(CGRP_RELEASABLE, &oldcgrp->flags); 1877 set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
1895 return 0;
1896} 1878}
1897 1879
1898/** 1880/**
@@ -1910,6 +1892,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
1910 struct cgroup *oldcgrp; 1892 struct cgroup *oldcgrp;
1911 struct cgroupfs_root *root = cgrp->root; 1893 struct cgroupfs_root *root = cgrp->root;
1912 struct cgroup_taskset tset = { }; 1894 struct cgroup_taskset tset = { };
1895 struct css_set *newcg;
1913 1896
1914 /* @tsk either already exited or can't exit until the end */ 1897 /* @tsk either already exited or can't exit until the end */
1915 if (tsk->flags & PF_EXITING) 1898 if (tsk->flags & PF_EXITING)
@@ -1939,9 +1922,13 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
1939 } 1922 }
1940 } 1923 }
1941 1924
1942 retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, false); 1925 newcg = find_css_set(tsk->cgroups, cgrp);
1943 if (retval) 1926 if (!newcg) {
1927 retval = -ENOMEM;
1944 goto out; 1928 goto out;
1929 }
1930
1931 cgroup_task_migrate(cgrp, oldcgrp, tsk, newcg);
1945 1932
1946 for_each_subsys(root, ss) { 1933 for_each_subsys(root, ss) {
1947 if (ss->attach) 1934 if (ss->attach)
@@ -1997,66 +1984,6 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
1997} 1984}
1998EXPORT_SYMBOL_GPL(cgroup_attach_task_all); 1985EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
1999 1986
2000/*
2001 * cgroup_attach_proc works in two stages, the first of which prefetches all
2002 * new css_sets needed (to make sure we have enough memory before committing
2003 * to the move) and stores them in a list of entries of the following type.
2004 * TODO: possible optimization: use css_set->rcu_head for chaining instead
2005 */
2006struct cg_list_entry {
2007 struct css_set *cg;
2008 struct list_head links;
2009};
2010
2011static bool css_set_check_fetched(struct cgroup *cgrp,
2012 struct task_struct *tsk, struct css_set *cg,
2013 struct list_head *newcg_list)
2014{
2015 struct css_set *newcg;
2016 struct cg_list_entry *cg_entry;
2017 struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
2018
2019 read_lock(&css_set_lock);
2020 newcg = find_existing_css_set(cg, cgrp, template);
2021 read_unlock(&css_set_lock);
2022
2023 /* doesn't exist at all? */
2024 if (!newcg)
2025 return false;
2026 /* see if it's already in the list */
2027 list_for_each_entry(cg_entry, newcg_list, links)
2028 if (cg_entry->cg == newcg)
2029 return true;
2030
2031 /* not found */
2032 return false;
2033}
2034
2035/*
2036 * Find the new css_set and store it in the list in preparation for moving the
2037 * given task to the given cgroup. Returns 0 or -ENOMEM.
2038 */
2039static int css_set_prefetch(struct cgroup *cgrp, struct css_set *cg,
2040 struct list_head *newcg_list)
2041{
2042 struct css_set *newcg;
2043 struct cg_list_entry *cg_entry;
2044
2045 /* ensure a new css_set will exist for this thread */
2046 newcg = find_css_set(cg, cgrp);
2047 if (!newcg)
2048 return -ENOMEM;
2049 /* add it to the list */
2050 cg_entry = kmalloc(sizeof(struct cg_list_entry), GFP_KERNEL);
2051 if (!cg_entry) {
2052 put_css_set(newcg);
2053 return -ENOMEM;
2054 }
2055 cg_entry->cg = newcg;
2056 list_add(&cg_entry->links, newcg_list);
2057 return 0;
2058}
2059
2060/** 1987/**
2061 * cgroup_attach_proc - attach all threads in a threadgroup to a cgroup 1988 * cgroup_attach_proc - attach all threads in a threadgroup to a cgroup
2062 * @cgrp: the cgroup to attach to 1989 * @cgrp: the cgroup to attach to
@@ -2070,20 +1997,12 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
2070 int retval, i, group_size; 1997 int retval, i, group_size;
2071 struct cgroup_subsys *ss, *failed_ss = NULL; 1998 struct cgroup_subsys *ss, *failed_ss = NULL;
2072 /* guaranteed to be initialized later, but the compiler needs this */ 1999 /* guaranteed to be initialized later, but the compiler needs this */
2073 struct css_set *oldcg;
2074 struct cgroupfs_root *root = cgrp->root; 2000 struct cgroupfs_root *root = cgrp->root;
2075 /* threadgroup list cursor and array */ 2001 /* threadgroup list cursor and array */
2076 struct task_struct *tsk; 2002 struct task_struct *tsk;
2077 struct task_and_cgroup *tc; 2003 struct task_and_cgroup *tc;
2078 struct flex_array *group; 2004 struct flex_array *group;
2079 struct cgroup_taskset tset = { }; 2005 struct cgroup_taskset tset = { };
2080 /*
2081 * we need to make sure we have css_sets for all the tasks we're
2082 * going to move -before- we actually start moving them, so that in
2083 * case we get an ENOMEM we can bail out before making any changes.
2084 */
2085 struct list_head newcg_list;
2086 struct cg_list_entry *cg_entry, *temp_nobe;
2087 2006
2088 /* 2007 /*
2089 * step 0: in order to do expensive, possibly blocking operations for 2008 * step 0: in order to do expensive, possibly blocking operations for
@@ -2119,15 +2038,15 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
2119 2038
2120 /* as per above, nr_threads may decrease, but not increase. */ 2039 /* as per above, nr_threads may decrease, but not increase. */
2121 BUG_ON(i >= group_size); 2040 BUG_ON(i >= group_size);
2122 /*
2123 * saying GFP_ATOMIC has no effect here because we did prealloc
2124 * earlier, but it's good form to communicate our expectations.
2125 */
2126 ent.task = tsk; 2041 ent.task = tsk;
2127 ent.cgrp = task_cgroup_from_root(tsk, root); 2042 ent.cgrp = task_cgroup_from_root(tsk, root);
2128 /* nothing to do if this task is already in the cgroup */ 2043 /* nothing to do if this task is already in the cgroup */
2129 if (ent.cgrp == cgrp) 2044 if (ent.cgrp == cgrp)
2130 continue; 2045 continue;
2046 /*
2047 * saying GFP_ATOMIC has no effect here because we did prealloc
2048 * earlier, but it's good form to communicate our expectations.
2049 */
2131 retval = flex_array_put(group, i, &ent, GFP_ATOMIC); 2050 retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
2132 BUG_ON(retval != 0); 2051 BUG_ON(retval != 0);
2133 i++; 2052 i++;
@@ -2160,17 +2079,12 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
2160 * step 2: make sure css_sets exist for all threads to be migrated. 2079 * step 2: make sure css_sets exist for all threads to be migrated.
2161 * we use find_css_set, which allocates a new one if necessary. 2080 * we use find_css_set, which allocates a new one if necessary.
2162 */ 2081 */
2163 INIT_LIST_HEAD(&newcg_list);
2164 for (i = 0; i < group_size; i++) { 2082 for (i = 0; i < group_size; i++) {
2165 tc = flex_array_get(group, i); 2083 tc = flex_array_get(group, i);
2166 oldcg = tc->task->cgroups; 2084 tc->cg = find_css_set(tc->task->cgroups, cgrp);
2167 2085 if (!tc->cg) {
2168 /* if we don't already have it in the list get a new one */ 2086 retval = -ENOMEM;
2169 if (!css_set_check_fetched(cgrp, tc->task, oldcg, 2087 goto out_put_css_set_refs;
2170 &newcg_list)) {
2171 retval = css_set_prefetch(cgrp, oldcg, &newcg_list);
2172 if (retval)
2173 goto out_list_teardown;
2174 } 2088 }
2175 } 2089 }
2176 2090
@@ -2181,8 +2095,7 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
2181 */ 2095 */
2182 for (i = 0; i < group_size; i++) { 2096 for (i = 0; i < group_size; i++) {
2183 tc = flex_array_get(group, i); 2097 tc = flex_array_get(group, i);
2184 retval = cgroup_task_migrate(cgrp, tc->cgrp, tc->task, true); 2098 cgroup_task_migrate(cgrp, tc->cgrp, tc->task, tc->cg);
2185 BUG_ON(retval);
2186 } 2099 }
2187 /* nothing is sensitive to fork() after this point. */ 2100 /* nothing is sensitive to fork() after this point. */
2188 2101
@@ -2200,15 +2113,16 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
2200 synchronize_rcu(); 2113 synchronize_rcu();
2201 cgroup_wakeup_rmdir_waiter(cgrp); 2114 cgroup_wakeup_rmdir_waiter(cgrp);
2202 retval = 0; 2115 retval = 0;
2203out_list_teardown: 2116out_put_css_set_refs:
2204 /* clean up the list of prefetched css_sets. */ 2117 if (retval) {
2205 list_for_each_entry_safe(cg_entry, temp_nobe, &newcg_list, links) { 2118 for (i = 0; i < group_size; i++) {
2206 list_del(&cg_entry->links); 2119 tc = flex_array_get(group, i);
2207 put_css_set(cg_entry->cg); 2120 if (!tc->cg)
2208 kfree(cg_entry); 2121 break;
2122 put_css_set(tc->cg);
2123 }
2209 } 2124 }
2210out_cancel_attach: 2125out_cancel_attach:
2211 /* same deal as in cgroup_attach_task */
2212 if (retval) { 2126 if (retval) {
2213 for_each_subsys(root, ss) { 2127 for_each_subsys(root, ss) {
2214 if (ss == failed_ss) 2128 if (ss == failed_ss)