Re: [RFC] simple_lmk: Introduce Simple Low Memory Killer for Android
From: Sultan Alsawaf
Date: Thu May 09 2019 - 14:35:12 EST
On Thu, May 09, 2019 at 05:56:46PM +0200, Oleg Nesterov wrote:
> Impossible ;) I bet lockdep should report the deadlock as soon as find_victims()
> calls find_lock_task_mm() when you already have a locked victim.
I hope you're not a betting man ;)
With the following configured:
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_SPINLOCK=y
# CONFIG_DEBUG_SPINLOCK_BITE_ON_BUG is not set
CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_LOCKDEP=y
CONFIG_LOCK_STAT=y
CONFIG_DEBUG_LOCKDEP=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
And a printk added in vtsk_is_duplicate() to print when a duplicate is detected,
and my phone's memory cut in half to make simple_lmk do something, this is what
I observed:
taimen:/ # dmesg | grep lockdep
[ 0.000000] \x09RCU lockdep checking is enabled.
taimen:/ # dmesg | grep simple_lmk
[ 23.211091] simple_lmk: Killing android.carrier with adj 906 to free 37420 kiB
[ 23.211160] simple_lmk: Killing oadcastreceiver with adj 906 to free 36784 kiB
[ 23.248457] simple_lmk: Killing .apps.translate with adj 904 to free 45884 kiB
[ 23.248720] simple_lmk: Killing ndroid.settings with adj 904 to free 42868 kiB
[ 23.313417] simple_lmk: DUPLICATE VTSK!
[ 23.313440] simple_lmk: Killing ndroid.keychain with adj 906 to free 33680 kiB
[ 23.313513] simple_lmk: Killing com.whatsapp with adj 904 to free 51436 kiB
[ 34.646695] simple_lmk: DUPLICATE VTSK!
[ 34.646717] simple_lmk: Killing ndroid.apps.gcs with adj 906 to free 37956 kiB
[ 34.646792] simple_lmk: Killing droid.apps.maps with adj 904 to free 63600 kiB
taimen:/ # dmesg | grep lockdep
[ 0.000000] \x09RCU lockdep checking is enabled.
taimen:/ #
> As for https://github.com/kerneltoast/android_kernel_google_wahoo/commit/afc8c9bf2dbde95941253c168d1adb64cfa2e3ad
> Well,
>
> mmdrop(mm);
> simple_lmk_mm_freed(mm);
>
> looks racy because mmdrop(mm) can free this mm_struct. Yes, simple_lmk_mm_freed()
> does not dereference this pointer, but the same memory can be re-allocated as
> another ->mm for the new task which can be found by find_victims(), and _in theory_
> this all can happen in between, so the "victims[i].mm == mm" can be false positive.
>
> And this also means that simple_lmk_mm_freed() should clear victims[i].mm when
> it detects "victims[i].mm == mm", otherwise we have the same theoretical race,
> victims_to_kill is only cleared when the last victim goes away.
Fair point. Putting simple_lmk_mm_freed(mm) right before mmdrop(mm), and
sprinkling in a cmpxchg in simple_lmk_mm_freed() should fix that up.
> Another nit... you can drop tasklist_lock right after the 1st "find_victims" loop.
True!
> And it seems that you do not really need to walk the "victims" array twice after that,
> you can do everything in a single loop, but this is cosmetic.
Won't this result in potentially holding the task lock way longer than necessary
for multiple tasks that aren't going to be killed?
Thanks,
Sultan