Skip to contentSkip to conversation

staging: android/lowmemorykiller: Don't grab tasklist_lock

PATCH Superseded Anton Vorontsov 5 participants 37 messages Feb 1, 2012 – Feb 15, 2012

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 staging: android/lowmemorykiller: Don't grab tasklist_lock

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse loop with rcu_read_{,un}lock() pair.

---

Also thanks to Eric and Paul for the ideas.

 drivers/staging/android/lowmemorykiller.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
drivers/staging/android/lowmemorykiller.c +3 -2
index 2d8d2b7..b3ade2f 100644
@@ -34,6 +34,7 @@
 #include <linux/mm.h>
 #include <linux/oom.h>
 #include <linux/sched.h>
+#include <linux/rcupdate.h>
 #include <linux/profile.h>
 #include <linux/notifier.h>
 
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	for_each_process(p) {
 		struct mm_struct *mm;
 		struct signal_struct *sig;
@@ -185,7 +186,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 		     sc->nr_to_scan, sc->gfp_mask, rem);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	return rem;
 }
 
Signature · 1 line
1.7.7.6
#1 lore raw

drivers/staging/android/lowmemorykiller.c static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 136

Quoted 7 lines · Anton Vorontsov
drivers/staging/android/lowmemorykiller.c +1 -1
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();

This has the same problem, force_sig() becomes unsafe.

Why do you need force_? Do you really want to kill /sbin/init (or sub-namespace init) ?

We could change force_sig_info() to use lock_task_sighand(), but I'd like to avoid this. Imho, this interface should be cleanuped, and it should be used for synchronous signals only.

With or without this patch, sig == NULL is not possible but !mm is not right, there could be other other threads with mm != NULL.

Oleg.

#2 lore raw
Quoted 10 lines · Oleg Nesterov

Review static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 136

Quoted 7 lines · Anton Vorontsov
(quoted diff) +1 -1
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();

This has the same problem, force_sig() becomes unsafe.

Ouch, I think I finally got it. So, lock_task_sighand() is trying to gracefully grab the lock, checking if the sighand is not NULL (which means, per __exit_signal(), that the task is halfway into the grave).

Well, it seems that such a behaviour of force_sig() is not quite obvious, and there are other offenders out there. E.g. in sysrq code I don't see anything that prevent the same race.

static void send_sig_all(int sig)

{      
        struct task_struct *p;

        for_each_process(p) {
                if (p->mm && !is_global_init(p))
                        /* Not swapper, init nor kernel thread */
                        force_sig(sig, p);
        }
}

Would the following fix work for the sysrq?

- - - -
From: Anton Vorontsov <[email protected]>
Subject: [PATCH] sysrq: Fix unsafe operations on tasks

sysrq should grab the tasklist lock, otherwise calling force_sig() is not safe, as it might race with exiting task, which ->sighand might be set to NULL already.

---
 drivers/tty/sysrq.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/tty/sysrq.c +2 -0
index 7867b7c..a1bcad7 100644
@@ -322,11 +322,13 @@ static void send_sig_all(int sig)
 {
 	struct task_struct *p;
 
+	read_lock(&tasklist_lock);
 	for_each_process(p) {
 		if (p->mm && !is_global_init(p))
 			/* Not swapper, init nor kernel thread */
 			force_sig(sig, p);
 	}
+	read_unlock(&tasklist_lock);
 }
 
 static void sysrq_handle_term(int key)

- - - -

But for LMK I will use send_signal(), as LMK is special.

Plus, while I'm at it, might want to review a bit closer other offenders, and fix them as well.

Quoted 2 lines

Why do you need force_? Do you really want to kill /sbin/init (or sub-namespace init) ?

Nope.

Quoted 3 lines

We could change force_sig_info() to use lock_task_sighand(), but I'd like to avoid this. Imho, this interface should be cleanuped, and it should be used for synchronous signals only.

OK. Then we should fix the users?

Quoted 2 lines

With or without this patch, sig == NULL is not possible but !mm is not right, there could be other other threads with mm != NULL.

I'm not sure I completely follow. In the current LMK code, we check for !mm because otherwise the potential victim is useless for us (i.e. killing it will not free much memory anyway).

Thanks!

Signature · 2 lines
Anton Vorontsov
Email: [email protected]
#3 lore raw

PATCH v3 1/1 staging: android/lowmemorykiller: Don't grab tasklist_lock

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

Quoted 1 line

From now on using force_sig() is not safe, as it can race with an

already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

---
 drivers/staging/android/lowmemorykiller.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
drivers/staging/android/lowmemorykiller.c +4 -3
index 2d8d2b7..63da844 100644
@@ -34,6 +34,7 @@
 #include <linux/mm.h>
 #include <linux/oom.h>
 #include <linux/sched.h>
+#include <linux/rcupdate.h>
 #include <linux/profile.h>
 #include <linux/notifier.h>
 
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	for_each_process(p) {
 		struct mm_struct *mm;
 		struct signal_struct *sig;
@@ -180,12 +181,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 		lowmem_deathpending = selected;
 		task_handoff_register(&task_nb);
 #endif
-		force_sig(SIGKILL, selected);
+		send_sig(SIGKILL, selected, 0);
 		rem -= selected_tasksize;
 	}
 	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 		     sc->nr_to_scan, sc->gfp_mask, rem);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	return rem;
 }
 
Signature · 1 line
1.7.7.6
#4 lore raw
Quoted 12 lines · Anton Vorontsov
drivers/staging/android/lowmemorykiller.c +1 -1
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	for_each_process(p) {
 		struct mm_struct *mm;
 		struct signal_struct *sig;
@@ -180,12 +181,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 		lowmem_deathpending = selected;

drivers/staging/android/lowmemorykiller.c static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 189

Quoted 10 lines
drivers/staging/android/lowmemorykiller.c +2 -2
 		task_handoff_register(&task_nb);
 #endif
-		force_sig(SIGKILL, selected);
+		send_sig(SIGKILL, selected, 0);
 		rem -= selected_tasksize;
 	}
 	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 		     sc->nr_to_scan, sc->gfp_mask, rem);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();

I think this is correct. As for ->mm check please look at find_lock_task_mm().

You can also remove the !sig check.

And, forgot to mention. There is another reason why mm != NULL check is wrong (send_sig_all too). A kernel thread can do use_mm(). You should also check PF_KTHREAD.

Oleg.

#5 lore raw
In reply to Anton Vorontsov
Quoted 8 lines · Anton Vorontsov
Quoted 2 lines · Oleg Nesterov

This has the same problem, force_sig() becomes unsafe.

Ouch, I think I finally got it. So, lock_task_sighand() is trying to gracefully grab the lock, checking if the sighand is not NULL (which means, per __exit_signal(), that the task is halfway into the grave).

Yes.

Quoted 9 lines

Would the following fix work for the sysrq?

- - - -
From: Anton Vorontsov <[email protected]>
Subject: [PATCH] sysrq: Fix unsafe operations on tasks

sysrq should grab the tasklist lock, otherwise calling force_sig() is not safe, as it might race with exiting task, which ->sighand might be set to NULL already.

And there are other reasons for tasklist. It is not clear why for_each_process() itself is safe. OK, currently (afaics) the caller disables irqs, but in theory this doesn't imply rcu_lock.

And it can race with fork() and miss the task, although mostly in theory.

drivers/tty/sysrq.c static void send_sig_all(int sig) · line 331

Quoted 13 lines
drivers/tty/sysrq.c +2 -0
@@ -322,11 +322,13 @@ static void send_sig_all(int sig)
 {
 	struct task_struct *p;
 
+	read_lock(&tasklist_lock);
 	for_each_process(p) {
 		if (p->mm && !is_global_init(p))
 			/* Not swapper, init nor kernel thread */
 			force_sig(sig, p);
 	}
+	read_unlock(&tasklist_lock);

Agreed, but force_sig() should not be used anyway. It sends the signal to the thread, we need to kill the process. The main thread can exit.

Quoted 6 lines
drivers/tty/sysrq.c +0 -0
 > With or without this patch, sig == NULL is not possible but !mm is not right,
Quoted 1 line

there could be other other threads with mm != NULL.

I'm not sure I completely follow. In the current LMK code, we check for !mm because otherwise the potential victim is useless for us (i.e. killing it will not free much memory anyway).

This is the common mistake. Consider this program:

	void *thread_func(...)
	{
		use_a_lot_of_memory();
	}

	int main(void)
	{
		pthread_create(..., thread_func, ...);
		pthread_exit();
	}

lowmem_shrink() will skip this task because p->mm == NULL.

Oleg.

#6 lore raw

PATCH 1/6 oom: Make find_lock_task_mm() sparse-aware

This is needed so that callers would not get 'context imbalance' warnings from the sparse tool.

As a side effect, this patch fixes the following sparse warnings:

CHECK mm/oom_kill.c
mm/oom_kill.c:201:28: warning: context imbalance in 'oom_badness' - unexpected unlock
include/linux/rcupdate.h:249:30: warning: context imbalance in 'dump_tasks' - unexpected unlock
mm/oom_kill.c:453:9: warning: context imbalance in 'oom_kill_task' - unexpected unlock
CHECK mm/memcontrol.c
...
mm/memcontrol.c:1130:17: warning: context imbalance in 'task_in_mem_cgroup' - unexpected unlock

---
 include/linux/oom.h |   11 ++++++++++-
 mm/oom_kill.c       |    2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)
include/linux/oom.h +10 -1
index 552fba9..e64bfd2 100644
@@ -21,6 +21,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/nodemask.h>
@@ -65,7 +66,15 @@ static inline void oom_killer_enable(void)
 	oom_killer_disabled = false;
 }
 
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+#define find_lock_task_mm(p)						\
+({									\
+	struct task_struct *__ret;					\
+									\
+	__cond_lock(&(p)->alloc_lock, __ret = __find_lock_task_mm(p));	\
+	__ret;								\
+})
 
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
mm/oom_kill.c +1 -1
index 2958fd8..0ebb383 100644
@@ -136,7 +136,7 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk,
  * pointer.  Return p, or any of its subthreads with a valid ->mm, with
  * task_lock() held.
  */
-struct task_struct *find_lock_task_mm(struct task_struct *p)
+struct task_struct *__find_lock_task_mm(struct task_struct *p)
 {
 	struct task_struct *t = p;
 
Signature · 1 line
1.7.7.6
maintainer
#7 lore raw

Re: [PATCH 1/6] oom: Make find_lock_task_mm() sparse-aware

Quoted 39 lines · Anton Vorontsov

This is needed so that callers would not get 'context imbalance' warnings from the sparse tool.

As a side effect, this patch fixes the following sparse warnings:

CHECK mm/oom_kill.c
mm/oom_kill.c:201:28: warning: context imbalance in 'oom_badness' - unexpected unlock
include/linux/rcupdate.h:249:30: warning: context imbalance in 'dump_tasks' - unexpected unlock
mm/oom_kill.c:453:9: warning: context imbalance in 'oom_kill_task' - unexpected unlock
CHECK mm/memcontrol.c
...
mm/memcontrol.c:1130:17: warning: context imbalance in 'task_in_mem_cgroup' - unexpected unlock

---
 include/linux/oom.h |   11 ++++++++++-
 mm/oom_kill.c       |    2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)
include/linux/oom.h +1 -0
index 552fba9..e64bfd2 100644
@@ -21,6 +21,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/nodemask.h>
@@ -65,7 +66,15 @@ static inline void oom_killer_enable(void)
 	oom_killer_disabled = false;
 }
 

include/linux/oom.h static inline void oom_killer_enable(void) · line 77

Quoted 10 lines
include/linux/oom.h +9 -1
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+#define find_lock_task_mm(p)						\
+({									\
+	struct task_struct *__ret;					\
+									\
+	__cond_lock(&(p)->alloc_lock, __ret = __find_lock_task_mm(p));	\
+	__ret;								\
+})

Please use the proper "do...while" style thing here for multi-line, complex #defines like the rest of the kernel does so that you don't end up debugging horrible problems later.

And I would need acks from the -mm developers before I could apply any of this.

thanks,

greg k-h

#8 lore raw

Re: [PATCH 1/6] oom: Make find_lock_task_mm() sparse-aware

On Mon, Feb 06, 2012 at 08:35:42AM -0800, Greg KH wrote:
[...]

Quoted 6 lines
Quoted 6 lines
include/linux/oom.h +5 -1
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+#define find_lock_task_mm(p)						\
+({									\
+	struct task_struct *__ret;					\
Quoted 8 lines

include/linux/oom.h static inline void oom_killer_enable(void) · line 77

Quoted 4 lines
include/linux/oom.h +4 -0
+									\
+	__cond_lock(&(p)->alloc_lock, __ret = __find_lock_task_mm(p));	\
+	__ret;								\
+})

Please use the proper "do...while" style thing here for multi-line, complex #defines like the rest of the kernel does so that you don't end up debugging horrible problems later.

Unfortunately this isn't possible in this case. Unlike '({})' GCC extension, do-while statement does not evaluate to a value, i.e. 'x = do { 123; } while (0);' is illegal.

Thanks,

Signature · 2 lines
Anton Vorontsov
Email: [email protected]
maintainer
#9 lore raw

Re: [PATCH 1/6] oom: Make find_lock_task_mm() sparse-aware

Quoted 17 lines · Anton Vorontsov

On Mon, Feb 06, 2012 at 08:35:42AM -0800, Greg KH wrote:
[...]

Quoted 6 lines
Quoted 6 lines
include/linux/oom.h +5 -1
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+#define find_lock_task_mm(p)						\
+({									\
+	struct task_struct *__ret;					\
Quoted 8 lines

include/linux/oom.h static inline void oom_killer_enable(void) · line 77

Quoted 4 lines
include/linux/oom.h +4 -0
+									\
+	__cond_lock(&(p)->alloc_lock, __ret = __find_lock_task_mm(p));	\
+	__ret;								\
+})

Please use the proper "do...while" style thing here for multi-line, complex #defines like the rest of the kernel does so that you don't end up debugging horrible problems later.

Quoted 3 lines

Unfortunately this isn't possible in this case. Unlike '({})' GCC extension, do-while statement does not evaluate to a value, i.e. 'x = do { 123; } while (0);' is illegal.

Ah, you are right, my bad, sorry about that.

greg k-h

#10 lore raw

Re: [PATCH 1/6] oom: Make find_lock_task_mm() sparse-aware

2012/2/6 Greg KH <[email protected]>:

Quoted 18 lines · Anton Vorontsov
Quoted 17 lines · Greg KH

[...]

Quoted 14 lines

include/linux/oom.h static inline void oom_killer_enable(void) · line 77

Quoted 10 lines
include/linux/oom.h +9 -1
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+#define find_lock_task_mm(p)                                             \
+({                                                                       \
+ struct task_struct *__ret;                                      \
+                                                                 \
+ __cond_lock(&(p)->alloc_lock, __ret = __find_lock_task_mm(p));  \
+ __ret;                                                          \
+})

Please use the proper "do...while" style thing here for multi-line, complex #defines like the rest of the kernel does so that you don't end up debugging horrible problems later.

Quoted 7 lines
Quoted 3 lines

Unfortunately this isn't possible in this case. Unlike '({})' GCC extension, do-while statement does not evaluate to a value, i.e. 'x = do { 123; } while (0);' is illegal.

Ah, you are right, my bad, sorry about that.

greg k-h

Some __cond_lock() caller are inline functions. Is this bad? inline function is always recommended than macros.

#11 lore raw

PATCH v2 1/6 oom: Make find_lock_task_mm() sparse-aware

This is needed so that callers would not get 'context imbalance' warnings from the sparse tool.

As a side effect, this patch fixes the following sparse warnings:

CHECK mm/oom_kill.c
mm/oom_kill.c:201:28: warning: context imbalance in 'oom_badness' - unexpected unlock
include/linux/rcupdate.h:249:30: warning: context imbalance in 'dump_tasks' - unexpected unlock
mm/oom_kill.c:453:9: warning: context imbalance in 'oom_kill_task' - unexpected unlock
CHECK mm/memcontrol.c
...
mm/memcontrol.c:1130:17: warning: context imbalance in 'task_in_mem_cgroup' - unexpected unlock

---

On Mon, Feb 06, 2012 at 04:27:32PM -0500, KOSAKI Motohiro wrote:
[...]

Quoted 9 lines
Quoted 7 lines
Quoted 3 lines

Unfortunately this isn't possible in this case. Unlike '({})' GCC extension, do-while statement does not evaluate to a value, i.e. 'x = do { 123; } while (0);' is illegal.

Ah, you are right, my bad, sorry about that.

greg k-h

Some __cond_lock() caller are inline functions. Is this bad?

No, that's great, actually. :-) Not obvious, but seems like sparse understands __cond_lock in inline functions, so I'd better use it.

Thanks,

 include/linux/oom.h |   12 +++++++++++-
 mm/oom_kill.c       |    2 +-
 2 files changed, 12 insertions(+), 2 deletions(-)
include/linux/oom.h +11 -1
index 552fba9..7c8946a 100644
@@ -21,6 +21,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/nodemask.h>
@@ -65,7 +66,16 @@ static inline void oom_killer_enable(void)
 	oom_killer_disabled = false;
 }
 
-extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+extern struct task_struct *__find_lock_task_mm(struct task_struct *p);
+
+static inline struct task_struct *find_lock_task_mm(struct task_struct *p)
+{
+	struct task_struct *ret;
+
+	ret = __find_lock_task_mm(p);
+	(void)__cond_lock(&p->alloc_lock, ret);
+	return ret;
+}
 
 /* sysctls */
 extern int sysctl_oom_dump_tasks;
mm/oom_kill.c +1 -1
index 2958fd8..0ebb383 100644
@@ -136,7 +136,7 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk,
  * pointer.  Return p, or any of its subthreads with a valid ->mm, with
  * task_lock() held.
  */
-struct task_struct *find_lock_task_mm(struct task_struct *p)
+struct task_struct *__find_lock_task_mm(struct task_struct *p)
 {
 	struct task_struct *t = p;
 
Signature · 1 line
1.7.7.6
Acked-by on v2 1/6
#12 lore raw

Re: [PATCH v2 1/6] oom: Make find_lock_task_mm() sparse-aware

Quoted 7 lines
Quoted 1 line

Some __cond_lock() caller are inline functions. Is this bad?

No, that's great, actually. :-) Not obvious, but seems like sparse understands __cond_lock in inline functions, so I'd better use it.

Thanks,

Great. So, to this version

#13 lore raw

Re: [PATCH v2 1/6] oom: Make find_lock_task_mm() sparse-aware

In reply to Anton Vorontsov
Quoted 8 lines · Anton Vorontsov
Quoted 2 lines · KOSAKI Motohiro

Some __cond_lock() caller are inline functions. Is this bad?

No, that's great, actually. :-) Not obvious, but seems like sparse understands __cond_lock in inline functions, so I'd better use it.

Hmm, great...

may be you can update lock_task_sighand() too ? (in a separate patch of course).

Oleg.

#14 lore raw

PATCH 1/1 sched: Turn lock_task_sighand() into a static inline

It appears that sparse tool understands static inline functions for context balance checking, so let's turn the macros into an inline func.

This makes the code a little bit more robust.

---

Quoted 6 lines · Oleg Nesterov
Quoted 5 lines · Anton Vorontsov
Quoted 2 lines · KOSAKI Motohiro

Some __cond_lock() caller are inline functions. Is this bad?

Quoted 8 lines
Quoted 3 lines

No, that's great, actually. :-) Not obvious, but seems like sparse understands __cond_lock in inline functions, so I'd better use it.

Hmm, great...

may be you can update lock_task_sighand() too ? (in a separate patch of course).

Sure thing. Here it goes...

 include/linux/sched.h |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)
include/linux/sched.h +9 -6
index e82f721..22ae10e 100644
@@ -2394,12 +2394,15 @@ static inline void task_unlock(struct task_struct *p)
 extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
 							unsigned long *flags);
 
-#define lock_task_sighand(tsk, flags)					\
-({	struct sighand_struct *__ss;					\
-	__cond_lock(&(tsk)->sighand->siglock,				\
-		    (__ss = __lock_task_sighand(tsk, flags)));		\
-	__ss;								\
-})									\
+static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+						       unsigned long *flags)
+{
+	struct sighand_struct *ret;
+
+	ret = __lock_task_sighand(tsk, flags);
+	(void)__cond_lock(&tsk->sighand->siglock, ret);
+	return ret;
+}
 
 static inline void unlock_task_sighand(struct task_struct *tsk,
 						unsigned long *flags)
Signature · 1 line
1.7.8.3
#15 lore raw

[tip:sched/core] sched: Turn lock_task_sighand() into a static inline

Commit-ID:  9388dc3047a88bedfd867e9ba3e1980c815ac524
Gitweb:     http://git.kernel.org/tip/9388dc3047a88bedfd867e9ba3e1980c815ac524
Author:     Anton Vorontsov <[email protected]>
AuthorDate: Thu, 9 Feb 2012 20:45:19 +0400
Committer:  Ingo Molnar <[email protected]>
CommitDate: Sat, 11 Feb 2012 15:41:33 +0100

sched: Turn lock_task_sighand() into a static inline

It appears that sparse tool understands static inline functions for context balance checking, so let's turn the macros into an inline func.

This makes the code a little bit more robust.

---
 include/linux/sched.h |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)
include/linux/sched.h +9 -6
index 92313a3f..5dba2ad 100644
@@ -2393,12 +2393,15 @@ static inline void task_unlock(struct task_struct *p)
 extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
 							unsigned long *flags);
 
-#define lock_task_sighand(tsk, flags)					\
-({	struct sighand_struct *__ss;					\
-	__cond_lock(&(tsk)->sighand->siglock,				\
-		    (__ss = __lock_task_sighand(tsk, flags)));		\
-	__ss;								\
-})									\
+static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+						       unsigned long *flags)
+{
+	struct sighand_struct *ret;
+
+	ret = __lock_task_sighand(tsk, flags);
+	(void)__cond_lock(&tsk->sighand->siglock, ret);
+	return ret;
+}
 
 static inline void unlock_task_sighand(struct task_struct *tsk,
 						unsigned long *flags)
maintainer
#16 lore raw

Re: [tip:sched/core] sched: Turn lock_task_sighand() into a static inline

include/linux/sched.h static inline void task_unlock(struct task_struct *p) · line 2404

Quoted 9 lines · tip-bot for Anton Vorontsov
include/linux/sched.h +9 -0
+static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
+                                                      unsigned long *flags)
+{
+       struct sighand_struct *ret;
+
+       ret = __lock_task_sighand(tsk, flags);
+       (void)__cond_lock(&tsk->sighand->siglock, ret);
+       return ret;
+} 

FWIW, I still really utterly detest __cond_lock(). Ideally someone would teach sparse the conditional based on return thing and we could do the function level annotation.

#17 lore raw

PATCH 2/6 oom: Get rid of sparse warnings

In reply to Oleg Nesterov

Sparse flood makes it hard to catch newly-introduced warnings. So let's fix the the sparse warnings in the oom killer:

CHECK mm/oom_kill.c
mm/oom_kill.c:139:20: warning: context imbalance in
'__find_lock_task_mm' - wrong count at exit
mm/oom_kill.c:771:9: warning: context imbalance in 'out_of_memory' -
different lock contexts for basic block

The first one is fixed by assuring sparse that we know that we exit with the lock held.

The second one is caused by the fact that sparse isn't smart enough to handle noreturn attribute.

---
 mm/oom_kill.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
mm/oom_kill.c +8 -1
index 0ebb383..49569b6 100644
@@ -142,8 +142,14 @@ struct task_struct *__find_lock_task_mm(struct task_struct *p)
 
 	do {
 		task_lock(t);
-		if (likely(t->mm))
+		if (likely(t->mm)) {
+			/*
+			 * Shut up sparse: we do know that we exit w/ the
+			 * task locked.
+			 */
+			__release(&t->alloc_loc);
 			return t;
+		}
 		task_unlock(t);
 	} while_each_thread(p, t);
 
@@ -766,6 +772,7 @@ retry:
 		dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
 		read_unlock(&tasklist_lock);
 		panic("Out of memory and no killable processes...\n");
+		return;
 	}
 
 	if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
Signature · 1 line
1.7.7.6
#18 lore raw

Re: [PATCH 2/6] oom: Get rid of sparse warnings

2012/2/6 Anton Vorontsov <[email protected]>:

Quoted 25 lines

Sparse flood makes it hard to catch newly-introduced warnings. So let's fix the the sparse warnings in the oom killer:

 CHECK   mm/oom_kill.c
 mm/oom_kill.c:139:20: warning: context imbalance in '__find_lock_task_mm' - wrong count at exit mm/oom_kill.c:771:9: warning: context imbalance in 'out_of_memory' - different lock contexts for basic block

The first one is fixed by assuring sparse that we know that we exit with the lock held.

The second one is caused by the fact that sparse isn't smart enough to handle noreturn attribute.

---
 mm/oom_kill.c |    9 ++++++++-

 1 files changed, 8 insertions(+), 1 deletions(-)
mm/oom_kill.c +0 -0
index 0ebb383..49569b6 100644

mm/oom_kill.c struct task_struct *__find_lock_task_mm(struct task_struct *p) · line 150

Quoted 10 lines
mm/oom_kill.c +6 -1
@@ -142,8 +142,14 @@ struct task_struct *__find_lock_task_mm(struct task_struct *p)
 
        do {
                task_lock(t);
-               if (likely(t->mm))
+               if (likely(t->mm)) {
+                       /*
+                        * Shut up sparse: we do know that we exit w/ the
+                        * task locked.
+                        */
+                       __release(&t->alloc_loc);

task struct only have allock_lock, not alloc_loc. Moreover we don't release the lock in this code path. Seems odd.

Quoted 16 lines
mm/oom_kill.c +2 -1
                        return t;
+               }
                task_unlock(t);
        } while_each_thread(p, t);
 
@@ -766,6 +772,7 @@ retry:
                dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
                read_unlock(&tasklist_lock);
                panic("Out of memory and no killable processes...\n");
+               return;
        }
 
        if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
--

1.7.7.6

#19 lore raw

PATCH v2 2/6 oom: Get rid of sparse warnings

Sparse flood makes it hard to catch newly-introduced warnings. So let's fix the the sparse warnings in the oom killer:

CHECK mm/oom_kill.c
mm/oom_kill.c:139:20: warning: context imbalance in
'__find_lock_task_mm' - wrong count at exit
mm/oom_kill.c:771:9: warning: context imbalance in 'out_of_memory' -
different lock contexts for basic block

The first one is fixed by assuring sparse that we know that we exit with the lock held.

The second one is caused by the fact that sparse isn't smart enough to handle noreturn attribute.

---

Quoted 27 lines · KOSAKI Motohiro

2012/2/6 Anton Vorontsov <[email protected]>:

Quoted 26 lines

Sparse flood makes it hard to catch newly-introduced warnings. So let's fix the the sparse warnings in the oom killer:

 CHECK   mm/oom_kill.c
 mm/oom_kill.c:139:20: warning: context imbalance in '__find_lock_task_mm' - wrong count at exit mm/oom_kill.c:771:9: warning: context imbalance in 'out_of_memory' - different lock contexts for basic block

The first one is fixed by assuring sparse that we know that we exit with the lock held.

The second one is caused by the fact that sparse isn't smart enough to handle noreturn attribute.

---
 mm/oom_kill.c |    9 ++++++++-

 1 files changed, 8 insertions(+), 1 deletions(-)
mm/oom_kill.c +0 -0
index 0ebb383..49569b6 100644
@@ -142,8 +142,14 @@ struct task_struct *__find_lock_task_mm(struct task_struct *p)
 
Quoted 11 lines

mm/oom_kill.c struct task_struct *__find_lock_task_mm(struct task_struct *p) · line 150

Quoted 9 lines
mm/oom_kill.c +6 -1
        do {
                task_lock(t);
-               if (likely(t->mm))
+               if (likely(t->mm)) {
+                       /*
+                        * Shut up sparse: we do know that we exit w/ the
+                        * task locked.
+                        */
+                       __release(&t->alloc_loc);

task struct only have allock_lock, not alloc_loc.

Funnily, but sparse does not care. :-) __release(foo) will work as well. Seems like sparse counts locking balance globally.

This is now fixed in the patch down below, thanks for catching.

Quoted 2 lines

Moreover we don't release
the lock in this code path. Seems odd.

Indeed. That's exactly what sparse seeing is as well. We exit without releasing the lock, which is bad (in sparse' eyes). So we lie to sparse, telling it that we do release, so it shut ups.

Usually, we annotate functions with __releases() and __acquires() when when functions releases/acquires one of its arguments, but in this case the function returns a locked value, and it seems that there's no way to properly annotate this case.

 mm/oom_kill.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
mm/oom_kill.c +8 -1
index 0ebb383..1914367 100644
@@ -142,8 +142,14 @@ struct task_struct *__find_lock_task_mm(struct task_struct *p)
 
 	do {
 		task_lock(t);
-		if (likely(t->mm))
+		if (likely(t->mm)) {
+			/*
+			 * Shut up sparse: we do know that we exit w/ the
+			 * task locked.
+			 */
+			__release(&t->alloc_lock);
 			return t;
+		}
 		task_unlock(t);
 	} while_each_thread(p, t);
 
@@ -766,6 +772,7 @@ retry:
 		dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
 		read_unlock(&tasklist_lock);
 		panic("Out of memory and no killable processes...\n");
+		return;
 	}
 
 	if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
Signature · 1 line
1.7.7.6
#20 lore raw

Re: [PATCH v2 2/6] oom: Get rid of sparse warnings

Quoted 5 lines
Quoted 1 line

task struct only have allock_lock, not alloc_loc.

Funnily, but sparse does not care. :-) __release(foo) will work as well. Seems like sparse counts locking balance globally.

Quoted 8 lines

This is now fixed in the patch down below, thanks for catching.

Quoted 2 lines

Moreover we don't release
the lock in this code path. Seems odd.

Indeed. That's exactly what sparse seeing is as well. We exit without releasing the lock, which is bad (in sparse' eyes). So we lie to sparse, telling it that we do release, so it shut ups.

Hmmm....

To be honest, I really dislike any lie annotation. Why? It is very fragile and easily
become broken from unrelated but near line changes. Please consider to enhance sparse at first.

#21 lore raw

Re: [PATCH v2 2/6] oom: Get rid of sparse warnings

Quoted 14 lines · KOSAKI Motohiro
Quoted 5 lines
Quoted 1 line

task struct only have allock_lock, not alloc_loc.

Funnily, but sparse does not care. :-) __release(foo) will work as well. Seems like sparse counts locking balance globally.

Quoted 8 lines

This is now fixed in the patch down below, thanks for catching.

Quoted 2 lines

Moreover we don't release
the lock in this code path. Seems odd.

Indeed. That's exactly what sparse seeing is as well. We exit without releasing the lock, which is bad (in sparse' eyes). So we lie to sparse, telling it that we do release, so it shut ups.

Quoted 6 lines

Hmmm....

To be honest, I really dislike any lie annotation. Why? It is very fragile and easily
become broken from unrelated but near line changes. Please consider to enhance sparse at first.

I somewhat doubt that it is possible to "enhance it". We keep the lock held conditionaly, so we need too place the hint in the code itself. I believe the best we can do would be something like this:

include/linux/compiler.h +2 -0
index 4a24354..61d91f2 100644
@@ -14,6 +14,7 @@
 # define __releases(x)	__attribute__((context(x,1,0)))
 # define __acquire(x)	__context__(x,1)
 # define __release(x)	__context__(x,-1)
+# define __ret_with_lock(x)	__context__(x,-1)
 # define __cond_lock(x,c)	((c) ? ({ __acquire(x); 1; }) : 0)
 # define __percpu	__attribute__((noderef, address_space(3)))
 #ifdef CONFIG_SPARSE_RCU_POINTER
@@ -37,6 +38,7 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 # define __releases(x)
 # define __acquire(x) (void)0
 # define __release(x) (void)0
+# define __ret_with_lock(x)
 # define __cond_lock(x,c) (c)
 # define __percpu
 # define __rcu

And then use it instead of __release().

Signature · 2 lines
Anton Vorontsov
Email: [email protected]
#22 lore raw

Re: [PATCH v2 2/6] oom: Get rid of sparse warnings

Quoted 48 lines · Anton Vorontsov
Quoted 14 lines · KOSAKI Motohiro
Quoted 5 lines
Quoted 1 line

task struct only have allock_lock, not alloc_loc.

Funnily, but sparse does not care. :-) __release(foo) will work as well. Seems like sparse counts locking balance globally.

Quoted 8 lines

This is now fixed in the patch down below, thanks for catching.

Quoted 2 lines

Moreover we don't release
the lock in this code path. Seems odd.

Indeed. That's exactly what sparse seeing is as well. We exit without releasing the lock, which is bad (in sparse' eyes). So we lie to sparse, telling it that we do release, so it shut ups.

Quoted 6 lines

Hmmm....

To be honest, I really dislike any lie annotation. Why? It is very fragile and easily
become broken from unrelated but near line changes. Please consider to enhance sparse at first.

I somewhat doubt that it is possible to "enhance it". We keep the lock held conditionaly, so we need too place the hint in the code itself. I believe the best we can do would be something like this:

include/linux/compiler.h +2 -0
index 4a24354..61d91f2 100644
@@ -14,6 +14,7 @@
  # define __releases(x)	__attribute__((context(x,1,0)))
  # define __acquire(x)	__context__(x,1)
  # define __release(x)	__context__(x,-1)
+# define __ret_with_lock(x)	__context__(x,-1)
  # define __cond_lock(x,c)	((c) ? ({ __acquire(x); 1; }) : 0)
  # define __percpu	__attribute__((noderef, address_space(3)))
  #ifdef CONFIG_SPARSE_RCU_POINTER
@@ -37,6 +38,7 @@ extern void __chk_io_ptr(const volatile void __iomem *);
  # define __releases(x)
  # define __acquire(x) (void)0
  # define __release(x) (void)0
+# define __ret_with_lock(x)
  # define __cond_lock(x,c) (c)
  # define __percpu
  # define __rcu
Quoted 1 line

And then use it instead of __release().

Hmmm...

I still dislike this lie annotation. But maybe it's better than nothing (dunno, just guess). Go ahead.

#23 lore raw

PATCH 3/6 staging: android/lowmemorykiller: Don't grab tasklist_lock

In reply to Oleg Nesterov

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

Quoted 1 line

From now on using force_sig() is not safe, as it can race with an

already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

---
 drivers/staging/android/lowmemorykiller.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
drivers/staging/android/lowmemorykiller.c +4 -3
index 2d8d2b7..63da844 100644
@@ -34,6 +34,7 @@
 #include <linux/mm.h>
 #include <linux/oom.h>
 #include <linux/sched.h>
+#include <linux/rcupdate.h>
 #include <linux/profile.h>
 #include <linux/notifier.h>
 
@@ -132,7 +133,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	}
 	selected_oom_adj = min_adj;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	for_each_process(p) {
 		struct mm_struct *mm;
 		struct signal_struct *sig;
@@ -180,12 +181,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 		lowmem_deathpending = selected;
 		task_handoff_register(&task_nb);
 #endif
-		force_sig(SIGKILL, selected);
+		send_sig(SIGKILL, selected, 0);
 		rem -= selected_tasksize;
 	}
 	lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 		     sc->nr_to_scan, sc->gfp_mask, rem);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	return rem;
 }
 
Signature · 1 line
1.7.7.6
maintainer
#24 lore raw
Quoted 7 lines · Anton Vorontsov

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

Quoted 7 lines
Quoted 1 line

From now on using force_sig() is not safe, as it can race with an

already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

Are these last 4 patches independant of the first 2 and can be taken through the staging tree now?

thanks,

greg k-h

#25 lore raw
Quoted 13 lines · Greg KH
Quoted 12 lines · Anton Vorontsov

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

Quoted 1 line

From now on using force_sig() is not safe, as it can race with an

already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

Quoted 5 lines
Quoted 2 lines

Are these last 4 patches independant of the first 2 and can be taken through the staging tree now?

Yep, without the first two there is just a bit of sparse warnings. Not a big deal.

Thanks,

Signature · 2 lines
Anton Vorontsov
Email: [email protected]
maintainer
#26 lore raw
Quoted 14 lines · Anton Vorontsov
Quoted 13 lines · Greg KH
Quoted 12 lines · Anton Vorontsov

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

Quoted 1 line

From now on using force_sig() is not safe, as it can race with an

already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Are these last 4 patches independant of the first 2 and can be taken through the staging tree now?

Yep, without the first two there is just a bit of sparse warnings. Not a big deal.

Ok, I'll take the last 4, the first 2 needs to go through some other tree (-mm?)

thanks,

greg k-h

Reviewed-by on v1 3/6
#27 lore raw
In reply to Anton Vorontsov
Quoted 5 lines · Anton Vorontsov

Grabbing tasklist_lock has its disadvantages, i.e. it blocks process creation and destruction. If there are lots of processes, blocking doesn't sound as a great idea.

Quoted 7 lines

For LMK, it is sufficient to surround tasks list traverse with rcu_read_{,un}lock().

From now on using force_sig() is not safe, as it can race with an already exiting task, so we use send_sig() now. As a downside, it won't kill PID namespace init processes, but that's not what we want anyway.

#28 lore raw

PATCH 4/6 staging: android/lowmemorykiller: Better mm handling

In reply to Oleg Nesterov

LMK should not directly check for task->mm. The reason is that the process' threads may exit or detach its mm via use_mm(), but other threads may still have a valid mm. To catch this we use find_lock_task_mm(), which walks up all threads and returns an appropriate task (with lock held).

---
 drivers/staging/android/lowmemorykiller.c |   16 +++++++++-------
 1 files changed, 9 insertions(+), 7 deletions(-)
drivers/staging/android/lowmemorykiller.c +9 -7
index 63da844..0755e2f 100644
@@ -82,7 +82,7 @@ task_notify_func(struct notifier_block *self, unsigned long val, void *data)
 
 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 {
-	struct task_struct *p;
+	struct task_struct *tsk;
 	struct task_struct *selected = NULL;
 	int rem = 0;
 	int tasksize;
@@ -134,15 +134,17 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	selected_oom_adj = min_adj;
 
 	rcu_read_lock();
-	for_each_process(p) {
-		struct mm_struct *mm;
+	for_each_process(tsk) {
+		struct task_struct *p;
 		struct signal_struct *sig;
 		int oom_adj;
 
-		task_lock(p);
-		mm = p->mm;
+		p = find_lock_task_mm(tsk);
+		if (!p)
+			continue;
+
 		sig = p->signal;
-		if (!mm || !sig) {
+		if (!sig) {
 			task_unlock(p);
 			continue;
 		}
@@ -151,7 +153,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 			task_unlock(p);
 			continue;
 		}
-		tasksize = get_mm_rss(mm);
+		tasksize = get_mm_rss(p->mm);
 		task_unlock(p);
 		if (tasksize <= 0)
 			continue;
Signature · 1 line
1.7.7.6
#29 lore raw

Re: [PATCH 4/6] staging: android/lowmemorykiller: Better mm handling

Quoted 31 lines

 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) {
-       struct task_struct *p;
+       struct task_struct *tsk;
       struct task_struct *selected = NULL;
       int rem = 0;
       int tasksize;

drivers/staging/android/lowmemorykiller.c +7 -5
@@ -134,15 +134,17 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
        selected_oom_adj = min_adj;
 
        rcu_read_lock();
-       for_each_process(p) {
-               struct mm_struct *mm;
+       for_each_process(tsk) {
+               struct task_struct *p;
                struct signal_struct *sig;
                int oom_adj;
 
-               task_lock(p);
-               mm = p->mm;
+               p = find_lock_task_mm(tsk);
+               if (!p)
+                       continue;
+
                sig = p->signal;
-               if (!mm || !sig) {
+               if (!sig) {
                        task_unlock(p);
                        continue;
                }

drivers/staging/android/lowmemorykiller.c static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 159

Quoted 8 lines
drivers/staging/android/lowmemorykiller.c +1 -1
@@ -151,7 +153,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
                        task_unlock(p);
                        continue;
                }
-               tasksize = get_mm_rss(mm);
+               tasksize = get_mm_rss(p->mm);
                task_unlock(p);
                if (tasksize <= 0)
                        continue;

ack.

Reviewed-by on v1 4/6
#30 lore raw

Re: [PATCH 4/6] staging: android/lowmemorykiller: Better mm handling

In reply to Anton Vorontsov
Quoted 6 lines · Anton Vorontsov

LMK should not directly check for task->mm. The reason is that the process' threads may exit or detach its mm via use_mm(), but other threads may still have a valid mm. To catch this we use find_lock_task_mm(), which walks up all threads and returns an appropriate task (with lock held).

#31 lore raw

PATCH 5/6 staging: android/lowmemorykiller: No need for task->signal check

In reply to Oleg Nesterov

task->signal == NULL is not possible, so no need for these checks.

---
 drivers/staging/android/lowmemorykiller.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)
drivers/staging/android/lowmemorykiller.c +1 -7
index 0755e2f..6e800d3 100644
@@ -136,19 +136,13 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 	rcu_read_lock();
 	for_each_process(tsk) {
 		struct task_struct *p;
-		struct signal_struct *sig;
 		int oom_adj;
 
 		p = find_lock_task_mm(tsk);
 		if (!p)
 			continue;
 
-		sig = p->signal;
-		if (!sig) {
-			task_unlock(p);
-			continue;
-		}
-		oom_adj = sig->oom_adj;
+		oom_adj = p->signal->oom_adj;
 		if (oom_adj < min_adj) {
 			task_unlock(p);
 			continue;
Signature · 1 line
1.7.7.6
#32 lore raw

Re: [PATCH 5/6] staging: android/lowmemorykiller: No need for task->signal check

Quoted 18 lines

 drivers/staging/android/lowmemorykiller.c |    8 +-------

 1 files changed, 1 insertions(+), 7 deletions(-)
drivers/staging/android/lowmemorykiller.c +0 -1
index 0755e2f..6e800d3 100644
@@ -136,19 +136,13 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
        rcu_read_lock();
        for_each_process(tsk) {
                struct task_struct *p;
-               struct signal_struct *sig;
                int oom_adj;
 
                p = find_lock_task_mm(tsk);
                if (!p)
                        continue;
 

drivers/staging/android/lowmemorykiller.c static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 148

Quoted 10 lines
drivers/staging/android/lowmemorykiller.c +1 -6
-               sig = p->signal;
-               if (!sig) {
-                       task_unlock(p);
-                       continue;
-               }
-               oom_adj = sig->oom_adj;
+               oom_adj = p->signal->oom_adj;
                if (oom_adj < min_adj) {
                        task_unlock(p);
                        continue;

ack.

#34 lore raw

PATCH 6/6 staging: android/lowmemorykiller: Do not kill kernel threads

In reply to Oleg Nesterov

LMK should not try killing kernel threads.

---
 drivers/staging/android/lowmemorykiller.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/staging/android/lowmemorykiller.c +3 -0
index 6e800d3..ae38c39 100644
@@ -138,6 +138,9 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
 		struct task_struct *p;
 		int oom_adj;
 
+		if (tsk->flags & PF_KTHREAD)
+			continue;
+
 		p = find_lock_task_mm(tsk);
 		if (!p)
 			continue;
Signature · 1 line
1.7.7.6
#35 lore raw

Re: [PATCH 6/6] staging: android/lowmemorykiller: Do not kill kernel threads

2012/2/6 Anton Vorontsov <[email protected]>:

Quoted 13 lines

LMK should not try killing kernel threads.

---
 drivers/staging/android/lowmemorykiller.c |    3 +++

 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/staging/android/lowmemorykiller.c +0 -0
index 6e800d3..ae38c39 100644

drivers/staging/android/lowmemorykiller.c static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) · line 143

Quoted 6 lines
drivers/staging/android/lowmemorykiller.c +3 -0
@@ -138,6 +138,9 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
                struct task_struct *p;
                int oom_adj;
 
+               if (tsk->flags & PF_KTHREAD)
+                       continue;
+

ack.