mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
2271989942
PD#SWPL-95400 Problem: If we pin a file in android, the whole data of this file will be loaded to DDR, but most of these data may not be used, this caused memory waste. Solution: delay mark mlocked flags for unevictable pages until it has been faulted. You can use following command to disable this function: echo 0 > /proc/sys/vm/shrink_unevictable Verify: sc2_ah212. Change-Id: I3981b36114ab331c558198b80140aaa91fe7e7df Signed-off-by: Jianxiong Pan <jianxiong.pan@amlogic.com>
171 lines
4.2 KiB
C
171 lines
4.2 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/types.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/arm-smccc.h>
|
|
#include <linux/memcontrol.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/rmap.h>
|
|
#include <linux/spinlock.h>
|
|
#include <internal.h>
|
|
#include <linux/amlogic/pin_file.h>
|
|
|
|
static struct aml_pin_file *aml_pin;
|
|
|
|
extern void lru_add_drain(void);
|
|
|
|
struct page *aml_mlock_page_as_lock_mapping(struct vm_area_struct *vma,
|
|
struct mm_struct *mm, struct vm_fault *vmf, unsigned long address)
|
|
{
|
|
struct address_space *mapping = NULL;
|
|
|
|
/* Android lock it but not access it */
|
|
if (vma->vm_file && !(vma->vm_flags & VM_LOCKED))
|
|
mapping = vma->vm_file->f_mapping;
|
|
if (mapping && test_bit(AS_LOCK_MAPPING, &mapping->flags)) {
|
|
struct page *page;
|
|
spinlock_t *ptl; /* page table lock */
|
|
pte_t *ptep, pte;
|
|
int need_restore = 0;
|
|
|
|
ptep = pte_offset_map_lock(mm, vmf->pmd, address, &ptl);
|
|
pte = *ptep;
|
|
page = vm_normal_page(vmf->vma, address, pte);
|
|
if (page && !PageMlocked(page)) {
|
|
if (page->mapping && trylock_page(page)) {
|
|
pr_debug("fault on locked, new pte:%llx, addr:%lx, page:%lx, %lx, mapping:%px f:%lx\n",
|
|
(unsigned long long)pte_val(pte),
|
|
address, page_to_pfn(page),
|
|
page->flags,
|
|
mapping, mapping->flags);
|
|
lru_add_drain(); /* push cached pages to LRU */
|
|
mlock_vma_page(page);
|
|
/* Set this flag to avoid shrink again */
|
|
/* SetPageCmaAllocating(page); */
|
|
aml_set_pin_locked_file(page);
|
|
unlock_page(page);
|
|
need_restore = 1;
|
|
}
|
|
}
|
|
pte_unmap_unlock(ptep, ptl);
|
|
if (need_restore)
|
|
return page;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void reset_page_vma_flags(struct vm_area_struct *vma, vm_flags_t flags)
|
|
{
|
|
if (vma->vm_file && vma->vm_file->f_mapping) {
|
|
struct inode *host;
|
|
|
|
host = vma->vm_file->f_mapping->host;
|
|
if ((flags & (VM_LOCKED | VM_LOCKONFAULT))) {
|
|
set_bit(AS_LOCK_MAPPING,
|
|
&vma->vm_file->f_mapping->flags);
|
|
atomic_inc(&host->i_count);
|
|
} else if (test_bit(AS_LOCK_MAPPING,
|
|
&vma->vm_file->f_mapping->flags)){
|
|
atomic_dec(&host->i_count);
|
|
clear_bit(AS_LOCK_MAPPING,
|
|
&vma->vm_file->f_mapping->flags);
|
|
}
|
|
pr_debug("%s lock mapping:%px, f:%lx\n",
|
|
flags & (VM_LOCKED | VM_LOCKONFAULT) ?
|
|
"Mark" : "Clear",
|
|
vma->vm_file->f_mapping,
|
|
vma->vm_file->f_mapping->flags);
|
|
}
|
|
}
|
|
|
|
int sysctrl_shrink_unevictable = 1;
|
|
static struct ctl_table shrink_unevictable[] = {
|
|
{
|
|
.procname = "shrink_unevictable",
|
|
.data = &sysctrl_shrink_unevictable,
|
|
.maxlen = sizeof(sysctrl_shrink_unevictable),
|
|
.mode = 0644,
|
|
.proc_handler = proc_dointvec_minmax,
|
|
.extra1 = SYSCTL_ZERO,
|
|
.extra2 = SYSCTL_ONE,
|
|
},
|
|
{ }
|
|
};
|
|
|
|
static int __init aml_gup_init(void)
|
|
{
|
|
register_sysctl("vm", shrink_unevictable);
|
|
return 0;
|
|
}
|
|
fs_initcall(aml_gup_init);
|
|
|
|
int aml_is_pin_locked_file(struct page *page)
|
|
{
|
|
unsigned long pfn;
|
|
|
|
pfn = page_to_pfn(page);
|
|
return test_bit(pfn, aml_pin->bitmap);
|
|
}
|
|
|
|
void aml_set_pin_locked_file(struct page *page)
|
|
{
|
|
unsigned long flags;
|
|
unsigned long pfn;
|
|
|
|
pfn = page_to_pfn(page);
|
|
spin_lock_irqsave(&aml_pin->pin_file_lock, flags);
|
|
bitmap_set(aml_pin->bitmap, pfn, 1);
|
|
spin_unlock_irqrestore(&aml_pin->pin_file_lock, flags);
|
|
}
|
|
|
|
void aml_clear_pin_locked_file(struct page *page)
|
|
{
|
|
unsigned long flags;
|
|
unsigned long pfn;
|
|
|
|
pfn = page_to_pfn(page);
|
|
spin_lock_irqsave(&aml_pin->pin_file_lock, flags);
|
|
bitmap_clear(aml_pin->bitmap, pfn, 1);
|
|
spin_unlock_irqrestore(&aml_pin->pin_file_lock, flags);
|
|
}
|
|
|
|
/* borrow the poking_init function, which comes from init/main.c */
|
|
void __init poking_init(void)
|
|
{
|
|
struct zone *zone;
|
|
unsigned long total_pages = 0;
|
|
|
|
for_each_populated_zone(zone)
|
|
total_pages += zone->spanned_pages;
|
|
|
|
aml_pin = kzalloc(sizeof(*aml_pin), GFP_KERNEL);
|
|
if (!aml_pin)
|
|
return;
|
|
|
|
aml_pin->bitmap = kzalloc(total_pages / 8, GFP_KERNEL);
|
|
if (!aml_pin->bitmap) {
|
|
kfree(aml_pin);
|
|
return;
|
|
}
|
|
|
|
spin_lock_init(&aml_pin->pin_file_lock);
|
|
}
|
|
|