Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cgroups: use flex_array in attach_proc

Convert cgroup_attach_proc to use flex_array.

The cgroup_attach_proc implementation requires a pre-allocated array to
store task pointers to atomically move a thread-group, but asking for a
monolithic array with kmalloc() may be unreliable for very large groups.
Using flex_array provides the same functionality with less risk of
failure.

This is a post-patch for cgroup-procs-write.patch.

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>

authored by

Ben Blum and committed by
Linus Torvalds
d846687d 74a1166d

+24 -9
+24 -9
kernel/cgroup.c
··· 57 57 #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */ 58 58 #include <linux/eventfd.h> 59 59 #include <linux/poll.h> 60 + #include <linux/flex_array.h> /* used in cgroup_attach_proc */ 60 61 61 62 #include <asm/atomic.h> 62 63 ··· 1996 1995 struct cgroupfs_root *root = cgrp->root; 1997 1996 /* threadgroup list cursor and array */ 1998 1997 struct task_struct *tsk; 1999 - struct task_struct **group; 1998 + struct flex_array *group; 2000 1999 /* 2001 2000 * we need to make sure we have css_sets for all the tasks we're 2002 2001 * going to move -before- we actually start moving them, so that in ··· 2013 2012 * and if threads exit, this will just be an over-estimate. 2014 2013 */ 2015 2014 group_size = get_nr_threads(leader); 2016 - group = kmalloc(group_size * sizeof(*group), GFP_KERNEL); 2015 + /* flex_array supports very large thread-groups better than kmalloc. */ 2016 + group = flex_array_alloc(sizeof(struct task_struct *), group_size, 2017 + GFP_KERNEL); 2017 2018 if (!group) 2018 2019 return -ENOMEM; 2020 + /* pre-allocate to guarantee space while iterating in rcu read-side. */ 2021 + retval = flex_array_prealloc(group, 0, group_size - 1, GFP_KERNEL); 2022 + if (retval) 2023 + goto out_free_group_list; 2019 2024 2020 2025 /* prevent changes to the threadgroup list while we take a snapshot. */ 2021 2026 rcu_read_lock(); ··· 2044 2037 /* as per above, nr_threads may decrease, but not increase. */ 2045 2038 BUG_ON(i >= group_size); 2046 2039 get_task_struct(tsk); 2047 - group[i] = tsk; 2040 + /* 2041 + * saying GFP_ATOMIC has no effect here because we did prealloc 2042 + * earlier, but it's good form to communicate our expectations. 2043 + */ 2044 + retval = flex_array_put_ptr(group, i, tsk, GFP_ATOMIC); 2045 + BUG_ON(retval != 0); 2048 2046 i++; 2049 2047 } while_each_thread(leader, tsk); 2050 2048 /* remember the number of threads in the array for later. */ ··· 2071 2059 if (ss->can_attach_task) { 2072 2060 /* run on each task in the threadgroup. */ 2073 2061 for (i = 0; i < group_size; i++) { 2074 - retval = ss->can_attach_task(cgrp, group[i]); 2062 + tsk = flex_array_get_ptr(group, i); 2063 + retval = ss->can_attach_task(cgrp, tsk); 2075 2064 if (retval) { 2076 2065 failed_ss = ss; 2077 2066 cancel_failed_ss = true; ··· 2088 2075 */ 2089 2076 INIT_LIST_HEAD(&newcg_list); 2090 2077 for (i = 0; i < group_size; i++) { 2091 - tsk = group[i]; 2078 + tsk = flex_array_get_ptr(group, i); 2092 2079 /* nothing to do if this task is already in the cgroup */ 2093 2080 oldcgrp = task_cgroup_from_root(tsk, root); 2094 2081 if (cgrp == oldcgrp) ··· 2127 2114 ss->pre_attach(cgrp); 2128 2115 } 2129 2116 for (i = 0; i < group_size; i++) { 2130 - tsk = group[i]; 2117 + tsk = flex_array_get_ptr(group, i); 2131 2118 /* leave current thread as it is if it's already there */ 2132 2119 oldcgrp = task_cgroup_from_root(tsk, root); 2133 2120 if (cgrp == oldcgrp) ··· 2180 2167 } 2181 2168 } 2182 2169 /* clean up the array of referenced threads in the group. */ 2183 - for (i = 0; i < group_size; i++) 2184 - put_task_struct(group[i]); 2170 + for (i = 0; i < group_size; i++) { 2171 + tsk = flex_array_get_ptr(group, i); 2172 + put_task_struct(tsk); 2173 + } 2185 2174 out_free_group_list: 2186 - kfree(group); 2175 + flex_array_free(group); 2187 2176 return retval; 2188 2177 } 2189 2178