From c93a1fab248c46487da803590a0f1cec135cd96a Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Thu, 13 Jun 2019 11:54:36 +0100 Subject: [PATCH] ANDROID: Avoid taking multiple locks in handle_lmk_event Conflicting lock events have been reported resulting from rcu_read_lock, mmap_sem (in get_cmdline) and lmk_event_lock. This CL avoids the possibility of these conditions by moving handle_lmk_event outside rcu_read_lock and invoking get_cmdline before lmk_event_lock is taken. Bug: 133479338, 133829075 Signed-off-by: Jim Blackler Change-Id: Ib3c32587472bd972e3ac108798e2af3f4a5c329a --- drivers/staging/android/lowmemorykiller.c | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 8b19b5e4bd69..d5f5bd4a2d5c 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -102,6 +102,7 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) struct lmk_event *event; int res; long rss_in_pages = -1; + char taskname[MAX_TASKNAME]; struct mm_struct *mm = get_task_mm(selected); if (mm) { @@ -109,6 +110,17 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) mmput(mm); } + res = get_cmdline(selected, taskname, MAX_TASKNAME - 1); + + /* No valid process name means this is definitely not associated with a + * userspace activity. + */ + + if (res <= 0 || res >= MAX_TASKNAME) + return; + + taskname[res] = '\0'; + spin_lock(&lmk_event_lock); head = event_buffer.head; @@ -123,18 +135,8 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) events = (struct lmk_event *) event_buffer.buf; event = &events[head]; - res = get_cmdline(selected, event->taskname, MAX_TASKNAME - 1); + memcpy(event->taskname, taskname, res + 1); - /* No valid process name means this is definitely not associated with a - * userspace activity. - */ - - if (res <= 0 || res >= MAX_TASKNAME) { - spin_unlock(&lmk_event_lock); - return; - } - - event->taskname[res] = '\0'; event->pid = selected->pid; event->uid = from_kuid_munged(current_user_ns(), task_uid(selected)); if (selected->group_leader) @@ -344,13 +346,15 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) free); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; - - handle_lmk_event(selected, min_score_adj); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); rcu_read_unlock(); + + if (selected) + handle_lmk_event(selected, min_score_adj); + return rem; }