Skip to contentSkip to conversation

Is not locking task_lock in cgroup_fork() safe?

PATCH In review Tejun Heo 6 participants 45 messages Oct 8, 2012 – Oct 22, 2012 12 messages not in the archive cgroup

lore
Share & tools
lore

Tejun Heo

author
#0 lore raw

Hello, Frederic.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Thanks.

Signature · 1 line
tejun
author
#1 lore raw
Quoted 7 lines · Tejun Heo

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Thanks.

Signature · 1 line
tejun
#2 lore raw
Quoted 8 lines · Tejun Heo
Quoted 7 lines · Tejun Heo

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 4 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#4 lore raw

Hello, Li, Frederic.

Quoted 8 lines · Li Zefan

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 2 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

There are other commits which perform similar optimization

7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Are they wrong too?

Thanks.

Signature · 1 line
tejun
author
#5 lore raw
Quoted 10 lines · Tejun Heo

Hello, Li, Frederic.

Quoted 7 lines · Li Zefan

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 2 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Quoted 8 lines
Quoted 1 line

Reverting that commit should be fine.

There are other commits which perform similar optimization

7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Are they wrong too?

Frederic, Li, Ping?

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw
Quoted 13 lines · Tejun Heo
Quoted 12 lines · Tejun Heo

Hello, Li, Frederic.

Quoted 8 lines · Li Zefan

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 2 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

Quoted 9 lines
Quoted 6 lines

There are other commits which perform similar optimization

7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Are they wrong too?

Frederic, Li, Ping?

Yes, they're wrong. I sugguest we revert those commits, and then fix cgroup_attach_task_all() and others if still any.

#8 lore raw
In reply to a message not in the archive
Quoted 13 lines · Tejun Heo
Quoted 12 lines · Tejun Heo

Hello, Li, Frederic.

Quoted 8 lines · Li Zefan

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 2 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

Quoted 9 lines
Quoted 6 lines

There are other commits which perform similar optimization

7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Are they wrong too?

Frederic, Li, Ping?

Yes, they're wrong. I sugguest we revert those commits, and then fix cgroup_attach_task_all() and others if still any.

_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers

author
#9 lore raw
In reply to a message not in the archive

Hello, Li, Frederic.

Quoted 8 lines · Li Zefan

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 2 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

There are other commits which perform similar optimization

7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Are they wrong too?

Thanks.

Signature · 1 line
tejun
#10 lore raw
In reply to Tejun Heo
Quoted 8 lines · Tejun Heo
Quoted 7 lines · Tejun Heo

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

You're right. threadgroup lock is held unconditionally in attach_task_py_pid(), but it's held only for CLONE_THREAD in fork path, which I guess I overlooked when reviewing the patch.

Quoted 4 lines

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Reverting that commit should be fine.

#11 lore raw
In reply to Tejun Heo

2012/10/8 Tejun Heo <[email protected]>:

Quoted 11 lines · Tejun Heo
Quoted 7 lines

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Locks are expensive anyway. And I think cgroup has enough of them in that hot path that fork is (threadgroup_lock, css_set_lock, ...)

#12 lore raw
In reply to Tejun Heo

2012/10/8 Tejun Heo <[email protected]>:

Quoted 11 lines · Tejun Heo
Quoted 7 lines

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Also, please note that task_lock is likely to be hot on local CPU at that point and avoiding it there might not really buy much.

Locks are expensive anyway. And I think cgroup has enough of them in that hot path that fork is (threadgroup_lock, css_set_lock, ...)

#13 lore raw
In reply to Tejun Heo

2012/10/8 Tejun Heo <[email protected]>:

Quoted 9 lines

Hello, Frederic.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Yeah I missed this one.
Now the whole cgroup_attach_task() is clusteracy without the threadgroup lock anyway:

* The PF_EXITING check is racy (we are neither holding tsk->flags nor threagroup lock).
* The cgrp == oldcgrp is racy (exit() can change the oldcgrp anytime.
* can_attach / attach / cancel_attach can race against fork/exit (and post_fork if you consider those interested in cgroup task link like the freezer. But that is racy in any case already even with threadgroup lock)

It has been designed to be called under that lock. So I suspect the best, at least for now, is to threadgroup lock from cgroup_attach_task_all(). And also make cgroup_attach_task() static to avoid future unsafe callers.
There is no harm yet because the only user of it calls that with current as the "task" parameter, in a place that is
not in the middle of a fork. So no need to worry about some stable backport.

Also, looking at cgroup_attach_task_all(), what guarantee do we have that "from" is not concurrently exiting and removing its cgrp. Which is a separate problem. But we probably need to do some css_set_get() before playing with it.

A message that is not in the archive (sent off-list or not yet received): CAFTL4hzXWtzp7megsCAEuak5=_2SWmp9age-+wrpyQAU4BRZ0w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

author
#15 lore raw

Hey, Frederic.

Quoted 2 lines · Frederic Weisbecker

Yeah I missed this one.
Now the whole cgroup_attach_task() is clusteracy without the

Clusteracy?

Quoted 4 lines

threadgroup lock anyway:

* The PF_EXITING check is racy (we are neither holding tsk->flags nor threagroup lock).

PF_EXITING is *always* protected by threadgroup_change_begin/end().

Quoted 1 line

* The cgrp == oldcgrp is racy (exit() can change the oldcgrp anytime.

So, as long as this happens after PF_EXITING check, it should be safe.

Quoted 4 lines

* can_attach / attach / cancel_attach can race against fork/exit (and post_fork if you consider those interested in cgroup task link like the freezer. But that is racy in any case already even with threadgroup lock)

Against exit, no. Against forking a new process, can they? If so, we need to fix it.

Quoted 1 line

It has been designed to be called under that lock. So I suspect the

Ummm.... threadgroup_lock is a recent addition so things couldn't have been designed to be called under that lock. threadgroup_lock protects the *threadgroup* - creating a new task in the same process or a task of the process exiting. It doesn't do anything about other processes. In fact, the lock itself is per-process.

Quoted 3 lines

best, at least for now, is to threadgroup lock from cgroup_attach_task_all(). And also make cgroup_attach_task() static to avoid future unsafe callers.

Oh, from that call path, sure. Can someone teach me why we need that one at all? I think we're confusing each other here. I was talking about the usual migration path not protected against forking a new process.

Quoted 8 lines

There is no harm yet because the only user of it calls that with current as the "task" parameter, in a place that is
not in the middle of a fork. So no need to worry about some stable backport.

Also, looking at cgroup_attach_task_all(), what guarantee do we have that "from" is not concurrently exiting and removing its cgrp. Which is a separate problem. But we probably need to do some css_set_get() before playing with it.

I really don't know. Why isn't it locking the threadgroup to begin with?

Thanks.

Signature · 1 line
tejun
#16 lore raw

2012/10/16 Tejun Heo <[email protected]>:

Quoted 35 lines

Hey, Frederic.

Quoted 2 lines · Frederic Weisbecker

Yeah I missed this one.
Now the whole cgroup_attach_task() is clusteracy without the

Clusteracy?

Quoted 4 lines

threadgroup lock anyway:

* The PF_EXITING check is racy (we are neither holding tsk->flags nor threagroup lock).

PF_EXITING is *always* protected by threadgroup_change_begin/end().

Quoted 1 line

* The cgrp == oldcgrp is racy (exit() can change the oldcgrp anytime.

So, as long as this happens after PF_EXITING check, it should be safe.

Quoted 4 lines

* can_attach / attach / cancel_attach can race against fork/exit (and post_fork if you consider those interested in cgroup task link like the freezer. But that is racy in any case already even with threadgroup lock)

Against exit, no. Against forking a new process, can they? If so, we need to fix it.

Quoted 1 line

It has been designed to be called under that lock. So I suspect the

Ummm.... threadgroup_lock is a recent addition so things couldn't have been designed to be called under that lock. threadgroup_lock protects the *threadgroup* - creating a new task in the same process or a task of the process exiting. It doesn't do anything about other processes. In fact, the lock itself is per-process.

Quoted 8 lines
Quoted 3 lines

best, at least for now, is to threadgroup lock from cgroup_attach_task_all(). And also make cgroup_attach_task() static to avoid future unsafe callers.

Oh, from that call path, sure. Can someone teach me why we need that one at all? I think we're confusing each other here. I was talking about the usual migration path not protected against forking a new process.

Ah right I was confused. Hmm, indeed we have a race here on cgroup_fork(). How about using css_try_get() in cgroup_fork() and refetch the parent's css until we succeed? This requires rcu_read_lock though, and freeing the css_set under RCU.

Don't know which is better.

Different problem but I really would like we sanitize the cgroup hooks in fork. There is cgroup_fork(), cgroup_post_fork() which takes that big css_set_lock, plus the big threadgroup lock... I hope we can simplify the mess there.

Quoted 5 lines
Quoted 5 lines

There is no harm yet because the only user of it calls that with current as the "task" parameter, in a place that is
not in the middle of a fork. So no need to worry about some stable backport.

Quoted 7 lines
Quoted 4 lines

Also, looking at cgroup_attach_task_all(), what guarantee do we have that "from" is not concurrently exiting and removing its cgrp. Which is a separate problem. But we probably need to do some css_set_get() before playing with it.

I really don't know. Why isn't it locking the threadgroup to begin with?

No idea, sounds like something to fix.

maintainer
#17 lore raw

Hello, Frederic.

Quoted 6 lines · Frederic Weisbecker

Ah right I was confused. Hmm, indeed we have a race here on cgroup_fork(). How about using css_try_get() in cgroup_fork() and refetch the parent's css until we succeed? This requires rcu_read_lock though, and freeing the css_set under RCU.

Don't know which is better.

For now, I'll revert the patches and cc stable. Let's think about improving it later.

Quoted 4 lines

Different problem but I really would like we sanitize the cgroup hooks in fork. There is cgroup_fork(), cgroup_post_fork() which takes that big css_set_lock, plus the big threadgroup lock... I hope we can simplify the mess there.

Oh yeah, I've been looking at that one too. There are a few problems in that area. I think all we need is clearing ->cgroups to NULL on copy_process() and all the rest can be moved to cgroup_post_fork(). I'd also like to make it very explicit that migration can't happen before post_fork is complete.

Quoted 4 lines
Quoted 2 lines

I really don't know. Why isn't it locking the threadgroup to begin with?

No idea, sounds like something to fix.

Alrighty.

Thanks.

Signature · 1 line
tejun
#18 lore raw

2012/10/18 Tejun Heo <[email protected]>:

Quoted 8 lines

Hello, Frederic.

Quoted 5 lines · Frederic Weisbecker

Ah right I was confused. Hmm, indeed we have a race here on cgroup_fork(). How about using css_try_get() in cgroup_fork() and refetch the parent's css until we succeed? This requires rcu_read_lock though, and freeing the css_set under RCU.

Quoted 4 lines
Quoted 1 line

Don't know which is better.

For now, I'll revert the patches and cc stable. Let's think about improving it later.

Ok for reverting in cgroup_fork(). Is it necessary for the cgroup_post_fork() thing? I don't immediately see any race involved there.

Quoted 10 lines
Quoted 4 lines

Different problem but I really would like we sanitize the cgroup hooks in fork. There is cgroup_fork(), cgroup_post_fork() which takes that big css_set_lock, plus the big threadgroup lock... I hope we can simplify the mess there.

Oh yeah, I've been looking at that one too. There are a few problems in that area. I think all we need is clearing ->cgroups to NULL on copy_process() and all the rest can be moved to cgroup_post_fork(). I'd also like to make it very explicit that migration can't happen before post_fork is complete.

Sounds right.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

I really don't know. Why isn't it locking the threadgroup to begin with?

No idea, sounds like something to fix.

Alrighty.

Ok thanks.

Quoted 4 lines

Thanks.

--
tejun

maintainer
#19 lore raw

Hello, Frederic.

Quoted 6 lines · Frederic Weisbecker
Quoted 2 lines

For now, I'll revert the patches and cc stable. Let's think about improving it later.

Ok for reverting in cgroup_fork(). Is it necessary for the cgroup_post_fork() thing? I don't immediately see any race involved there.

Even if there isn't an actual race, the comment is dead wrong. I'm reverting the following three patches. Let's try again later.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()")
7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Thanks.

Signature · 1 line
tejun
maintainer
#20 lore raw

Hello, again.

Quoted 5 lines · Tejun Heo

Even if there isn't an actual race, the comment is dead wrong. I'm reverting the following three patches. Let's try again later.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") 7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()")

So, after some more looking, I think the following is correct and doesn't need to be reverted. It's depending on threadgroup locking from migration path to synchronize against exit path which is always performed.

Quoted 1 line

c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Frederic, were you trying to say that the above commit is correct? Li, do you agree?

Thanks.

Signature · 1 line
tejun
#21 lore raw
Quoted 14 lines · Tejun Heo

Hello, again.

Quoted 5 lines · Tejun Heo

Even if there isn't an actual race, the comment is dead wrong. I'm reverting the following three patches. Let's try again later.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") 7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()")

So, after some more looking, I think the following is correct and doesn't need to be reverted. It's depending on threadgroup locking from migration path to synchronize against exit path which is always performed.

Quoted 5 lines
Quoted 1 line

c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Frederic, were you trying to say that the above commit is correct? Li, do you agree?

This one does look innocent.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#23 lore raw
Quoted 14 lines · Tejun Heo

Hello, again.

Quoted 5 lines · Tejun Heo

Even if there isn't an actual race, the comment is dead wrong. I'm reverting the following three patches. Let's try again later.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") 7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()")

So, after some more looking, I think the following is correct and doesn't need to be reverted. It's depending on threadgroup locking from migration path to synchronize against exit path which is always performed.

Quoted 5 lines
Quoted 1 line

c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Frederic, were you trying to say that the above commit is correct? Li, do you agree?

This one does look innocent.

A message that is not in the archive (sent off-list or not yet received): CAFTL4hy7g4e11OUOyoihrEU8hiVgZoV1=141UtUpj9a72SNs_Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

author
#25 lore raw

Hello, Frederic.

Quoted 6 lines · Frederic Weisbecker
Quoted 2 lines

For now, I'll revert the patches and cc stable. Let's think about improving it later.

Ok for reverting in cgroup_fork(). Is it necessary for the cgroup_post_fork() thing? I don't immediately see any race involved there.

Even if there isn't an actual race, the comment is dead wrong. I'm reverting the following three patches. Let's try again later.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()")
7e3aa30ac8 ("cgroup: Remove task_lock() from cgroup_post_fork()") c84cdf75cc ("cgroup: Remove unnecessary task_lock before fetching css_set on migration")

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): [email protected]

#27 lore raw

2012/10/16 Tejun Heo <[email protected]>:

Quoted 35 lines

Hey, Frederic.

Quoted 2 lines · Frederic Weisbecker

Yeah I missed this one.
Now the whole cgroup_attach_task() is clusteracy without the

Clusteracy?

Quoted 4 lines

threadgroup lock anyway:

* The PF_EXITING check is racy (we are neither holding tsk->flags nor threagroup lock).

PF_EXITING is *always* protected by threadgroup_change_begin/end().

Quoted 1 line

* The cgrp == oldcgrp is racy (exit() can change the oldcgrp anytime.

So, as long as this happens after PF_EXITING check, it should be safe.

Quoted 4 lines

* can_attach / attach / cancel_attach can race against fork/exit (and post_fork if you consider those interested in cgroup task link like the freezer. But that is racy in any case already even with threadgroup lock)

Against exit, no. Against forking a new process, can they? If so, we need to fix it.

Quoted 1 line

It has been designed to be called under that lock. So I suspect the

Ummm.... threadgroup_lock is a recent addition so things couldn't have been designed to be called under that lock. threadgroup_lock protects the *threadgroup* - creating a new task in the same process or a task of the process exiting. It doesn't do anything about other processes. In fact, the lock itself is per-process.

Quoted 8 lines
Quoted 3 lines

best, at least for now, is to threadgroup lock from cgroup_attach_task_all(). And also make cgroup_attach_task() static to avoid future unsafe callers.

Oh, from that call path, sure. Can someone teach me why we need that one at all? I think we're confusing each other here. I was talking about the usual migration path not protected against forking a new process.

Ah right I was confused. Hmm, indeed we have a race here on cgroup_fork(). How about using css_try_get() in cgroup_fork() and refetch the parent's css until we succeed? This requires rcu_read_lock though, and freeing the css_set under RCU.

Don't know which is better.

Different problem but I really would like we sanitize the cgroup hooks in fork. There is cgroup_fork(), cgroup_post_fork() which takes that big css_set_lock, plus the big threadgroup lock... I hope we can simplify the mess there.

Quoted 5 lines
Quoted 5 lines

There is no harm yet because the only user of it calls that with current as the "task" parameter, in a place that is
not in the middle of a fork. So no need to worry about some stable backport.

Quoted 7 lines
Quoted 4 lines

Also, looking at cgroup_attach_task_all(), what guarantee do we have that "from" is not concurrently exiting and removing its cgrp. Which is a separate problem. But we probably need to do some css_set_get() before playing with it.

I really don't know. Why isn't it locking the threadgroup to begin with?

No idea, sounds like something to fix.

#28 lore raw
In reply to Tejun Heo

2012/10/8 Tejun Heo <[email protected]>:

Quoted 9 lines

Hello, Frederic.

7e381b0eb1 ("cgroup: Drop task_lock(parent) on cgroup_fork()") removed task_lock from cgroup_fork citing that current->cgroups can't change due to threadgroup_change locking; however, threadgroup_change locking is used only during CLONE_THREAD forking. If @current is forking a new process, there's nothing preventing someone else to migrate the parent while forking is in progress and delete the css_set it currently is using. Am I confused somewhere?

Yeah I missed this one.
Now the whole cgroup_attach_task() is clusteracy without the threadgroup lock anyway:

* The PF_EXITING check is racy (we are neither holding tsk->flags nor threagroup lock).
* The cgrp == oldcgrp is racy (exit() can change the oldcgrp anytime.
* can_attach / attach / cancel_attach can race against fork/exit (and post_fork if you consider those interested in cgroup task link like the freezer. But that is racy in any case already even with threadgroup lock)

It has been designed to be called under that lock. So I suspect the best, at least for now, is to threadgroup lock from cgroup_attach_task_all(). And also make cgroup_attach_task() static to avoid future unsafe callers.
There is no harm yet because the only user of it calls that with current as the "task" parameter, in a place that is
not in the middle of a fork. So no need to worry about some stable backport.

Also, looking at cgroup_attach_task_all(), what guarantee do we have that "from" is not concurrently exiting and removing its cgrp. Which is a separate problem. But we probably need to do some css_set_get() before playing with it.

author
#29 lore raw

PATCH 1/2 Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to Tejun Heo

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
kernel/cgroup.c +3 -12
index d1739fc..2990dc7 100644
@@ -4894,19 +4894,10 @@ void cgroup_post_fork(struct task_struct *child)
 	 */
 	if (use_task_css_set_links) {
 		write_lock(&css_set_lock);
-		if (list_empty(&child->cg_list)) {
-			/*
-			 * It's safe to use child->cgroups without task_lock()
-			 * here because we are protected through
-			 * threadgroup_change_begin() against concurrent
-			 * css_set change in cgroup_task_migrate(). Also
-			 * the task can't exit at that point until
-			 * wake_up_new_task() is called, so we are protected
-			 * against cgroup_exit() setting child->cgroup to
-			 * init_css_set.
-			 */
+		task_lock(child);
+		if (list_empty(&child->cg_list))
 			list_add(&child->cg_list, &child->cgroups->tasks);
-		}
+		task_unlock(child);
 		write_unlock(&css_set_lock);
 	}
 }
Signature · 1 line
1.7.7.3

A message that is not in the archive (sent off-list or not yet received): [email protected]

Acked-by
#31 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

Quoted 16 lines · Tejun Heo
Quoted 1 line

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001

From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 7 lines

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

#32 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to a message not in the archive

2012/10/18 Tejun Heo <[email protected]>:

Quoted 11 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

Quoted 6 lines

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

Quoted 40 lines

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
kernel/cgroup.c +3 -13
index d1739fc..2990dc7 100644
@@ -4894,19 +4894,10 @@ void cgroup_post_fork(struct task_struct *child)
         */
        if (use_task_css_set_links) {
                write_lock(&css_set_lock);
-               if (list_empty(&child->cg_list)) {
-                       /*
-                        * It's safe to use child->cgroups without task_lock()
-                        * here because we are protected through
-                        * threadgroup_change_begin() against concurrent
-                        * css_set change in cgroup_task_migrate(). Also
-                        * the task can't exit at that point until
-                        * wake_up_new_task() is called, so we are protected
-                        * against cgroup_exit() setting child->cgroup to
-                        * init_css_set.
-                        */
+               task_lock(child);
+               if (list_empty(&child->cg_list))
                        list_add(&child->cg_list, &child->cgroups->tasks);
-               }
+               task_unlock(child);
                write_unlock(&css_set_lock);
        }
 }
--

1.7.7.3

A message that is not in the archive (sent off-list or not yet received): CAFTL4hz82==b3ioSMhbKzh0CN1ivR7RQMKKMFFWu5PHPjg=Bfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

author
#34 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

Quoted 17 lines · Frederic Weisbecker

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 5 lines
Quoted 1 line

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

Thanks.

Signature · 1 line
tejun
#35 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/19 Tejun Heo <[email protected]>:

Quoted 18 lines · Frederic Weisbecker
Quoted 17 lines

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

I don't think that a wrong comment justifies a patch to stable.

maintainer
#36 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

Hello, Frederic.

Quoted 4 lines · Frederic Weisbecker
Quoted 2 lines

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

I don't think that a wrong comment justifies a patch to stable.

I'm not really sure whether it's safe or not. It seems all usages are protected by write locking css_set_lock but maybe I'm missing something and as the commit is born out of confusion, I'm very inclined to revert it by default. Are you sure this one is safe?

Thanks.

Signature · 1 line
tejun
#37 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/19 Tejun Heo <[email protected]>:

Quoted 6 lines

Hello, Frederic.

Quoted 3 lines · Frederic Weisbecker
Quoted 2 lines

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

Quoted 6 lines
Quoted 1 line

I don't think that a wrong comment justifies a patch to stable.

I'm not really sure whether it's safe or not. It seems all usages are protected by write locking css_set_lock but maybe I'm missing something and as the commit is born out of confusion, I'm very inclined to revert it by default. Are you sure this one is safe?

Thinking about it further, one scenario is worrying me but it eventually looks safe but by accident.

CPU 0
CPU 1

cgroup_task_migrate {
        task_lock(p)
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);

        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
            list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);

                          write_lock(&css_set_lock);
	put_css_set(oldcg);
         list_add(&child->cg_list, &child->cgroups->tasks); (1)

On (1), child->cgroups should have the value of newcg and not oldcg due to the memory ordering implied by the locking of css_set_lock. Now I can't guarantee that because I'm no memory ordering expert. And even if it's safe, it's so very non obvious that I now agree with you:
let's revert the patch and restart with a better base by gathering all the cgroup fork code in the current cgroup_post_fork place.

Thanks.

#38 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/20 Frederic Weisbecker <[email protected]>:

Quoted 20 lines

2012/10/19 Tejun Heo <[email protected]>:

Quoted 6 lines

Hello, Frederic.

Quoted 3 lines · Frederic Weisbecker
Quoted 2 lines

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

Quoted 6 lines
Quoted 1 line

I don't think that a wrong comment justifies a patch to stable.

I'm not really sure whether it's safe or not. It seems all usages are protected by write locking css_set_lock but maybe I'm missing something and as the commit is born out of confusion, I'm very inclined to revert it by default. Are you sure this one is safe?

Thinking about it further, one scenario is worrying me but it eventually looks safe but by accident.

CPU 0
CPU 1

Quoted 13 lines
cgroup_task_migrate {
        task_lock(p)
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);

        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
            list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);

                          write_lock(&css_set_lock);
        put_css_set(oldcg);
         list_add(&child->cg_list, &child->cgroups->tasks); (1)

gmail mangled everything :(

maintainer
#39 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to Frederic Weisbecker

Hello, Frederic.

Quoted 16 lines · Frederic Weisbecker

CPU 0
CPU 1

cgroup_task_migrate {
        task_lock(p)
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);

        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
            list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);

                          write_lock(&css_set_lock);
	put_css_set(oldcg);
         list_add(&child->cg_list, &child->cgroups->tasks); (1)

Man, that's confusing. :)

Quoted 6 lines

On (1), child->cgroups should have the value of newcg and not oldcg due to the memory ordering implied by the locking of css_set_lock. Now I can't guarantee that because I'm no memory ordering expert. And even if it's safe, it's so very non obvious that I now agree with you:
let's revert the patch and restart with a better base by gathering all the cgroup fork code in the current cgroup_post_fork place.

Aye aye, let's move everything to cgroup_post_fork() and then we don't have to worry about grabbing task_lock multiple times.

Thanks.

Signature · 1 line
tejun
#40 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/21 Tejun Heo <[email protected]>:

Quoted 16 lines

Hello, Frederic.

Quoted 13 lines · Frederic Weisbecker

CPU 0
CPU 1

cgroup_task_migrate {
        task_lock(p)
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);

        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
            list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);
Quoted 5 lines
Quoted 3 lines
                          write_lock(&css_set_lock);
      put_css_set(oldcg);
         list_add(&child->cg_list, &child->cgroups->tasks); (1)

Man, that's confusing. :)

Sorry and I'm currently stuck in some airport and too lazy to reorder the above lines :)

Quoted 10 lines
Quoted 7 lines

On (1), child->cgroups should have the value of newcg and not oldcg due to the memory ordering implied by the locking of css_set_lock. Now I can't guarantee that because I'm no memory ordering expert. And even if it's safe, it's so very non obvious that I now agree with you:
let's revert the patch and restart with a better base by gathering all the cgroup fork code in the current cgroup_post_fork place.

Aye aye, let's move everything to cgroup_post_fork() and then we don't have to worry about grabbing task_lock multiple times.

Agreed. and Acked-by: Frederic Weisbecker <[email protected]>

A message that is not in the archive (sent off-list or not yet received): 20121020223709.GA5626-Gd/HAXX7CRxy/[email protected]

#42 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/21 Tejun Heo <[email protected]>:

Quoted 16 lines

Hello, Frederic.

Quoted 13 lines · Frederic Weisbecker

CPU 0
CPU 1

cgroup_task_migrate {
        task_lock(p)
        rcu_assign_pointer(tsk->cgroups, newcg);
        task_unlock(tsk);

        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
            list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);
Quoted 5 lines
Quoted 3 lines
                          write_lock(&css_set_lock);
      put_css_set(oldcg);
         list_add(&child->cg_list, &child->cgroups->tasks); (1)

Man, that's confusing. :)

Sorry and I'm currently stuck in some airport and too lazy to reorder the above lines :)

Quoted 10 lines
Quoted 7 lines

On (1), child->cgroups should have the value of newcg and not oldcg due to the memory ordering implied by the locking of css_set_lock. Now I can't guarantee that because I'm no memory ordering expert. And even if it's safe, it's so very non obvious that I now agree with you:
let's revert the patch and restart with a better base by gathering all the cgroup fork code in the current cgroup_post_fork place.

Aye aye, let's move everything to cgroup_post_fork() and then we don't have to worry about grabbing task_lock multiple times.

Agreed. and Acked-by: Frederic Weisbecker <[email protected]>

A message that is not in the archive (sent off-list or not yet received): CAFTL4hwQ6Ntn5GJwj=jiO2p3GdwhEMp0MyR8dgUj_Lx0U4kNqg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

author
#44 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

Hello, Frederic.

Quoted 4 lines · Frederic Weisbecker
Quoted 2 lines

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

I don't think that a wrong comment justifies a patch to stable.

I'm not really sure whether it's safe or not. It seems all usages are protected by write locking css_set_lock but maybe I'm missing something and as the commit is born out of confusion, I'm very inclined to revert it by default. Are you sure this one is safe?

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): [email protected]

#46 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

2012/10/19 Tejun Heo <[email protected]>:

Quoted 18 lines · Frederic Weisbecker
Quoted 17 lines

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

I don't think that a wrong comment justifies a patch to stable.

author
#47 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to a message not in the archive
Quoted 17 lines · Frederic Weisbecker

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 5 lines
Quoted 1 line

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

For -stable, I think it's better to revert. If you want to remove task_lock, let's do it for 3.8.

Thanks.

Signature · 1 line
tejun
#48 lore raw

Re: [PATCH cgroup/for-3.7-fixes 1/2] Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to a message not in the archive

2012/10/18 Tejun Heo <[email protected]>:

Quoted 11 lines

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

Quoted 6 lines

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

Ok but there is still no good reason to task_lock() there. But the comment is indeed wrong, how about fixing it instead? I can send you a patch for that.

Quoted 40 lines

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
kernel/cgroup.c +3 -13
index d1739fc..2990dc7 100644
@@ -4894,19 +4894,10 @@ void cgroup_post_fork(struct task_struct *child)
         */
        if (use_task_css_set_links) {
                write_lock(&css_set_lock);
-               if (list_empty(&child->cg_list)) {
-                       /*
-                        * It's safe to use child->cgroups without task_lock()
-                        * here because we are protected through
-                        * threadgroup_change_begin() against concurrent
-                        * css_set change in cgroup_task_migrate(). Also
-                        * the task can't exit at that point until
-                        * wake_up_new_task() is called, so we are protected
-                        * against cgroup_exit() setting child->cgroup to
-                        * init_css_set.
-                        */
+               task_lock(child);
+               if (list_empty(&child->cg_list))
                        list_add(&child->cg_list, &child->cgroups->tasks);
-               }
+               task_unlock(child);
                write_unlock(&css_set_lock);
        }
 }
--

1.7.7.3

author
#49 lore raw

PATCH 1/2 Revert "cgroup: Remove task_lock() from cgroup_post_fork()"

In reply to Tejun Heo

From d935a5d6832a264ce52f4257e176f4f96cbaf048 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:40:30 -0700

This reverts commit 7e3aa30ac8c904a706518b725c451bb486daaae9.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
kernel/cgroup.c +3 -12
index d1739fc..2990dc7 100644
@@ -4894,19 +4894,10 @@ void cgroup_post_fork(struct task_struct *child)
 	 */
 	if (use_task_css_set_links) {
 		write_lock(&css_set_lock);
-		if (list_empty(&child->cg_list)) {
-			/*
-			 * It's safe to use child->cgroups without task_lock()
-			 * here because we are protected through
-			 * threadgroup_change_begin() against concurrent
-			 * css_set change in cgroup_task_migrate(). Also
-			 * the task can't exit at that point until
-			 * wake_up_new_task() is called, so we are protected
-			 * against cgroup_exit() setting child->cgroup to
-			 * init_css_set.
-			 */
+		task_lock(child);
+		if (list_empty(&child->cg_list))
 			list_add(&child->cg_list, &child->cgroups->tasks);
-		}
+		task_unlock(child);
 		write_unlock(&css_set_lock);
 	}
 }
Signature · 1 line
1.7.7.3
author
#50 lore raw

PATCH 2/2 Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

In reply to Tejun Heo

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   23 ++++++-----------------
 1 files changed, 6 insertions(+), 17 deletions(-)
kernel/cgroup.c +6 -17
index 2990dc7..f24f724 100644
@@ -4814,31 +4814,20 @@ static const struct file_operations proc_cgroupstats_operations = {
  *
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
- * it was not made under the protection of RCU, cgroup_mutex or
- * threadgroup_change_begin(), so it might no longer be a valid
- * cgroup pointer.  cgroup_attach_task() might have already changed
- * current->cgroups, allowing the previously referenced cgroup
- * group to be removed and freed.
- *
- * Outside the pointer validity we also need to process the css_set
- * inheritance between threadgoup_change_begin() and
- * threadgoup_change_end(), this way there is no leak in any process
- * wide migration performed by cgroup_attach_proc() that could otherwise
- * miss a thread because it is too early or too late in the fork stage.
+ * it was not made under the protection of RCU or cgroup_mutex, so
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
+ * have already changed current->cgroups, allowing the previously
+ * referenced cgroup group to be removed and freed.
  *
  * At the point that cgroup_fork() is called, 'current' is the parent
  * task, and the passed argument 'child' points to the child task.
  */
 void cgroup_fork(struct task_struct *child)
 {
-	/*
-	 * We don't need to task_lock() current because current->cgroups
-	 * can't be changed concurrently here. The parent obviously hasn't
-	 * exited and called cgroup_exit(), and we are synchronized against
-	 * cgroup migration through threadgroup_change_begin().
-	 */
+	task_lock(current);
 	child->cgroups = current->cgroups;
 	get_css_set(child->cgroups);
+	task_unlock(current);
 	INIT_LIST_HEAD(&child->cg_list);
 }
 
Signature · 1 line
1.7.7.3

A message that is not in the archive (sent off-list or not yet received): [email protected]

Acked-by
#52 lore raw

Re: [PATCH cgroup/for-3.7-fixes 2/2] Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

Quoted 16 lines · Tejun Heo
Quoted 1 line

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001

From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 7 lines

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

Acked-by
#53 lore raw

Re: [PATCH cgroup/for-3.7-fixes 2/2] Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

In reply to a message not in the archive
Quoted 16 lines · Tejun Heo
Quoted 1 line

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001

From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 7 lines

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

#54 lore raw

Re: [PATCH cgroup/for-3.7-fixes 2/2] Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

In reply to a message not in the archive

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 4 lines

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>

(bitterly) Acked-by: Frederic Weisbecker <[email protected]> :-)

Quoted 51 lines
---
 kernel/cgroup.c |   23 ++++++-----------------
 1 files changed, 6 insertions(+), 17 deletions(-)
kernel/cgroup.c +6 -18
index 2990dc7..f24f724 100644
@@ -4814,31 +4814,20 @@ static const struct file_operations proc_cgroupstats_operations = {
  *
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
- * it was not made under the protection of RCU, cgroup_mutex or
- * threadgroup_change_begin(), so it might no longer be a valid
- * cgroup pointer.  cgroup_attach_task() might have already changed
- * current->cgroups, allowing the previously referenced cgroup
- * group to be removed and freed.
- *
- * Outside the pointer validity we also need to process the css_set
- * inheritance between threadgoup_change_begin() and
- * threadgoup_change_end(), this way there is no leak in any process
- * wide migration performed by cgroup_attach_proc() that could otherwise
- * miss a thread because it is too early or too late in the fork stage.
+ * it was not made under the protection of RCU or cgroup_mutex, so
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
+ * have already changed current->cgroups, allowing the previously
+ * referenced cgroup group to be removed and freed.
  *
  * At the point that cgroup_fork() is called, 'current' is the parent
  * task, and the passed argument 'child' points to the child task.
  */
 void cgroup_fork(struct task_struct *child)
 {
-       /*
-        * We don't need to task_lock() current because current->cgroups
-        * can't be changed concurrently here. The parent obviously hasn't
-        * exited and called cgroup_exit(), and we are synchronized against
-        * cgroup migration through threadgroup_change_begin().
-        */
+       task_lock(current);
        child->cgroups = current->cgroups;
        get_css_set(child->cgroups);
+       task_unlock(current);
        INIT_LIST_HEAD(&child->cg_list);
 }
 
--

1.7.7.3

#55 lore raw

Re: [PATCH cgroup/for-3.7-fixes 2/2] Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

In reply to a message not in the archive

2012/10/18 Tejun Heo <[email protected]>:

Quoted 16 lines

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Quoted 4 lines

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>

(bitterly) Acked-by: Frederic Weisbecker <[email protected]> :-)

Quoted 51 lines
---
 kernel/cgroup.c |   23 ++++++-----------------
 1 files changed, 6 insertions(+), 17 deletions(-)
kernel/cgroup.c +6 -18
index 2990dc7..f24f724 100644
@@ -4814,31 +4814,20 @@ static const struct file_operations proc_cgroupstats_operations = {
  *
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
- * it was not made under the protection of RCU, cgroup_mutex or
- * threadgroup_change_begin(), so it might no longer be a valid
- * cgroup pointer.  cgroup_attach_task() might have already changed
- * current->cgroups, allowing the previously referenced cgroup
- * group to be removed and freed.
- *
- * Outside the pointer validity we also need to process the css_set
- * inheritance between threadgoup_change_begin() and
- * threadgoup_change_end(), this way there is no leak in any process
- * wide migration performed by cgroup_attach_proc() that could otherwise
- * miss a thread because it is too early or too late in the fork stage.
+ * it was not made under the protection of RCU or cgroup_mutex, so
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
+ * have already changed current->cgroups, allowing the previously
+ * referenced cgroup group to be removed and freed.
  *
  * At the point that cgroup_fork() is called, 'current' is the parent
  * task, and the passed argument 'child' points to the child task.
  */
 void cgroup_fork(struct task_struct *child)
 {
-       /*
-        * We don't need to task_lock() current because current->cgroups
-        * can't be changed concurrently here. The parent obviously hasn't
-        * exited and called cgroup_exit(), and we are synchronized against
-        * cgroup migration through threadgroup_change_begin().
-        */
+       task_lock(current);
        child->cgroups = current->cgroups;
        get_css_set(child->cgroups);
+       task_unlock(current);
        INIT_LIST_HEAD(&child->cg_list);
 }
 
--

1.7.7.3

author
#56 lore raw

PATCH 2/2 Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"

In reply to Tejun Heo

From c8b27924a8b6fd74066088f1cf07c256bbc6ed74 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Thu, 18 Oct 2012 17:52:07 -0700

This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c.

The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock().

threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks.

Revert the incorrect optimization.

LKML-Reference: <20121008020000.GB2575@localhost>
Cc: Frederic Weisbecker <[email protected]>
Cc: Li Zefan <[email protected]>
Cc: [email protected]

---
 kernel/cgroup.c |   23 ++++++-----------------
 1 files changed, 6 insertions(+), 17 deletions(-)
kernel/cgroup.c +6 -17
index 2990dc7..f24f724 100644
@@ -4814,31 +4814,20 @@ static const struct file_operations proc_cgroupstats_operations = {
  *
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
- * it was not made under the protection of RCU, cgroup_mutex or
- * threadgroup_change_begin(), so it might no longer be a valid
- * cgroup pointer.  cgroup_attach_task() might have already changed
- * current->cgroups, allowing the previously referenced cgroup
- * group to be removed and freed.
- *
- * Outside the pointer validity we also need to process the css_set
- * inheritance between threadgoup_change_begin() and
- * threadgoup_change_end(), this way there is no leak in any process
- * wide migration performed by cgroup_attach_proc() that could otherwise
- * miss a thread because it is too early or too late in the fork stage.
+ * it was not made under the protection of RCU or cgroup_mutex, so
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
+ * have already changed current->cgroups, allowing the previously
+ * referenced cgroup group to be removed and freed.
  *
  * At the point that cgroup_fork() is called, 'current' is the parent
  * task, and the passed argument 'child' points to the child task.
  */
 void cgroup_fork(struct task_struct *child)
 {
-	/*
-	 * We don't need to task_lock() current because current->cgroups
-	 * can't be changed concurrently here. The parent obviously hasn't
-	 * exited and called cgroup_exit(), and we are synchronized against
-	 * cgroup migration through threadgroup_change_begin().
-	 */
+	task_lock(current);
 	child->cgroups = current->cgroups;
 	get_css_set(child->cgroups);
+	task_unlock(current);
 	INIT_LIST_HEAD(&child->cg_list);
 }
 
Signature · 1 line
1.7.7.3