cgroups: fix incorrect using rcu_dereference() in cgroup_subsys_state()
PATCH 1/1 cgroups: fix incorrect using rcu_dereference() in cgroup_subsys_state()
It's task->cgroups protected by RCU. and struct css_set.subsys[subsys_id] is readonly(after init). so we don't need rcu_dereference() for struct css_set.subsys[subsys_id].
the ways using cgroup_subsys_state() safely:
#1:rcu_read_lock() / task_lock();
c = cgroup_subsys_state(tsk, id);
use c;rcu_read_unlock() / task_unlock();
#2: use cgroup_lock() for _current_ task.cgroup_lock();
c = cgroup_subsys_state(current, id);
use c;cgroup_unlock();
---
include/linux/cgroup.h +6 -1
@@ -359,10 +360,15 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(return cgrp->subsys[subsys_id]; } +/* Caller must hold task_lock() or rcu_read_lock() */ static inline struct cgroup_subsys_state *task_subsys_state (struct task_struct *task,int subsys_id) { -return rcu_dereference (task->cgroups->subsys[subsys_id]); +/* +* ->subsys[subsys_id] are read-only data, so we do not need +* rcu_dereference() for it. +*/ +return rcu_dereference (task->cgroups)->subsys[subsys_id]; } static inline struct cgroup* task_cgroup(struct task_struct *task,
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 5 lines · Lai Jiangshan
It's
task->cgroupsprotected by RCU. and struct css_set.subsys[subsys_id] is readonly(after init). so we don't needrcu_dereference()for struct css_set.subsys[subsys_id].
Quoted 7 lines
the ways using
cgroup_subsys_state()safely:#1:
rcu_read_lock()/task_lock();
c =cgroup_subsys_state(tsk, id);
use c;rcu_read_unlock()/task_unlock();
You need to qualify that with the fact that if you're just using RCU, the subsys state may no longer be the state for the task that you're interested in, since we don't guarantee that the task won't move directly after you read the state pointer.
Quoted 7 lines
#2: use
cgroup_lock()for _current_ task.cgroup_lock();
c =cgroup_subsys_state(current, id);
use c;cgroup_unlock();
No, if you use cgroup_lock() you can do this for any task. cgroup_lock() is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
include/linux/cgroup.h static inline struct cgroup_subsys_state *cgroup_subsys_state( · line 372
Quoted 10 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{include/linux/cgroup.h +5
-1-return rcu_dereference (task->cgroups->subsys[subsys_id]); +/* +* ->subsys[subsys_id] are read-only data, so we do not need +* rcu_dereference() for it. +*/ +return rcu_dereference (task->cgroups)->subsys[subsys_id]; }
Change looks OK but I think we can lose the additional comment.
Paul
Quoted 5 lines · Lai Jiangshan
It's
task->cgroupsprotected by RCU. and struct css_set.subsys[subsys_id] is readonly(after init). so we don't needrcu_dereference()for struct css_set.subsys[subsys_id].
Quoted 7 lines
the ways using
cgroup_subsys_state()safely:#1:
rcu_read_lock()/task_lock();
c =cgroup_subsys_state(tsk, id);
use c;rcu_read_unlock()/task_unlock();
You need to qualify that with the fact that if you're just using RCU, the subsys state may no longer be the state for the task that you're interested in, since we don't guarantee that the task won't move directly after you read the state pointer.
Quoted 7 lines
#2: use
cgroup_lock()for _current_ task.cgroup_lock();
c =cgroup_subsys_state(current, id);
use c;cgroup_unlock();
No, if you use cgroup_lock() you can do this for any task. cgroup_lock() is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
include/linux/cgroup.h static inline struct cgroup_subsys_state *cgroup_subsys_state( · line 372
Quoted 10 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{include/linux/cgroup.h +5
-1-return rcu_dereference (task->cgroups->subsys[subsys_id]); +/* +* ->subsys[subsys_id] are read-only data, so we do not need +* rcu_dereference() for it. +*/ +return rcu_dereference (task->cgroups)->subsys[subsys_id]; }
Change looks OK but I think we can lose the additional comment.
Paul
A message that is not in the archive (sent off-list or not yet received): 6599ad830811211007s43f0c683s9d56e0aed3af938-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Quoted 25 lines · Paul Menage
Quoted 11 lines · Lai Jiangshan
It's
task->cgroupsprotected by RCU. and struct css_set.subsys[subsys_id] is readonly(after init). so we don't needrcu_dereference()for struct css_set.subsys[subsys_id].the ways using
cgroup_subsys_state()safely:#1:
rcu_read_lock()/task_lock();
c =cgroup_subsys_state(tsk, id);
use c;rcu_read_unlock()/task_unlock();You need to qualify that with the fact that if you're just using RCU, the subsys state may no longer be the state for the task that you're interested in, since we don't guarantee that the task won't move directly after you read the state pointer.
Quoted 6 lines
#2: use
cgroup_lock()for _current_ task.cgroup_lock();
c =cgroup_subsys_state(current, id);
use c;cgroup_unlock();
Quoted 3 lines
No, if you use
cgroup_lock()you can do this for any task.cgroup_lock()is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
cgroup_exit() will defeat you.
Quoted 11 lines
Review
Quoted 10 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{(quoted diff) +5
-1- return rcu_dereference(task->cgroups->subsys[subsys_id]); + /* + * ->subsys[subsys_id] are read-only data, so we do not need + * rcu_dereference() for it. + */ + return rcu_dereference(task->cgroups)->subsys[subsys_id]; }
Quoted 6 lines
Change looks OK but I think we can lose the additional comment.
Paul
I just remembered I had deferred Li Zefan's patch.
(I'm also RCU developer, I had been writing CGROUP VS RCU then, I thought these patches should be sent together, So I deferred his patch)
From: Li Zefan <[email protected]>
Date: Mon, 25 Aug 2008 11:05:28 +0800
Subject: [PATCH] cgroup: fix wrong rcu_dereference()
It is tsk->cgroups which is protected by RCU.
--- include/linux/cgroup.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/cgroup.h +1 -1
@@ -355,7 +355,7 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(static inline struct cgroup_subsys_state *task_subsys_state (struct task_struct *task,int subsys_id) { -return rcu_dereference (task->cgroups->subsys[subsys_id]); +return rcu_dereference (task->cgroups)->subsys[subsys_id]; } static inline struct cgroup* task_cgroup(struct task_struct *task,
Quoted 25 lines · Paul Menage
Quoted 11 lines · Lai Jiangshan
It's
task->cgroupsprotected by RCU. and struct css_set.subsys[subsys_id] is readonly(after init). so we don't needrcu_dereference()for struct css_set.subsys[subsys_id].the ways using
cgroup_subsys_state()safely:#1:
rcu_read_lock()/task_lock();
c =cgroup_subsys_state(tsk, id);
use c;rcu_read_unlock()/task_unlock();You need to qualify that with the fact that if you're just using RCU, the subsys state may no longer be the state for the task that you're interested in, since we don't guarantee that the task won't move directly after you read the state pointer.
Quoted 6 lines
#2: use
cgroup_lock()for _current_ task.cgroup_lock();
c =cgroup_subsys_state(current, id);
use c;cgroup_unlock();
Quoted 3 lines
No, if you use
cgroup_lock()you can do this for any task.cgroup_lock()is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
cgroup_exit() will defeat you.
Quoted 11 lines
Review
Quoted 10 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{(quoted diff) +5
-1- return rcu_dereference(task->cgroups->subsys[subsys_id]); + /* + * ->subsys[subsys_id] are read-only data, so we do not need + * rcu_dereference() for it. + */ + return rcu_dereference(task->cgroups)->subsys[subsys_id]; }
Quoted 6 lines
Change looks OK but I think we can lose the additional comment.
Paul
I just remembered I had deferred Li Zefan's patch.
(I'm also RCU developer, I had been writing CGROUP VS RCU then, I thought these patches should be sent together, So I deferred his patch)
From: Li Zefan <[email protected]>
Date: Mon, 25 Aug 2008 11:05:28 +0800
Subject: [PATCH] cgroup: fix wrong rcu_dereference()
It is tsk->cgroups which is protected by RCU.
--- include/linux/cgroup.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/cgroup.h +1 -1
@@ -355,7 +355,7 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(static inline struct cgroup_subsys_state *task_subsys_state (struct task_struct *task,int subsys_id) { -return rcu_dereference (task->cgroups->subsys[subsys_id]); +return rcu_dereference (task->cgroups)->subsys[subsys_id]; } static inline struct cgroup* task_cgroup(struct task_struct *task,
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 5 lines · Lai Jiangshan
Quoted 3 lines
No, if you use
cgroup_lock()you can do this for any task.cgroup_lock()is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
cgroup_exit()will defeat you.
Ah, good point. You should mention that in your description of the locking rules. But it would be nice if we could get rid of that restriction.
Paul
Quoted 49 lines
Quoted 12 lines
Review
Quoted 11 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{(quoted diff) +5
-1- return rcu_dereference(task->cgroups->subsys[subsys_id]); + /* + * ->subsys[subsys_id] are read-only data, so we do not need + * rcu_dereference() for it. + */ + return rcu_dereference(task->cgroups)->subsys[subsys_id]; }Quoted 6 lines
Change looks OK but I think we can lose the additional comment.
Paul
I just remembered I had deferred Li Zefan's patch.
(I'm also RCU developer, I had been writing CGROUP VS RCU then, I thought these patches should be sent together, So I deferred his patch)From: Li Zefan <[email protected]>
Date: Mon, 25 Aug 2008 11:05:28 +0800
Subject: [PATCH] cgroup: fix wrongrcu_dereference()It is
tsk->cgroupswhich is protected by RCU.Signed-off-by Li Zefan <[email protected]>--- include/linux/cgroup.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)include/linux/cgroup.h +1
-1@@ -355,7 +355,7 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(static inline struct cgroup_subsys_state *task_subsys_state (struct task_struct *task,int subsys_id) { -return rcu_dereference (task->cgroups->subsys[subsys_id]); +return rcu_dereference (task->cgroups)->subsys[subsys_id]; } static inline struct cgroup* task_cgroup(struct task_struct *task,
Quoted 5 lines · Lai Jiangshan
Quoted 3 lines
No, if you use
cgroup_lock()you can do this for any task.cgroup_lock()is the cgroups equivalent of the BKL, and definitely prevents all task movement between groups.
cgroup_exit()will defeat you.
Ah, good point. You should mention that in your description of the locking rules. But it would be nice if we could get rid of that restriction.
Paul
Quoted 49 lines
Quoted 12 lines
Review
Quoted 11 lines
static inline struct
cgroup_subsys_state*task_subsys_state(
structtask_struct*task, intsubsys_id)
{(quoted diff) +5
-1- return rcu_dereference(task->cgroups->subsys[subsys_id]); + /* + * ->subsys[subsys_id] are read-only data, so we do not need + * rcu_dereference() for it. + */ + return rcu_dereference(task->cgroups)->subsys[subsys_id]; }Quoted 6 lines
Change looks OK but I think we can lose the additional comment.
Paul
I just remembered I had deferred Li Zefan's patch.
(I'm also RCU developer, I had been writing CGROUP VS RCU then, I thought these patches should be sent together, So I deferred his patch)From: Li Zefan <[email protected]>
Date: Mon, 25 Aug 2008 11:05:28 +0800
Subject: [PATCH] cgroup: fix wrongrcu_dereference()It is
tsk->cgroupswhich is protected by RCU.Signed-off-by Li Zefan <[email protected]>--- include/linux/cgroup.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)include/linux/cgroup.h +1
-1@@ -355,7 +355,7 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(static inline struct cgroup_subsys_state *task_subsys_state (struct task_struct *task,int subsys_id) { -return rcu_dereference (task->cgroups->subsys[subsys_id]); +return rcu_dereference (task->cgroups)->subsys[subsys_id]; } static inline struct cgroup* task_cgroup(struct task_struct *task,