OSDN Git Service

lowmemorykiller: don't unregister notifier from atomic context
authorRabin Vincent <rabin.vincent@stericsson.com>
Thu, 9 Sep 2010 05:18:21 +0000 (10:48 +0530)
committerBrian Swetland <swetland@google.com>
Tue, 29 Mar 2011 20:58:01 +0000 (13:58 -0700)
The lowmemorykiller registers an atomic notifier for notfication of when
the task is freed.  From this atomic notifier callback, it removes the
atomic notifier via task_free_unregister().  This is incorrect because
atomic_notifier_chain_unregister() calls syncronize_rcu(), which can
sleep, which shouldn't be done from an atomic notifier.

Fix this by registering the notifier during init, and only unregister it
if the lowmemorykiller is unloaded.

Change-Id: I1577b04e617bc2b2e39dcb490fcfc9ce660eb7ec
Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: Christian Bejram <christian.bejram@stericsson.com>
drivers/staging/android/lowmemorykiller.c

index 8b67ac0..efbe556 100644 (file)
@@ -71,10 +71,10 @@ static int
 task_notify_func(struct notifier_block *self, unsigned long val, void *data)
 {
        struct task_struct *task = data;
-       if (task == lowmem_deathpending) {
+
+       if (task == lowmem_deathpending)
                lowmem_deathpending = NULL;
-               task_free_unregister(&task_nb);
-       }
+
        return NOTIFY_OK;
 }
 
@@ -168,7 +168,6 @@ static int lowmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask)
                             selected->pid, selected->comm,
                             selected_oom_adj, selected_tasksize);
                lowmem_deathpending = selected;
-               task_free_register(&task_nb);
                force_sig(SIGKILL, selected);
                rem -= selected_tasksize;
        }
@@ -185,6 +184,7 @@ static struct shrinker lowmem_shrinker = {
 
 static int __init lowmem_init(void)
 {
+       task_free_register(&task_nb);
        register_shrinker(&lowmem_shrinker);
        return 0;
 }
@@ -192,6 +192,7 @@ static int __init lowmem_init(void)
 static void __exit lowmem_exit(void)
 {
        unregister_shrinker(&lowmem_shrinker);
+       task_free_unregister(&task_nb);
 }
 
 module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);