Commit db0c2bf6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

* 'for-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (21 commits)
  cgroup: fix to allow mounting a hierarchy by name
  cgroup: move assignement out of condition in cgroup_attach_proc()
  cgroup: Remove task_lock() from cgroup_post_fork()
  cgroup: add sparse annotation to cgroup_iter_start() and cgroup_iter_end()
  cgroup: mark cgroup_rmdir_waitq and cgroup_attach_proc() as static
  cgroup: only need to check oldcgrp==newgrp once
  cgroup: remove redundant get/put of task struct
  cgroup: remove redundant get/put of old css_set from migrate
  cgroup: Remove unnecessary task_lock before fetching css_set on migration
  cgroup: Drop task_lock(parent) on cgroup_fork()
  cgroups: remove redundant get/put of css_set from css_set_check_fetched()
  resource cgroups: remove bogus cast
  cgroup: kill subsys->can_attach_task(), pre_attach() and attach_task()
  cgroup, cpuset: don't use ss->pre_attach()
  cgroup: don't use subsys->can_attach_task() or ->attach_task()
  cgroup: introduce cgroup_taskset and use it in subsys->can_attach(), cancel_attach() and attach()
  cgroup: improve old cgroup handling in cgroup_attach_proc()
  cgroup: always lock threadgroup during migration
  threadgroup: extend threadgroup_lock() to cover exit and exec
  threadgroup: rename signal->threadgroup_fork_lock to ->group_rwsem
  ...

Fix up conflict in kernel/cgroup.c due to commit e0197aae: "cgroups:
fix a css_set not found bug in cgroup_attach_proc" that already
mentioned that the bug is fixed (differently) in Tejun's cgroup
patchset. This one, in other words.
parents ac69e092 0d19ea86
...@@ -594,53 +594,44 @@ rmdir() will fail with it. From this behavior, pre_destroy() can be ...@@ -594,53 +594,44 @@ rmdir() will fail with it. From this behavior, pre_destroy() can be
called multiple times against a cgroup. called multiple times against a cgroup.
int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct task_struct *task) struct cgroup_taskset *tset)
(cgroup_mutex held by caller) (cgroup_mutex held by caller)
Called prior to moving a task into a cgroup; if the subsystem Called prior to moving one or more tasks into a cgroup; if the
returns an error, this will abort the attach operation. If a NULL subsystem returns an error, this will abort the attach operation.
task is passed, then a successful result indicates that *any* @tset contains the tasks to be attached and is guaranteed to have at
unspecified task can be moved into the cgroup. Note that this isn't least one task in it.
called on a fork. If this method returns 0 (success) then this should
remain valid while the caller holds cgroup_mutex and it is ensured that either If there are multiple tasks in the taskset, then:
- it's guaranteed that all are from the same thread group
- @tset contains all tasks from the thread group whether or not
they're switching cgroups
- the first task is the leader
Each @tset entry also contains the task's old cgroup and tasks which
aren't switching cgroup can be skipped easily using the
cgroup_taskset_for_each() iterator. Note that this isn't called on a
fork. If this method returns 0 (success) then this should remain valid
while the caller holds cgroup_mutex and it is ensured that either
attach() or cancel_attach() will be called in future. attach() or cancel_attach() will be called in future.
int can_attach_task(struct cgroup *cgrp, struct task_struct *tsk);
(cgroup_mutex held by caller)
As can_attach, but for operations that must be run once per task to be
attached (possibly many when using cgroup_attach_proc). Called after
can_attach.
void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct task_struct *task, bool threadgroup) struct cgroup_taskset *tset)
(cgroup_mutex held by caller) (cgroup_mutex held by caller)
Called when a task attach operation has failed after can_attach() has succeeded. Called when a task attach operation has failed after can_attach() has succeeded.
A subsystem whose can_attach() has some side-effects should provide this A subsystem whose can_attach() has some side-effects should provide this
function, so that the subsystem can implement a rollback. If not, not necessary. function, so that the subsystem can implement a rollback. If not, not necessary.
This will be called only about subsystems whose can_attach() operation have This will be called only about subsystems whose can_attach() operation have
succeeded. succeeded. The parameters are identical to can_attach().
void pre_attach(struct cgroup *cgrp);
(cgroup_mutex held by caller)
For any non-per-thread attachment work that needs to happen before
attach_task. Needed by cpuset.
void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup *old_cgrp, struct task_struct *task) struct cgroup_taskset *tset)
(cgroup_mutex held by caller) (cgroup_mutex held by caller)
Called after the task has been attached to the cgroup, to allow any Called after the task has been attached to the cgroup, to allow any
post-attachment activity that requires memory allocations or blocking. post-attachment activity that requires memory allocations or blocking.
The parameters are identical to can_attach().
void attach_task(struct cgroup *cgrp, struct task_struct *tsk);
(cgroup_mutex held by caller)
As attach, but for operations that must be run once per task to be attached,
like can_attach_task. Called before attach. Currently does not support any
subsystem that might need the old_cgrp for every thread in the group.
void fork(struct cgroup_subsy *ss, struct task_struct *task) void fork(struct cgroup_subsy *ss, struct task_struct *task)
......
...@@ -30,8 +30,10 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup); ...@@ -30,8 +30,10 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup);
static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *, static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
struct cgroup *); struct cgroup *);
static int blkiocg_can_attach_task(struct cgroup *, struct task_struct *); static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
static void blkiocg_attach_task(struct cgroup *, struct task_struct *); struct cgroup_taskset *);
static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
struct cgroup_taskset *);
static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *); static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
...@@ -44,8 +46,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); ...@@ -44,8 +46,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
struct cgroup_subsys blkio_subsys = { struct cgroup_subsys blkio_subsys = {
.name = "blkio", .name = "blkio",
.create = blkiocg_create, .create = blkiocg_create,
.can_attach_task = blkiocg_can_attach_task, .can_attach = blkiocg_can_attach,
.attach_task = blkiocg_attach_task, .attach = blkiocg_attach,
.destroy = blkiocg_destroy, .destroy = blkiocg_destroy,
.populate = blkiocg_populate, .populate = blkiocg_populate,
#ifdef CONFIG_BLK_CGROUP #ifdef CONFIG_BLK_CGROUP
...@@ -1626,30 +1628,39 @@ blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) ...@@ -1626,30 +1628,39 @@ blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
* of the main cic data structures. For now we allow a task to change * of the main cic data structures. For now we allow a task to change
* its cgroup only if it's the only owner of its ioc. * its cgroup only if it's the only owner of its ioc.
*/ */
static int blkiocg_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) static int blkiocg_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup_taskset *tset)
{ {
struct task_struct *task;
struct io_context *ioc; struct io_context *ioc;
int ret = 0; int ret = 0;
/* task_lock() is needed to avoid races with exit_io_context() */ /* task_lock() is needed to avoid races with exit_io_context() */
task_lock(tsk); cgroup_taskset_for_each(task, cgrp, tset) {
ioc = tsk->io_context; task_lock(task);
if (ioc && atomic_read(&ioc->nr_tasks) > 1) ioc = task->io_context;
ret = -EINVAL; if (ioc && atomic_read(&ioc->nr_tasks) > 1)
task_unlock(tsk); ret = -EINVAL;
task_unlock(task);
if (ret)
break;
}
return ret; return ret;
} }
static void blkiocg_attach_task(struct cgroup *cgrp, struct task_struct *tsk) static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup_taskset *tset)
{ {
struct task_struct *task;
struct io_context *ioc; struct io_context *ioc;
task_lock(tsk); cgroup_taskset_for_each(task, cgrp, tset) {
ioc = tsk->io_context; task_lock(task);
if (ioc) ioc = task->io_context;
ioc->cgroup_changed = 1; if (ioc)
task_unlock(tsk); ioc->cgroup_changed = 1;
task_unlock(task);
}
} }
void blkio_policy_register(struct blkio_policy_type *blkiop) void blkio_policy_register(struct blkio_policy_type *blkiop)
......
...@@ -456,6 +456,28 @@ int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task); ...@@ -456,6 +456,28 @@ int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
void cgroup_exclude_rmdir(struct cgroup_subsys_state *css); void cgroup_exclude_rmdir(struct cgroup_subsys_state *css);
void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css); void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css);
/*
* Control Group taskset, used to pass around set of tasks to cgroup_subsys
* methods.
*/
struct cgroup_taskset;
struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset);
struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset);
struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset);
int cgroup_taskset_size(struct cgroup_taskset *tset);
/**
* cgroup_taskset_for_each - iterate cgroup_taskset
* @task: the loop cursor
* @skip_cgrp: skip if task's cgroup matches this, %NULL to iterate through all
* @tset: taskset to iterate
*/
#define cgroup_taskset_for_each(task, skip_cgrp, tset) \
for ((task) = cgroup_taskset_first((tset)); (task); \
(task) = cgroup_taskset_next((tset))) \
if (!(skip_cgrp) || \
cgroup_taskset_cur_cgroup((tset)) != (skip_cgrp))
/* /*
* Control Group subsystem type. * Control Group subsystem type.
* See Documentation/cgroups/cgroups.txt for details * See Documentation/cgroups/cgroups.txt for details
...@@ -467,14 +489,11 @@ struct cgroup_subsys { ...@@ -467,14 +489,11 @@ struct cgroup_subsys {
int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct task_struct *tsk); struct cgroup_taskset *tset);
int (*can_attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct task_struct *tsk); struct cgroup_taskset *tset);
void (*pre_attach)(struct cgroup *cgrp);
void (*attach_task)(struct cgroup *cgrp, struct task_struct *tsk);
void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup *old_cgrp, struct task_struct *tsk); struct cgroup_taskset *tset);
void (*fork)(struct cgroup_subsys *ss, struct task_struct *task); void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp, void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup *old_cgrp, struct task_struct *task); struct cgroup *old_cgrp, struct task_struct *task);
......
...@@ -23,11 +23,10 @@ extern struct files_struct init_files; ...@@ -23,11 +23,10 @@ extern struct files_struct init_files;
extern struct fs_struct init_fs; extern struct fs_struct init_fs;
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
#define INIT_THREADGROUP_FORK_LOCK(sig) \ #define INIT_GROUP_RWSEM(sig) \
.threadgroup_fork_lock = \ .group_rwsem = __RWSEM_INITIALIZER(sig.group_rwsem),
__RWSEM_INITIALIZER(sig.threadgroup_fork_lock),
#else #else
#define INIT_THREADGROUP_FORK_LOCK(sig) #define INIT_GROUP_RWSEM(sig)
#endif #endif
#define INIT_SIGNALS(sig) { \ #define INIT_SIGNALS(sig) { \
...@@ -46,7 +45,7 @@ extern struct fs_struct init_fs; ...@@ -46,7 +45,7 @@ extern struct fs_struct init_fs;
}, \ }, \
.cred_guard_mutex = \ .cred_guard_mutex = \
__MUTEX_INITIALIZER(sig.cred_guard_mutex), \ __MUTEX_INITIALIZER(sig.cred_guard_mutex), \
INIT_THREADGROUP_FORK_LOCK(sig) \ INIT_GROUP_RWSEM(sig) \
} }
extern struct nsproxy init_nsproxy; extern struct nsproxy init_nsproxy;
......
...@@ -637,13 +637,15 @@ struct signal_struct { ...@@ -637,13 +637,15 @@ struct signal_struct {
#endif #endif
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
/* /*
* The threadgroup_fork_lock prevents threads from forking with * group_rwsem prevents new tasks from entering the threadgroup and
* CLONE_THREAD while held for writing. Use this for fork-sensitive * member tasks from exiting,a more specifically, setting of
* threadgroup-wide operations. It's taken for reading in fork.c in * PF_EXITING. fork and exit paths are protected with this rwsem
* copy_process(). * using threadgroup_change_begin/end(). Users which require
* Currently only needed write-side by cgroups. * threadgroup to remain stable should use threadgroup_[un]lock()
* which also takes care of exec path. Currently, cgroup is the
* only user.
*/ */
struct rw_semaphore threadgroup_fork_lock; struct rw_semaphore group_rwsem;
#endif #endif
int oom_adj; /* OOM kill score adjustment (bit shift) */ int oom_adj; /* OOM kill score adjustment (bit shift) */
...@@ -2394,29 +2396,62 @@ static inline void unlock_task_sighand(struct task_struct *tsk, ...@@ -2394,29 +2396,62 @@ static inline void unlock_task_sighand(struct task_struct *tsk,
spin_unlock_irqrestore(&tsk->sighand->siglock, *flags); spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
} }
/* See the declaration of threadgroup_fork_lock in signal_struct. */
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
static inline void threadgroup_fork_read_lock(struct task_struct *tsk) static inline void threadgroup_change_begin(struct task_struct *tsk)
{ {
down_read(&tsk->signal->threadgroup_fork_lock); down_read(&tsk->signal->group_rwsem);
} }
static inline void threadgroup_fork_read_unlock(struct task_struct *tsk) static inline void threadgroup_change_end(struct task_struct *tsk)
{ {
up_read(&tsk->signal->threadgroup_fork_lock); up_read(&tsk->signal->group_rwsem);
} }
static inline void threadgroup_fork_write_lock(struct task_struct *tsk)
/**
* threadgroup_lock - lock threadgroup
* @tsk: member task of the threadgroup to lock
*
* Lock the threadgroup @tsk belongs to. No new task is allowed to enter
* and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
* perform exec. This is useful for cases where the threadgroup needs to
* stay stable across blockable operations.
*
* fork and exit paths explicitly call threadgroup_change_{begin|end}() for
* synchronization. While held, no new task will be added to threadgroup
* and no existing live task will have its PF_EXITING set.
*
* During exec, a task goes and puts its thread group through unusual
* changes. After de-threading, exclusive access is assumed to resources
* which are usually shared by tasks in the same group - e.g. sighand may
* be replaced with a new one. Also, the exec'ing task takes over group
* leader role including its pid. Exclude these changes while locked by
* grabbing cred_guard_mutex which is used to synchronize exec path.
*/
static inline void threadgroup_lock(struct task_struct *tsk)
{ {
down_write(&tsk->signal->threadgroup_fork_lock); /*
* exec uses exit for de-threading nesting group_rwsem inside
* cred_guard_mutex. Grab cred_guard_mutex first.
*/
mutex_lock(&tsk->signal->cred_guard_mutex);
down_write(&tsk->signal->group_rwsem);
} }
static inline void threadgroup_fork_write_unlock(struct task_struct *tsk)
/**
* threadgroup_unlock - unlock threadgroup
* @tsk: member task of the threadgroup to unlock
*
* Reverse threadgroup_lock().
*/
static inline void threadgroup_unlock(struct task_struct *tsk)
{ {
up_write(&tsk->signal->threadgroup_fork_lock); up_write(&tsk->signal->group_rwsem);
mutex_unlock(&tsk->signal->cred_guard_mutex);
} }
#else #else
static inline void threadgroup_fork_read_lock(struct task_struct *tsk) {} static inline void threadgroup_change_begin(struct task_struct *tsk) {}
static inline void threadgroup_fork_read_unlock(struct task_struct *tsk) {} static inline void threadgroup_change_end(struct task_struct *tsk) {}
static inline void threadgroup_fork_write_lock(struct task_struct *tsk) {} static inline void threadgroup_lock(struct task_struct *tsk) {}
static inline void threadgroup_fork_write_unlock(struct task_struct *tsk) {} static inline void threadgroup_unlock(struct task_struct *tsk) {}
#endif #endif
#ifndef __HAVE_THREAD_FUNCTIONS #ifndef __HAVE_THREAD_FUNCTIONS
......
This diff is collapsed.
...@@ -166,13 +166,17 @@ static bool is_task_frozen_enough(struct task_struct *task) ...@@ -166,13 +166,17 @@ static bool is_task_frozen_enough(struct task_struct *task)
*/ */
static int freezer_can_attach(struct cgroup_subsys *ss, static int freezer_can_attach(struct cgroup_subsys *ss,
struct cgroup *new_cgroup, struct cgroup *new_cgroup,
struct task_struct *task) struct cgroup_taskset *tset)
{ {
struct freezer *freezer; struct freezer *freezer;
struct task_struct *task;
/* /*
* Anything frozen can't move or be moved to/from. * Anything frozen can't move or be moved to/from.
*/ */
cgroup_taskset_for_each(task, new_cgroup, tset)
if (cgroup_freezing(task))
return -EBUSY;
freezer = cgroup_freezer(new_cgroup); freezer = cgroup_freezer(new_cgroup);
if (freezer->state != CGROUP_THAWED) if (freezer->state != CGROUP_THAWED)
...@@ -181,11 +185,6 @@ static int freezer_can_attach(struct cgroup_subsys *ss, ...@@ -181,11 +185,6 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
return 0; return 0;
} }
static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
{
return cgroup_freezing(tsk) ? -EBUSY : 0;
}
static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
{ {
struct freezer *freezer; struct freezer *freezer;
...@@ -381,10 +380,5 @@ struct cgroup_subsys freezer_subsys = { ...@@ -381,10 +380,5 @@ struct cgroup_subsys freezer_subsys = {
.populate = freezer_populate, .populate = freezer_populate,
.subsys_id = freezer_subsys_id, .subsys_id = freezer_subsys_id,
.can_attach = freezer_can_attach, .can_attach = freezer_can_attach,
.can_attach_task = freezer_can_attach_task,
.pre_attach = NULL,
.attach_task = NULL,
.attach = NULL,
.fork = freezer_fork, .fork = freezer_fork,
.exit = NULL,
}; };
...@@ -1389,79 +1389,73 @@ static int fmeter_getrate(struct fmeter *fmp) ...@@ -1389,79 +1389,73 @@ static int fmeter_getrate(struct fmeter *fmp)
return val; return val;
} }
/* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
struct task_struct *tsk)
{
struct cpuset *cs = cgroup_cs(cont);
if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
return -ENOSPC;
/*
* Kthreads bound to specific cpus cannot be moved to a new cpuset; we
* cannot change their cpu affinity and isolating such threads by their
* set of allowed nodes is unnecessary. Thus, cpusets are not
* applicable for such threads. This prevents checking for success of
* set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may
* be changed.
*/
if (tsk->flags & PF_THREAD_BOUND)
return -EINVAL;
return 0;
}
static int cpuset_can_attach_task(struct cgroup *cgrp, struct task_struct *task)
{
return security_task_setscheduler(task);
}
/* /*
* Protected by cgroup_lock. The nodemasks must be stored globally because * Protected by cgroup_lock. The nodemasks must be stored globally because
* dynamically allocating them is not allowed in pre_attach, and they must * dynamically allocating them is not allowed in can_attach, and they must
* persist among pre_attach, attach_task, and attach. * persist until attach.
*/ */
static cpumask_var_t cpus_attach; static cpumask_var_t cpus_attach;
static nodemask_t cpuset_attach_nodemask_from; static nodemask_t cpuset_attach_nodemask_from;
static nodemask_t cpuset_attach_nodemask_to; static nodemask_t cpuset_attach_nodemask_to;
/* Set-up work for before attaching each task. */ /* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
static void cpuset_pre_attach(struct cgroup *cont) static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup_taskset *tset)
{ {
struct cpuset *cs = cgroup_cs(cont); struct cpuset *cs = cgroup_cs(cgrp);
struct task_struct *task;
int ret;
if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
return -ENOSPC;
cgroup_taskset_for_each(task, cgrp, tset) {
/*
* Kthreads bound to specific cpus cannot be moved to a new
* cpuset; we cannot change their cpu affinity and
* isolating such threads by their set of allowed nodes is
* unnecessary. Thus, cpusets are not applicable for such
* threads. This prevents checking for success of
* set_cpus_allowed_ptr() on all attached tasks before
* cpus_allowed may be changed.
*/
if (task->flags & PF_THREAD_BOUND)
return -EINVAL;
if ((ret = security_task_setscheduler(task)))
return ret;
}
/* prepare for attach */
if (cs == &top_cpuset) if (cs == &top_cpuset)
cpumask_copy(cpus_attach, cpu_possible_mask); cpumask_copy(cpus_attach, cpu_possible_mask);
else else
guarantee_online_cpus(cs, cpus_attach); guarantee_online_cpus(cs, cpus_attach);
guarantee_online_mems(cs, &cpuset_attach_nodemask_to); guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
}
/* Per-thread attachment work. */
static void cpuset_attach_task(struct cgroup *cont, struct task_struct *tsk)
{
int err;
struct cpuset *cs = cgroup_cs(cont);
/* return 0;
* can_attach beforehand should guarantee that this doesn't fail.
* TODO: have a better way to handle failure here
*/
err = set_cpus_allowed_ptr(tsk, cpus_attach);
WARN_ON_ONCE(err);
cpuset_change_task_nodemask(tsk, &cpuset_attach_nodemask_to);
cpuset_update_task_spread_flag(cs, tsk);
} }
static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup *oldcont, struct task_struct *tsk) struct cgroup_taskset *tset)
{ {
struct mm_struct *mm; struct mm_struct *mm;
struct cpuset *cs = cgroup_cs(cont); struct task_struct *task;
struct cpuset *oldcs = cgroup_cs(oldcont); struct task_struct *leader = cgroup_taskset_first(tset);
struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset);
struct cpuset *cs = cgroup_cs(cgrp);
struct cpuset *oldcs = cgroup_cs(oldcgrp);
cgroup_taskset_for_each(task, cgrp, tset) {
/*
* can_attach beforehand should guarantee that this doesn't
* fail. TODO: have a better way to handle failure here
*/
WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach));
cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to);
cpuset_update_task_spread_flag(cs, task);
}
/* /*
* Change mm, possibly for multiple threads in a threadgroup. This is * Change mm, possibly for multiple threads in a threadgroup. This is
...@@ -1469,7 +1463,7 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont, ...@@ -1469,7 +1463,7 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,
*/ */
cpuset_attach_nodemask_from = oldcs->mems_allowed; cpuset_attach_nodemask_from = oldcs->mems_allowed;
cpuset_attach_nodemask_to = cs->mems_allowed; cpuset_attach_nodemask_to = cs->mems_allowed;
mm = get_task_mm(tsk); mm = get_task_mm(leader);
if (mm) { if (mm) {
mpol_rebind_mm(mm, &cpuset_attach_nodemask_to); mpol_rebind_mm(mm, &cpuset_attach_nodemask_to);
if (is_memory_migrate(cs)) if (is_memory_migrate(cs))
...@@ -1925,9 +1919,6 @@ struct cgroup_subsys cpuset_subsys = { ...@@ -1925,9 +1919,6 @@ struct cgroup_subsys cpuset_subsys = {
.create = cpuset_create, .create = cpuset_create,
.destroy = cpuset_destroy, .destroy = cpuset_destroy,
.can_attach = cpuset_can_attach, .can_attach = cpuset_can_attach,
.can_attach_task = cpuset_can_attach_task,
.pre_attach = cpuset_pre_attach,
.attach_task = cpuset_attach_task,
.attach = cpuset_attach, .attach = cpuset_attach,
.populate = cpuset_populate, .populate = cpuset_populate,
.post_clone = cpuset_post_clone, .post_clone = cpuset_post_clone,
......
...@@ -6941,10 +6941,13 @@ static int __perf_cgroup_move(void *info) ...@@ -6941,10 +6941,13 @@ static int __perf_cgroup_move(void *info)
return 0; return 0;
} }
static void static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
perf_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *task) struct cgroup_taskset *tset)
{ {
task_function_call(task, __perf_cgroup_move, task); struct task_struct *task;
cgroup_taskset_for_each(task, cgrp, tset)
task_function_call(task, __perf_cgroup_move, task);
} }
static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
...@@ -6958,7 +6961,7 @@ static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, ...@@ -6958,7 +6961,7 @@ static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
if (!(task->flags & PF_EXITING)) if (!(task->flags & PF_EXITING))
return; return;
perf_cgroup_attach_task(cgrp, task); task_function_call(task, __perf_cgroup_move, task);
} }
struct cgroup_subsys perf_subsys = { struct cgroup_subsys perf_subsys = {
...@@ -6967,6 +6970,6 @@ struct cgroup_subsys perf_subsys = { ...@@ -6967,6 +6970,6 @@ struct cgroup_subsys perf_subsys = {
.create = perf_cgroup_create, .create = perf_cgroup_create,
.destroy = perf_cgroup_destroy, .destroy = perf_cgroup_destroy,
.exit = perf_cgroup_exit, .exit = perf_cgroup_exit,
.attach_task = perf_cgroup_attach_task, .attach = perf_cgroup_attach,
}; };
#endif /* CONFIG_CGROUP_PERF */ #endif /* CONFIG_CGROUP_PERF */
...@@ -972,7 +972,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) ...@@ -972,7 +972,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sched_autogroup_fork(sig); sched_autogroup_fork(sig);
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
init_rwsem(&sig->threadgroup_fork_lock); init_rwsem(&sig->group_rwsem);
#endif #endif
sig->oom_adj = current->signal->oom_adj; sig->oom_adj = current->signal->oom_adj;
...@@ -1153,7 +1153,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -1153,7 +1153,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->io_context = NULL; p->io_context = NULL;
p->audit_context = NULL; p->audit_context = NULL;
if (clone_flags & CLONE_THREAD) if (clone_flags & CLONE_THREAD)
threadgroup_fork_read_lock(current); threadgroup_change_begin(current);
cgroup_fork(p); cgroup_fork(p);
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
p->mempolicy = mpol_dup(p->mempolicy); p->mempolicy = mpol_dup(p->mempolicy);
...@@ -1368,7 +1368,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -1368,7 +1368,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
proc_fork_connector(p); proc_fork_connector(p);
cgroup_post_fork(p); cgroup_post_fork(p);
if (clone_flags & CLONE_THREAD) if (clone_flags & CLONE_THREAD)
threadgroup_fork_read_unlock(current); threadgroup_change_end(current);
perf_event_fork(p); perf_event_fork(p);
return p; return p;
...@@ -1403,7 +1403,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -1403,7 +1403,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
bad_fork_cleanup_cgroup: bad_fork_cleanup_cgroup:
#endif #endif
if (clone_flags & CLONE_THREAD) if (clone_flags & CLONE_THREAD)
threadgroup_fork_read_unlock(current); threadgroup_change_end(current);
cgroup_exit(p, cgroup_callbacks_done); cgroup_exit(p, cgroup_callbacks_done);
delayacct_tsk_free(p); delayacct_tsk_free(p);
module_put(task_thread_info(p)->exec_domain->module); module_put(task_thread_info(p)->exec_domain->module);
......
...@@ -159,8 +159,7 @@ int res_counter_memparse_write_strategy(const char *buf, ...@@ -159,8 +159,7 @@ int res_counter_memparse_write_strategy(const char *buf,
return 0; return 0;
} }
/* FIXME - make memparse() take const char* args */ *res = memparse(buf, &end);
*res = memparse((char *)buf, &end);
if (*end != '\0') if (*end != '\0')
return -EINVAL; return -EINVAL;
......
...@@ -7563,24 +7563,31 @@ cpu_cgroup_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) ...@@ -7563,24 +7563,31 @@ cpu_cgroup_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
sched_destroy_group(tg); sched_destroy_group(tg);
} }
static int static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
cpu_cgroup_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) struct cgroup_taskset *tset)
{ {
struct task_struct *task;
cgroup_taskset_for_each(task, cgrp, tset) {
#ifdef CONFIG_RT_GROUP_SCHED #ifdef CONFIG_RT_GROUP_SCHED
if (!sched_rt_can_attach(cgroup_tg(cgrp), tsk)) if (!sched_rt_can_attach(cgroup_tg(cgrp), task))
return -EINVAL; return -EINVAL;
#else #else
/* We don't support RT-tasks being in separate groups */ /* We don't support RT-tasks being in separate groups */
if (tsk->sched_class != &fair_sched_class) if (task->sched_class != &fair_sched_class)
return -EINVAL; return -EINVAL;
#endif #endif
}
return 0; return 0;
} }
static void static void cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
cpu_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) struct cgroup_taskset *tset)
{ {
sched_move_task(tsk); struct task_struct *task;
cgroup_taskset_for_each(task, cgrp, tset)
sched_move_task(task);
} }
static void static void
...@@ -7915,8 +7922,8 @@ struct cgroup_subsys cpu_cgroup_subsys = { ...@@ -7915,8 +7922,8 @@ struct cgroup_subsys cpu_cgroup_subsys = {
.name = "cpu", .name = "cpu",
.create = cpu_cgroup_create, .create = cpu_cgroup_create,
.destroy = cpu_cgroup_destroy, .destroy = cpu_cgroup_destroy,
.can_attach_task = cpu_cgroup_can_attach_task, .can_attach = cpu_cgroup_can_attach,
.attach_task = cpu_cgroup_attach_task, .attach = cpu_cgroup_attach,
.exit = cpu_cgroup_exit, .exit = cpu_cgroup_exit,
.populate = cpu_cgroup_populate, .populate = cpu_cgroup_populate,
.subsys_id = cpu_cgroup_subsys_id, .subsys_id = cpu_cgroup_subsys_id,
......
...@@ -2355,8 +2355,15 @@ void exit_signals(struct task_struct *tsk) ...@@ -2355,8 +2355,15 @@ void exit_signals(struct task_struct *tsk)
int group_stop = 0; int group_stop = 0;
sigset_t unblocked; sigset_t unblocked;
/*
* @tsk is about to have PF_EXITING set - lock out users which
* expect stable threadgroup.
*/
threadgroup_change_begin(tsk);
if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) {
tsk->flags |= PF_EXITING; tsk->flags |= PF_EXITING;
threadgroup_change_end(tsk);
return; return;
} }
...@@ -2366,6 +2373,9 @@ void exit_signals(struct task_struct *tsk) ...@@ -2366,6 +2373,9 @@ void exit_signals(struct task_struct *tsk)
* see wants_signal(), do_signal_stop(). * see wants_signal(), do_signal_stop().
*/ */
tsk->flags |= PF_EXITING; tsk->flags |= PF_EXITING;
threadgroup_change_end(tsk);
if (!signal_pending(tsk)) if (!signal_pending(tsk))
goto out; goto out;
......
...@@ -5391,8 +5391,9 @@ static void mem_cgroup_clear_mc(void) ...@@ -5391,8 +5391,9 @@ static void mem_cgroup_clear_mc(void)
static int mem_cgroup_can_attach(struct cgroup_subsys *ss, static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
struct cgroup *cgroup, struct cgroup *cgroup,
struct task_struct *p) struct cgroup_taskset *tset)
{ {
struct task_struct *p = cgroup_taskset_first(tset);
int ret = 0; int ret = 0;
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup); struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup);
...@@ -5430,7 +5431,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, ...@@ -5430,7 +5431,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
struct cgroup *cgroup, struct cgroup *cgroup,
struct task_struct *p) struct cgroup_taskset *tset)
{ {
mem_cgroup_clear_mc(); mem_cgroup_clear_mc();
} }
...@@ -5547,9 +5548,9 @@ static void mem_cgroup_move_charge(struct mm_struct *mm) ...@@ -5547,9 +5548,9 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
static void mem_cgroup_move_task(struct cgroup_subsys *ss, static void mem_cgroup_move_task(struct cgroup_subsys *ss,
struct cgroup *cont, struct cgroup *cont,
struct cgroup *old_cont, struct cgroup_taskset *tset)
struct task_struct *p)
{ {
struct task_struct *p = cgroup_taskset_first(tset);
struct mm_struct *mm = get_task_mm(p); struct mm_struct *mm = get_task_mm(p);
if (mm) { if (mm) {
...@@ -5564,19 +5565,18 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, ...@@ -5564,19 +5565,18 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss,
#else /* !CONFIG_MMU */ #else /* !CONFIG_MMU */
static int mem_cgroup_can_attach(struct cgroup_subsys *ss, static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
struct cgroup *cgroup, struct cgroup *cgroup,
struct task_struct *p) struct cgroup_taskset *tset)
{ {
return 0; return 0;
} }
static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
struct cgroup *cgroup, struct cgroup *cgroup,
struct task_struct *p) struct cgroup_taskset *tset)
{ {
} }
static void mem_cgroup_move_task(struct cgroup_subsys *ss, static void mem_cgroup_move_task(struct cgroup_subsys *ss,
struct cgroup *cont, struct cgroup *cont,
struct cgroup *old_cont, struct cgroup_taskset *tset)
struct task_struct *p)
{ {
} }
#endif #endif
......
...@@ -62,11 +62,12 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task) ...@@ -62,11 +62,12 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
struct cgroup_subsys devices_subsys; struct cgroup_subsys devices_subsys;
static int devcgroup_can_attach(struct cgroup_subsys *ss, static int devcgroup_can_attach(struct cgroup_subsys *ss,
struct cgroup *new_cgroup, struct task_struct *task) struct cgroup *new_cgrp, struct cgroup_taskset *set)
{ {
if (current != task && !capable(CAP_SYS_ADMIN)) struct task_struct *task = cgroup_taskset_first(set);
return -EPERM;
if (current != task && !capable(CAP_SYS_ADMIN))
return -EPERM;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment