diff options
author | David Rientjes <rientjes@google.com> | 2010-10-26 17:21:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 19:52:05 -0400 |
commit | d19d5476f4b9f91d2de92b91588bb118beba6c0d (patch) | |
tree | b267c225c2b7507f7e4900676649b20e56e06ba2 | |
parent | 723548bff1dde9ab6bdb23f4bb92277c4da49473 (diff) |
oom: fix locking for oom_adj and oom_score_adj
The locking order in oom_adjust_write() and oom_score_adj_write() for
task->alloc_lock and task->sighand->siglock is reversed, and lockdep
notices that irqs could encounter an ABBA scenario.
This fixes the locking order so that we always take task_lock(task) prior
to lock_task_sighand(task).
Signed-off-by: David Rientjes <rientjes@google.com>
Reported-by: Andrew Morton <akpm@linux-foundation.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Ying Han <yinghan@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/proc/base.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 34d11ac31f2e..53dc8ad40ae6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1042,9 +1042,16 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1042 | err = -ESRCH; | 1042 | err = -ESRCH; |
1043 | goto out; | 1043 | goto out; |
1044 | } | 1044 | } |
1045 | |||
1046 | task_lock(task); | ||
1047 | if (!task->mm) { | ||
1048 | err = -EINVAL; | ||
1049 | goto err_task_lock; | ||
1050 | } | ||
1051 | |||
1045 | if (!lock_task_sighand(task, &flags)) { | 1052 | if (!lock_task_sighand(task, &flags)) { |
1046 | err = -ESRCH; | 1053 | err = -ESRCH; |
1047 | goto err_task_struct; | 1054 | goto err_task_lock; |
1048 | } | 1055 | } |
1049 | 1056 | ||
1050 | if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { | 1057 | if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { |
@@ -1052,12 +1059,6 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1052 | goto err_sighand; | 1059 | goto err_sighand; |
1053 | } | 1060 | } |
1054 | 1061 | ||
1055 | task_lock(task); | ||
1056 | if (!task->mm) { | ||
1057 | err = -EINVAL; | ||
1058 | goto err_task_lock; | ||
1059 | } | ||
1060 | |||
1061 | if (oom_adjust != task->signal->oom_adj) { | 1062 | if (oom_adjust != task->signal->oom_adj) { |
1062 | if (oom_adjust == OOM_DISABLE) | 1063 | if (oom_adjust == OOM_DISABLE) |
1063 | atomic_inc(&task->mm->oom_disable_count); | 1064 | atomic_inc(&task->mm->oom_disable_count); |
@@ -1083,11 +1084,10 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1083 | else | 1084 | else |
1084 | task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / | 1085 | task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / |
1085 | -OOM_DISABLE; | 1086 | -OOM_DISABLE; |
1086 | err_task_lock: | ||
1087 | task_unlock(task); | ||
1088 | err_sighand: | 1087 | err_sighand: |
1089 | unlock_task_sighand(task, &flags); | 1088 | unlock_task_sighand(task, &flags); |
1090 | err_task_struct: | 1089 | err_task_lock: |
1090 | task_unlock(task); | ||
1091 | put_task_struct(task); | 1091 | put_task_struct(task); |
1092 | out: | 1092 | out: |
1093 | return err < 0 ? err : count; | 1093 | return err < 0 ? err : count; |
@@ -1150,21 +1150,24 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, | |||
1150 | err = -ESRCH; | 1150 | err = -ESRCH; |
1151 | goto out; | 1151 | goto out; |
1152 | } | 1152 | } |
1153 | |||
1154 | task_lock(task); | ||
1155 | if (!task->mm) { | ||
1156 | err = -EINVAL; | ||
1157 | goto err_task_lock; | ||
1158 | } | ||
1159 | |||
1153 | if (!lock_task_sighand(task, &flags)) { | 1160 | if (!lock_task_sighand(task, &flags)) { |
1154 | err = -ESRCH; | 1161 | err = -ESRCH; |
1155 | goto err_task_struct; | 1162 | goto err_task_lock; |
1156 | } | 1163 | } |
1164 | |||
1157 | if (oom_score_adj < task->signal->oom_score_adj && | 1165 | if (oom_score_adj < task->signal->oom_score_adj && |
1158 | !capable(CAP_SYS_RESOURCE)) { | 1166 | !capable(CAP_SYS_RESOURCE)) { |
1159 | err = -EACCES; | 1167 | err = -EACCES; |
1160 | goto err_sighand; | 1168 | goto err_sighand; |
1161 | } | 1169 | } |
1162 | 1170 | ||
1163 | task_lock(task); | ||
1164 | if (!task->mm) { | ||
1165 | err = -EINVAL; | ||
1166 | goto err_task_lock; | ||
1167 | } | ||
1168 | if (oom_score_adj != task->signal->oom_score_adj) { | 1171 | if (oom_score_adj != task->signal->oom_score_adj) { |
1169 | if (oom_score_adj == OOM_SCORE_ADJ_MIN) | 1172 | if (oom_score_adj == OOM_SCORE_ADJ_MIN) |
1170 | atomic_inc(&task->mm->oom_disable_count); | 1173 | atomic_inc(&task->mm->oom_disable_count); |
@@ -1181,11 +1184,10 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, | |||
1181 | else | 1184 | else |
1182 | task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / | 1185 | task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / |
1183 | OOM_SCORE_ADJ_MAX; | 1186 | OOM_SCORE_ADJ_MAX; |
1184 | err_task_lock: | ||
1185 | task_unlock(task); | ||
1186 | err_sighand: | 1187 | err_sighand: |
1187 | unlock_task_sighand(task, &flags); | 1188 | unlock_task_sighand(task, &flags); |
1188 | err_task_struct: | 1189 | err_task_lock: |
1190 | task_unlock(task); | ||
1189 | put_task_struct(task); | 1191 | put_task_struct(task); |
1190 | out: | 1192 | out: |
1191 | return err < 0 ? err : count; | 1193 | return err < 0 ? err : count; |