Skip to content

Commit 2f7ee56

Browse files
committed
cgroup: introduce cgroup_taskset and use it in subsys->can_attach(), cancel_attach() and attach()
Currently, there's no way to pass multiple tasks to cgroup_subsys methods necessitating the need for separate per-process and per-task methods. This patch introduces cgroup_taskset which can be used to pass multiple tasks and their associated cgroups to cgroup_subsys methods. Three methods - can_attach(), cancel_attach() and attach() - are converted to use cgroup_taskset. This unifies passed parameters so that all methods have access to all information. Conversions in this patchset are identical and don't introduce any behavior change. -v2: documentation updated as per Paul Menage's suggestion. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Reviewed-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Paul Menage <paul@paulmenage.org> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: James Morris <jmorris@namei.org>
1 parent 134d337 commit 2f7ee56

7 files changed

Lines changed: 158 additions & 43 deletions

File tree

Documentation/cgroups/cgroups.txt

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -594,15 +594,25 @@ rmdir() will fail with it. From this behavior, pre_destroy() can be
594594
called multiple times against a cgroup.
595595

596596
int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
597-
struct task_struct *task)
597+
struct cgroup_taskset *tset)
598598
(cgroup_mutex held by caller)
599599

600-
Called prior to moving a task into a cgroup; if the subsystem
601-
returns an error, this will abort the attach operation. If a NULL
602-
task is passed, then a successful result indicates that *any*
603-
unspecified task can be moved into the cgroup. Note that this isn't
604-
called on a fork. If this method returns 0 (success) then this should
605-
remain valid while the caller holds cgroup_mutex and it is ensured that either
600+
Called prior to moving one or more tasks into a cgroup; if the
601+
subsystem returns an error, this will abort the attach operation.
602+
@tset contains the tasks to be attached and is guaranteed to have at
603+
least one task in it.
604+
605+
If there are multiple tasks in the taskset, then:
606+
- it's guaranteed that all are from the same thread group
607+
- @tset contains all tasks from the thread group whether or not
608+
they're switching cgroups
609+
- the first task is the leader
610+
611+
Each @tset entry also contains the task's old cgroup and tasks which
612+
aren't switching cgroup can be skipped easily using the
613+
cgroup_taskset_for_each() iterator. Note that this isn't called on a
614+
fork. If this method returns 0 (success) then this should remain valid
615+
while the caller holds cgroup_mutex and it is ensured that either
606616
attach() or cancel_attach() will be called in future.
607617

608618
int can_attach_task(struct cgroup *cgrp, struct task_struct *tsk);
@@ -613,14 +623,14 @@ attached (possibly many when using cgroup_attach_proc). Called after
613623
can_attach.
614624

615625
void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
616-
struct task_struct *task, bool threadgroup)
626+
struct cgroup_taskset *tset)
617627
(cgroup_mutex held by caller)
618628

619629
Called when a task attach operation has failed after can_attach() has succeeded.
620630
A subsystem whose can_attach() has some side-effects should provide this
621631
function, so that the subsystem can implement a rollback. If not, not necessary.
622632
This will be called only about subsystems whose can_attach() operation have
623-
succeeded.
633+
succeeded. The parameters are identical to can_attach().
624634

625635
void pre_attach(struct cgroup *cgrp);
626636
(cgroup_mutex held by caller)
@@ -629,11 +639,12 @@ For any non-per-thread attachment work that needs to happen before
629639
attach_task. Needed by cpuset.
630640

631641
void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
632-
struct cgroup *old_cgrp, struct task_struct *task)
642+
struct cgroup_taskset *tset)
633643
(cgroup_mutex held by caller)
634644

635645
Called after the task has been attached to the cgroup, to allow any
636646
post-attachment activity that requires memory allocations or blocking.
647+
The parameters are identical to can_attach().
637648

638649
void attach_task(struct cgroup *cgrp, struct task_struct *tsk);
639650
(cgroup_mutex held by caller)

include/linux/cgroup.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,28 @@ int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
456456
void cgroup_exclude_rmdir(struct cgroup_subsys_state *css);
457457
void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css);
458458

459+
/*
460+
* Control Group taskset, used to pass around set of tasks to cgroup_subsys
461+
* methods.
462+
*/
463+
struct cgroup_taskset;
464+
struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset);
465+
struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset);
466+
struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset);
467+
int cgroup_taskset_size(struct cgroup_taskset *tset);
468+
469+
/**
470+
* cgroup_taskset_for_each - iterate cgroup_taskset
471+
* @task: the loop cursor
472+
* @skip_cgrp: skip if task's cgroup matches this, %NULL to iterate through all
473+
* @tset: taskset to iterate
474+
*/
475+
#define cgroup_taskset_for_each(task, skip_cgrp, tset) \
476+
for ((task) = cgroup_taskset_first((tset)); (task); \
477+
(task) = cgroup_taskset_next((tset))) \
478+
if (!(skip_cgrp) || \
479+
cgroup_taskset_cur_cgroup((tset)) != (skip_cgrp))
480+
459481
/*
460482
* Control Group subsystem type.
461483
* See Documentation/cgroups/cgroups.txt for details
@@ -467,14 +489,14 @@ struct cgroup_subsys {
467489
int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
468490
void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
469491
int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
470-
struct task_struct *tsk);
492+
struct cgroup_taskset *tset);
471493
int (*can_attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
472494
void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
473-
struct task_struct *tsk);
495+
struct cgroup_taskset *tset);
474496
void (*pre_attach)(struct cgroup *cgrp);
475497
void (*attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
476498
void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
477-
struct cgroup *old_cgrp, struct task_struct *tsk);
499+
struct cgroup_taskset *tset);
478500
void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
479501
void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp,
480502
struct cgroup *old_cgrp, struct task_struct *task);

kernel/cgroup.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,11 +1757,85 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
17571757
}
17581758
EXPORT_SYMBOL_GPL(cgroup_path);
17591759

1760+
/*
1761+
* Control Group taskset
1762+
*/
17601763
struct task_and_cgroup {
17611764
struct task_struct *task;
17621765
struct cgroup *cgrp;
17631766
};
17641767

1768+
struct cgroup_taskset {
1769+
struct task_and_cgroup single;
1770+
struct flex_array *tc_array;
1771+
int tc_array_len;
1772+
int idx;
1773+
struct cgroup *cur_cgrp;
1774+
};
1775+
1776+
/**
1777+
* cgroup_taskset_first - reset taskset and return the first task
1778+
* @tset: taskset of interest
1779+
*
1780+
* @tset iteration is initialized and the first task is returned.
1781+
*/
1782+
struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset)
1783+
{
1784+
if (tset->tc_array) {
1785+
tset->idx = 0;
1786+
return cgroup_taskset_next(tset);
1787+
} else {
1788+
tset->cur_cgrp = tset->single.cgrp;
1789+
return tset->single.task;
1790+
}
1791+
}
1792+
EXPORT_SYMBOL_GPL(cgroup_taskset_first);
1793+
1794+
/**
1795+
* cgroup_taskset_next - iterate to the next task in taskset
1796+
* @tset: taskset of interest
1797+
*
1798+
* Return the next task in @tset. Iteration must have been initialized
1799+
* with cgroup_taskset_first().
1800+
*/
1801+
struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
1802+
{
1803+
struct task_and_cgroup *tc;
1804+
1805+
if (!tset->tc_array || tset->idx >= tset->tc_array_len)
1806+
return NULL;
1807+
1808+
tc = flex_array_get(tset->tc_array, tset->idx++);
1809+
tset->cur_cgrp = tc->cgrp;
1810+
return tc->task;
1811+
}
1812+
EXPORT_SYMBOL_GPL(cgroup_taskset_next);
1813+
1814+
/**
1815+
* cgroup_taskset_cur_cgroup - return the matching cgroup for the current task
1816+
* @tset: taskset of interest
1817+
*
1818+
* Return the cgroup for the current (last returned) task of @tset. This
1819+
* function must be preceded by either cgroup_taskset_first() or
1820+
* cgroup_taskset_next().
1821+
*/
1822+
struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset)
1823+
{
1824+
return tset->cur_cgrp;
1825+
}
1826+
EXPORT_SYMBOL_GPL(cgroup_taskset_cur_cgroup);
1827+
1828+
/**
1829+
* cgroup_taskset_size - return the number of tasks in taskset
1830+
* @tset: taskset of interest
1831+
*/
1832+
int cgroup_taskset_size(struct cgroup_taskset *tset)
1833+
{
1834+
return tset->tc_array ? tset->tc_array_len : 1;
1835+
}
1836+
EXPORT_SYMBOL_GPL(cgroup_taskset_size);
1837+
1838+
17651839
/*
17661840
* cgroup_task_migrate - move a task from one cgroup to another.
17671841
*
@@ -1842,6 +1916,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
18421916
struct cgroup_subsys *ss, *failed_ss = NULL;
18431917
struct cgroup *oldcgrp;
18441918
struct cgroupfs_root *root = cgrp->root;
1919+
struct cgroup_taskset tset = { };
18451920

18461921
/* @tsk either already exited or can't exit until the end */
18471922
if (tsk->flags & PF_EXITING)
@@ -1852,9 +1927,12 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
18521927
if (cgrp == oldcgrp)
18531928
return 0;
18541929

1930+
tset.single.task = tsk;
1931+
tset.single.cgrp = oldcgrp;
1932+
18551933
for_each_subsys(root, ss) {
18561934
if (ss->can_attach) {
1857-
retval = ss->can_attach(ss, cgrp, tsk);
1935+
retval = ss->can_attach(ss, cgrp, &tset);
18581936
if (retval) {
18591937
/*
18601938
* Remember on which subsystem the can_attach()
@@ -1885,7 +1963,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
18851963
if (ss->attach_task)
18861964
ss->attach_task(cgrp, tsk);
18871965
if (ss->attach)
1888-
ss->attach(ss, cgrp, oldcgrp, tsk);
1966+
ss->attach(ss, cgrp, &tset);
18891967
}
18901968

18911969
synchronize_rcu();
@@ -1907,7 +1985,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
19071985
*/
19081986
break;
19091987
if (ss->cancel_attach)
1910-
ss->cancel_attach(ss, cgrp, tsk);
1988+
ss->cancel_attach(ss, cgrp, &tset);
19111989
}
19121990
}
19131991
return retval;
@@ -2023,6 +2101,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
20232101
struct task_struct *tsk;
20242102
struct task_and_cgroup *tc;
20252103
struct flex_array *group;
2104+
struct cgroup_taskset tset = { };
20262105
/*
20272106
* we need to make sure we have css_sets for all the tasks we're
20282107
* going to move -before- we actually start moving them, so that in
@@ -2089,6 +2168,8 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
20892168
} while_each_thread(leader, tsk);
20902169
/* remember the number of threads in the array for later. */
20912170
group_size = i;
2171+
tset.tc_array = group;
2172+
tset.tc_array_len = group_size;
20922173
read_unlock(&tasklist_lock);
20932174

20942175
/* methods shouldn't be called if no task is actually migrating */
@@ -2101,7 +2182,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
21012182
*/
21022183
for_each_subsys(root, ss) {
21032184
if (ss->can_attach) {
2104-
retval = ss->can_attach(ss, cgrp, leader);
2185+
retval = ss->can_attach(ss, cgrp, &tset);
21052186
if (retval) {
21062187
failed_ss = ss;
21072188
goto out_cancel_attach;
@@ -2183,10 +2264,8 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
21832264
* being moved, this call will need to be reworked to communicate that.
21842265
*/
21852266
for_each_subsys(root, ss) {
2186-
if (ss->attach) {
2187-
tc = flex_array_get(group, 0);
2188-
ss->attach(ss, cgrp, tc->cgrp, tc->task);
2189-
}
2267+
if (ss->attach)
2268+
ss->attach(ss, cgrp, &tset);
21902269
}
21912270

21922271
/*
@@ -2208,11 +2287,11 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
22082287
for_each_subsys(root, ss) {
22092288
if (ss == failed_ss) {
22102289
if (cancel_failed_ss && ss->cancel_attach)
2211-
ss->cancel_attach(ss, cgrp, leader);
2290+
ss->cancel_attach(ss, cgrp, &tset);
22122291
break;
22132292
}
22142293
if (ss->cancel_attach)
2215-
ss->cancel_attach(ss, cgrp, leader);
2294+
ss->cancel_attach(ss, cgrp, &tset);
22162295
}
22172296
}
22182297
out_put_tasks:

kernel/cgroup_freezer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ static void freezer_destroy(struct cgroup_subsys *ss,
159159
*/
160160
static int freezer_can_attach(struct cgroup_subsys *ss,
161161
struct cgroup *new_cgroup,
162-
struct task_struct *task)
162+
struct cgroup_taskset *tset)
163163
{
164164
struct freezer *freezer;
165165

kernel/cpuset.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,10 +1371,10 @@ static int fmeter_getrate(struct fmeter *fmp)
13711371
}
13721372

13731373
/* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
1374-
static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
1375-
struct task_struct *tsk)
1374+
static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
1375+
struct cgroup_taskset *tset)
13761376
{
1377-
struct cpuset *cs = cgroup_cs(cont);
1377+
struct cpuset *cs = cgroup_cs(cgrp);
13781378

13791379
if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
13801380
return -ENOSPC;
@@ -1387,7 +1387,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
13871387
* set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may
13881388
* be changed.
13891389
*/
1390-
if (tsk->flags & PF_THREAD_BOUND)
1390+
if (cgroup_taskset_first(tset)->flags & PF_THREAD_BOUND)
13911391
return -EINVAL;
13921392

13931393
return 0;
@@ -1437,12 +1437,14 @@ static void cpuset_attach_task(struct cgroup *cont, struct task_struct *tsk)
14371437
cpuset_update_task_spread_flag(cs, tsk);
14381438
}
14391439

1440-
static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,
1441-
struct cgroup *oldcont, struct task_struct *tsk)
1440+
static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
1441+
struct cgroup_taskset *tset)
14421442
{
14431443
struct mm_struct *mm;
1444-
struct cpuset *cs = cgroup_cs(cont);
1445-
struct cpuset *oldcs = cgroup_cs(oldcont);
1444+
struct task_struct *tsk = cgroup_taskset_first(tset);
1445+
struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset);
1446+
struct cpuset *cs = cgroup_cs(cgrp);
1447+
struct cpuset *oldcs = cgroup_cs(oldcgrp);
14461448

14471449
/*
14481450
* Change mm, possibly for multiple threads in a threadgroup. This is

mm/memcontrol.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5298,8 +5298,9 @@ static void mem_cgroup_clear_mc(void)
52985298

52995299
static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
53005300
struct cgroup *cgroup,
5301-
struct task_struct *p)
5301+
struct cgroup_taskset *tset)
53025302
{
5303+
struct task_struct *p = cgroup_taskset_first(tset);
53035304
int ret = 0;
53045305
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup);
53055306

@@ -5337,7 +5338,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
53375338

53385339
static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
53395340
struct cgroup *cgroup,
5340-
struct task_struct *p)
5341+
struct cgroup_taskset *tset)
53415342
{
53425343
mem_cgroup_clear_mc();
53435344
}
@@ -5454,9 +5455,9 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
54545455

54555456
static void mem_cgroup_move_task(struct cgroup_subsys *ss,
54565457
struct cgroup *cont,
5457-
struct cgroup *old_cont,
5458-
struct task_struct *p)
5458+
struct cgroup_taskset *tset)
54595459
{
5460+
struct task_struct *p = cgroup_taskset_first(tset);
54605461
struct mm_struct *mm = get_task_mm(p);
54615462

54625463
if (mm) {
@@ -5471,19 +5472,18 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss,
54715472
#else /* !CONFIG_MMU */
54725473
static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
54735474
struct cgroup *cgroup,
5474-
struct task_struct *p)
5475+
struct cgroup_taskset *tset)
54755476
{
54765477
return 0;
54775478
}
54785479
static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
54795480
struct cgroup *cgroup,
5480-
struct task_struct *p)
5481+
struct cgroup_taskset *tset)
54815482
{
54825483
}
54835484
static void mem_cgroup_move_task(struct cgroup_subsys *ss,
54845485
struct cgroup *cont,
5485-
struct cgroup *old_cont,
5486-
struct task_struct *p)
5486+
struct cgroup_taskset *tset)
54875487
{
54885488
}
54895489
#endif

0 commit comments

Comments
 (0)