mirror of
https://gitee.com/openharmony/kernel_linux
synced 2025-05-20 13:46:37 +00:00

Drop the global lru lock in isolate callback before calling zap_page_range which calls cond_resched, and re-acquire the global lru lock before returning. Also change return code to LRU_REMOVED_RETRY. Use mmput_async when fail to acquire mmap sem in an atomic context. Fix "BUG: sleeping function called from invalid context" errors when CONFIG_DEBUG_ATOMIC_SLEEP is enabled. Also restore mmput_async, which was initially introduced in commit ec8d7c14ea14 ("mm, oom_reaper: do not mmput synchronously from the oom reaper context"), and was removed in commit 212925802454 ("mm: oom: let oom_reap_task and exit_mmap run concurrently"). Link: http://lkml.kernel.org/r/20170914182231.90908-1-sherryy@android.com Fixes: f2517eb76f1f2 ("android: binder: Add global lru shrinker to binder") Signed-off-by: Sherry Yang <sherryy@android.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reported-by: Kyle Yan <kyan@codeaurora.org> Acked-by: Arve Hjønnevåg <arve@android.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Martijn Coenen <maco@google.com> Cc: Todd Kjos <tkjos@google.com> Cc: Riley Andrews <riandrews@android.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Hillf Danton <hdanton@sina.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Hoeun Ryu <hoeun.ryu@gmail.com> Cc: Christopher Lameter <cl@linux.com> Cc: Vegard Nossum <vegard.nossum@oracle.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
215 lines
6.0 KiB
C
215 lines
6.0 KiB
C
#ifndef _LINUX_SCHED_MM_H
|
|
#define _LINUX_SCHED_MM_H
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mm_types.h>
|
|
#include <linux/gfp.h>
|
|
|
|
/*
|
|
* Routines for handling mm_structs
|
|
*/
|
|
extern struct mm_struct * mm_alloc(void);
|
|
|
|
/**
|
|
* mmgrab() - Pin a &struct mm_struct.
|
|
* @mm: The &struct mm_struct to pin.
|
|
*
|
|
* Make sure that @mm will not get freed even after the owning task
|
|
* exits. This doesn't guarantee that the associated address space
|
|
* will still exist later on and mmget_not_zero() has to be used before
|
|
* accessing it.
|
|
*
|
|
* This is a preferred way to to pin @mm for a longer/unbounded amount
|
|
* of time.
|
|
*
|
|
* Use mmdrop() to release the reference acquired by mmgrab().
|
|
*
|
|
* See also <Documentation/vm/active_mm.txt> for an in-depth explanation
|
|
* of &mm_struct.mm_count vs &mm_struct.mm_users.
|
|
*/
|
|
static inline void mmgrab(struct mm_struct *mm)
|
|
{
|
|
atomic_inc(&mm->mm_count);
|
|
}
|
|
|
|
/* mmdrop drops the mm and the page tables */
|
|
extern void __mmdrop(struct mm_struct *);
|
|
static inline void mmdrop(struct mm_struct *mm)
|
|
{
|
|
if (unlikely(atomic_dec_and_test(&mm->mm_count)))
|
|
__mmdrop(mm);
|
|
}
|
|
|
|
static inline void mmdrop_async_fn(struct work_struct *work)
|
|
{
|
|
struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work);
|
|
__mmdrop(mm);
|
|
}
|
|
|
|
static inline void mmdrop_async(struct mm_struct *mm)
|
|
{
|
|
if (unlikely(atomic_dec_and_test(&mm->mm_count))) {
|
|
INIT_WORK(&mm->async_put_work, mmdrop_async_fn);
|
|
schedule_work(&mm->async_put_work);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* mmget() - Pin the address space associated with a &struct mm_struct.
|
|
* @mm: The address space to pin.
|
|
*
|
|
* Make sure that the address space of the given &struct mm_struct doesn't
|
|
* go away. This does not protect against parts of the address space being
|
|
* modified or freed, however.
|
|
*
|
|
* Never use this function to pin this address space for an
|
|
* unbounded/indefinite amount of time.
|
|
*
|
|
* Use mmput() to release the reference acquired by mmget().
|
|
*
|
|
* See also <Documentation/vm/active_mm.txt> for an in-depth explanation
|
|
* of &mm_struct.mm_count vs &mm_struct.mm_users.
|
|
*/
|
|
static inline void mmget(struct mm_struct *mm)
|
|
{
|
|
atomic_inc(&mm->mm_users);
|
|
}
|
|
|
|
static inline bool mmget_not_zero(struct mm_struct *mm)
|
|
{
|
|
return atomic_inc_not_zero(&mm->mm_users);
|
|
}
|
|
|
|
/* mmput gets rid of the mappings and all user-space */
|
|
extern void mmput(struct mm_struct *);
|
|
#ifdef CONFIG_MMU
|
|
/* same as above but performs the slow path from the async context. Can
|
|
* be called from the atomic context as well
|
|
*/
|
|
void mmput_async(struct mm_struct *);
|
|
#endif
|
|
|
|
/* Grab a reference to a task's mm, if it is not already going away */
|
|
extern struct mm_struct *get_task_mm(struct task_struct *task);
|
|
/*
|
|
* Grab a reference to a task's mm, if it is not already going away
|
|
* and ptrace_may_access with the mode parameter passed to it
|
|
* succeeds.
|
|
*/
|
|
extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode);
|
|
/* Remove the current tasks stale references to the old mm_struct */
|
|
extern void mm_release(struct task_struct *, struct mm_struct *);
|
|
|
|
#ifdef CONFIG_MEMCG
|
|
extern void mm_update_next_owner(struct mm_struct *mm);
|
|
#else
|
|
static inline void mm_update_next_owner(struct mm_struct *mm)
|
|
{
|
|
}
|
|
#endif /* CONFIG_MEMCG */
|
|
|
|
#ifdef CONFIG_MMU
|
|
extern void arch_pick_mmap_layout(struct mm_struct *mm);
|
|
extern unsigned long
|
|
arch_get_unmapped_area(struct file *, unsigned long, unsigned long,
|
|
unsigned long, unsigned long);
|
|
extern unsigned long
|
|
arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
|
|
unsigned long len, unsigned long pgoff,
|
|
unsigned long flags);
|
|
#else
|
|
static inline void arch_pick_mmap_layout(struct mm_struct *mm) {}
|
|
#endif
|
|
|
|
static inline bool in_vfork(struct task_struct *tsk)
|
|
{
|
|
bool ret;
|
|
|
|
/*
|
|
* need RCU to access ->real_parent if CLONE_VM was used along with
|
|
* CLONE_PARENT.
|
|
*
|
|
* We check real_parent->mm == tsk->mm because CLONE_VFORK does not
|
|
* imply CLONE_VM
|
|
*
|
|
* CLONE_VFORK can be used with CLONE_PARENT/CLONE_THREAD and thus
|
|
* ->real_parent is not necessarily the task doing vfork(), so in
|
|
* theory we can't rely on task_lock() if we want to dereference it.
|
|
*
|
|
* And in this case we can't trust the real_parent->mm == tsk->mm
|
|
* check, it can be false negative. But we do not care, if init or
|
|
* another oom-unkillable task does this it should blame itself.
|
|
*/
|
|
rcu_read_lock();
|
|
ret = tsk->vfork_done && tsk->real_parent->mm == tsk->mm;
|
|
rcu_read_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Applies per-task gfp context to the given allocation flags.
|
|
* PF_MEMALLOC_NOIO implies GFP_NOIO
|
|
* PF_MEMALLOC_NOFS implies GFP_NOFS
|
|
*/
|
|
static inline gfp_t current_gfp_context(gfp_t flags)
|
|
{
|
|
/*
|
|
* NOIO implies both NOIO and NOFS and it is a weaker context
|
|
* so always make sure it makes precendence
|
|
*/
|
|
if (unlikely(current->flags & PF_MEMALLOC_NOIO))
|
|
flags &= ~(__GFP_IO | __GFP_FS);
|
|
else if (unlikely(current->flags & PF_MEMALLOC_NOFS))
|
|
flags &= ~__GFP_FS;
|
|
return flags;
|
|
}
|
|
|
|
#ifdef CONFIG_LOCKDEP
|
|
extern void fs_reclaim_acquire(gfp_t gfp_mask);
|
|
extern void fs_reclaim_release(gfp_t gfp_mask);
|
|
#else
|
|
static inline void fs_reclaim_acquire(gfp_t gfp_mask) { }
|
|
static inline void fs_reclaim_release(gfp_t gfp_mask) { }
|
|
#endif
|
|
|
|
static inline unsigned int memalloc_noio_save(void)
|
|
{
|
|
unsigned int flags = current->flags & PF_MEMALLOC_NOIO;
|
|
current->flags |= PF_MEMALLOC_NOIO;
|
|
return flags;
|
|
}
|
|
|
|
static inline void memalloc_noio_restore(unsigned int flags)
|
|
{
|
|
current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
|
|
}
|
|
|
|
static inline unsigned int memalloc_nofs_save(void)
|
|
{
|
|
unsigned int flags = current->flags & PF_MEMALLOC_NOFS;
|
|
current->flags |= PF_MEMALLOC_NOFS;
|
|
return flags;
|
|
}
|
|
|
|
static inline void memalloc_nofs_restore(unsigned int flags)
|
|
{
|
|
current->flags = (current->flags & ~PF_MEMALLOC_NOFS) | flags;
|
|
}
|
|
|
|
static inline unsigned int memalloc_noreclaim_save(void)
|
|
{
|
|
unsigned int flags = current->flags & PF_MEMALLOC;
|
|
current->flags |= PF_MEMALLOC;
|
|
return flags;
|
|
}
|
|
|
|
static inline void memalloc_noreclaim_restore(unsigned int flags)
|
|
{
|
|
current->flags = (current->flags & ~PF_MEMALLOC) | flags;
|
|
}
|
|
|
|
#endif /* _LINUX_SCHED_MM_H */
|