mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 20:10:23 +09:00
ANDROID: mm: page_pinner: remove longterm_pinner
From the experience, longterm_pinner is not worth maintaining considering how much it churns MM. Just drop the feature and we are good with alloc_contig_failed. The visible effect from this patch is 1. drop $debugfs/page_pinner/longterm_pinner 2. drop put_user_page expoerted API 3. rename alloc_contig_failed to buffer Bug: 218731671 Signed-off-by: Minchan Kim <minchan@google.com> Change-Id: I68cc11db448260987a9e26b99647ecb55f571616
This commit is contained in:
@@ -900,7 +900,7 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start,
|
||||
|
||||
stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
|
||||
kunmap(page);
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
} else {
|
||||
stop = !dump_skip(cprm, PAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
|
||||
|
||||
static void put_arg_page(struct page *page)
|
||||
{
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
static void free_arg_pages(struct linux_binprm *bprm)
|
||||
|
||||
@@ -693,11 +693,7 @@ static void fuse_copy_finish(struct fuse_copy_state *cs)
|
||||
flush_dcache_page(cs->pg);
|
||||
set_page_dirty_lock(cs->pg);
|
||||
}
|
||||
/*
|
||||
* The page could be GUP page(see iov_iter_get_pages in
|
||||
* fuse_copy_fill) so use put_user_page to release it.
|
||||
*/
|
||||
put_user_page(cs->pg);
|
||||
put_page(cs->pg);
|
||||
}
|
||||
cs->pg = NULL;
|
||||
}
|
||||
|
||||
@@ -1286,7 +1286,6 @@ static inline void put_page(struct page *page)
|
||||
*/
|
||||
#define GUP_PIN_COUNTING_BIAS (1U << 10)
|
||||
|
||||
void put_user_page(struct page *page);
|
||||
void unpin_user_page(struct page *page);
|
||||
void unpin_user_pages_dirty_lock(struct page **pages, unsigned long npages,
|
||||
bool make_dirty);
|
||||
|
||||
@@ -20,8 +20,6 @@ enum page_ext_flags {
|
||||
PAGE_EXT_OWNER,
|
||||
PAGE_EXT_OWNER_ALLOCATED,
|
||||
#if defined(CONFIG_PAGE_PINNER)
|
||||
/* page refcount was increased by GUP or follow_page(FOLL_GET) */
|
||||
PAGE_EXT_GET,
|
||||
/* page migration failed */
|
||||
PAGE_EXT_PINNER_MIGRATION_FAILED,
|
||||
#endif
|
||||
|
||||
@@ -9,31 +9,17 @@ extern struct static_key_false page_pinner_inited;
|
||||
extern struct static_key_true failure_tracking;
|
||||
extern struct page_ext_operations page_pinner_ops;
|
||||
|
||||
extern void __unset_page_pinner(struct page *page, unsigned int order);
|
||||
extern void __free_page_pinner(struct page *page, unsigned int order);
|
||||
extern void __set_page_pinner(struct page *page, unsigned int order);
|
||||
extern void __dump_page_pinner(struct page *page);
|
||||
void __page_pinner_failure_detect(struct page *page);
|
||||
void __page_pinner_put_page(struct page *page);
|
||||
|
||||
static inline void unset_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
if (static_branch_unlikely(&page_pinner_inited))
|
||||
__unset_page_pinner(page, order);
|
||||
}
|
||||
|
||||
static inline void free_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
if (static_branch_unlikely(&page_pinner_inited))
|
||||
__free_page_pinner(page, order);
|
||||
}
|
||||
|
||||
static inline void set_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
if (static_branch_unlikely(&page_pinner_inited))
|
||||
__set_page_pinner(page, order);
|
||||
}
|
||||
|
||||
static inline void dump_page_pinner(struct page *page)
|
||||
{
|
||||
if (static_branch_unlikely(&page_pinner_inited))
|
||||
@@ -56,15 +42,9 @@ static inline void page_pinner_failure_detect(struct page *page)
|
||||
__page_pinner_failure_detect(page);
|
||||
}
|
||||
#else
|
||||
static inline void unset_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
}
|
||||
static inline void free_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
}
|
||||
static inline void set_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
}
|
||||
static inline void dump_page_pinner(struct page *page)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -587,7 +587,7 @@ again:
|
||||
lock_page(page);
|
||||
shmem_swizzled = PageSwapCache(page) || page->mapping;
|
||||
unlock_page(page);
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
|
||||
if (shmem_swizzled)
|
||||
goto again;
|
||||
@@ -637,7 +637,7 @@ again:
|
||||
|
||||
if (READ_ONCE(page->mapping) != mapping) {
|
||||
rcu_read_unlock();
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
|
||||
goto again;
|
||||
}
|
||||
@@ -645,7 +645,7 @@ again:
|
||||
inode = READ_ONCE(mapping->host);
|
||||
if (!inode) {
|
||||
rcu_read_unlock();
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
|
||||
goto again;
|
||||
}
|
||||
@@ -657,7 +657,7 @@ again:
|
||||
}
|
||||
|
||||
out:
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
33
mm/gup.c
33
mm/gup.c
@@ -126,10 +126,7 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page,
|
||||
return NULL;
|
||||
|
||||
if (flags & FOLL_GET) {
|
||||
struct page *head = try_get_compound_head(page, refs);
|
||||
if (head)
|
||||
set_page_pinner(head, compound_order(head));
|
||||
return head;
|
||||
return try_get_compound_head(page, refs);
|
||||
} else if (flags & FOLL_PIN) {
|
||||
int orig_refs = refs;
|
||||
|
||||
@@ -184,8 +181,6 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags)
|
||||
refs *= GUP_PIN_COUNTING_BIAS;
|
||||
}
|
||||
|
||||
if (flags & FOLL_GET)
|
||||
unset_page_pinner(page, compound_order(page));
|
||||
put_page_refs(page, refs);
|
||||
}
|
||||
|
||||
@@ -215,13 +210,7 @@ bool __must_check try_grab_page(struct page *page, unsigned int flags)
|
||||
WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN));
|
||||
|
||||
if (flags & FOLL_GET) {
|
||||
bool ret = try_get_page(page);
|
||||
|
||||
if (ret) {
|
||||
page = compound_head(page);
|
||||
set_page_pinner(page, compound_order(page));
|
||||
}
|
||||
return ret;
|
||||
return try_get_page(page);
|
||||
} else if (flags & FOLL_PIN) {
|
||||
int refs = 1;
|
||||
|
||||
@@ -264,24 +253,6 @@ void unpin_user_page(struct page *page)
|
||||
}
|
||||
EXPORT_SYMBOL(unpin_user_page);
|
||||
|
||||
/*
|
||||
* put_user_page() - release a page obtained using get_user_pages() or
|
||||
* follow_page(FOLL_GET)
|
||||
* @page: pointer to page to be released
|
||||
*
|
||||
* Pages that were obtained via get_user_pages()/follow_page(FOLL_GET) must be
|
||||
* released via put_user_page.
|
||||
* note: If it's not a page from GUP or follow_page(FOLL_GET), it's harmless.
|
||||
*/
|
||||
void put_user_page(struct page *page)
|
||||
{
|
||||
struct page *head = compound_head(page);
|
||||
|
||||
unset_page_pinner(head, compound_order(head));
|
||||
put_page(page);
|
||||
}
|
||||
EXPORT_SYMBOL(put_user_page);
|
||||
|
||||
/**
|
||||
* unpin_user_pages_dirty_lock() - release and optionally dirty gup-pinned pages
|
||||
* @pages: array of pages to be maybe marked dirty, and definitely released.
|
||||
|
||||
18
mm/ksm.c
18
mm/ksm.c
@@ -484,7 +484,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr)
|
||||
NULL);
|
||||
else
|
||||
ret = VM_FAULT_WRITE;
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
} while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM)));
|
||||
/*
|
||||
* We must loop because handle_mm_fault() may back out if there's
|
||||
@@ -569,7 +569,7 @@ static struct page *get_mergeable_page(struct rmap_item *rmap_item)
|
||||
flush_anon_page(vma, page, addr);
|
||||
flush_dcache_page(page);
|
||||
} else {
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
out:
|
||||
page = NULL;
|
||||
}
|
||||
@@ -1950,7 +1950,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item,
|
||||
* Don't substitute a ksm page for a forked page.
|
||||
*/
|
||||
if (page == tree_page) {
|
||||
put_user_page(tree_page);
|
||||
put_page(tree_page);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1958,10 +1958,10 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item,
|
||||
|
||||
parent = *new;
|
||||
if (ret < 0) {
|
||||
put_user_page(tree_page);
|
||||
put_page(tree_page);
|
||||
new = &parent->rb_left;
|
||||
} else if (ret > 0) {
|
||||
put_user_page(tree_page);
|
||||
put_page(tree_page);
|
||||
new = &parent->rb_right;
|
||||
} else if (!ksm_merge_across_nodes &&
|
||||
page_to_nid(tree_page) != nid) {
|
||||
@@ -1970,7 +1970,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item,
|
||||
* it will be flushed out and put in the right unstable
|
||||
* tree next time: only merge with it when across_nodes.
|
||||
*/
|
||||
put_user_page(tree_page);
|
||||
put_page(tree_page);
|
||||
return NULL;
|
||||
} else {
|
||||
*tree_pagep = tree_page;
|
||||
@@ -2151,7 +2151,7 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item)
|
||||
*/
|
||||
split = PageTransCompound(page)
|
||||
&& compound_head(page) == compound_head(tree_page);
|
||||
put_user_page(tree_page);
|
||||
put_page(tree_page);
|
||||
if (kpage) {
|
||||
/*
|
||||
* The pages were successfully merged: insert new
|
||||
@@ -2320,11 +2320,11 @@ next_mm:
|
||||
&rmap_item->rmap_list;
|
||||
ksm_scan.address += PAGE_SIZE;
|
||||
} else
|
||||
put_user_page(*page);
|
||||
put_page(*page);
|
||||
mmap_read_unlock(mm);
|
||||
return rmap_item;
|
||||
}
|
||||
put_user_page(*page);
|
||||
put_page(*page);
|
||||
ksm_scan.address += PAGE_SIZE;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
@@ -5535,7 +5535,7 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
|
||||
buf, maddr + offset, bytes);
|
||||
}
|
||||
kunmap(page);
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
}
|
||||
len -= bytes;
|
||||
buf += bytes;
|
||||
|
||||
@@ -1655,7 +1655,7 @@ out_putpage:
|
||||
* isolate_lru_page() or drop the page ref if it was
|
||||
* not isolated.
|
||||
*/
|
||||
put_user_page(page);
|
||||
put_page(page);
|
||||
out:
|
||||
mmap_read_unlock(mm);
|
||||
return err;
|
||||
|
||||
@@ -472,14 +472,6 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
|
||||
*/
|
||||
page = follow_page(vma, start, FOLL_GET | FOLL_DUMP);
|
||||
if (page && !IS_ERR(page)) {
|
||||
/*
|
||||
* munlock_vma_pages_range uses follow_page(FOLL_GET)
|
||||
* so it need to use put_user_page but the munlock
|
||||
* path is quite complicated to deal with each put
|
||||
* sites correctly so just unattribute them to avoid
|
||||
* false positive at this moment.
|
||||
*/
|
||||
unset_page_pinner(page, compound_order(page));
|
||||
if (PageTransTail(page)) {
|
||||
VM_BUG_ON_PAGE(PageMlocked(page), page);
|
||||
put_page(page); /* follow_page_mask() */
|
||||
|
||||
153
mm/page_pinner.c
153
mm/page_pinner.c
@@ -51,12 +51,6 @@ struct page_pinner_buffer {
|
||||
struct captured_pinner buffer[PP_BUF_SIZE];
|
||||
};
|
||||
|
||||
static struct page_pinner_buffer lt_buffer = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(lt_buffer.lock),
|
||||
};
|
||||
|
||||
static s64 threshold_usec = 300000;
|
||||
|
||||
/* alloc_contig failed pinner */
|
||||
static struct page_pinner_buffer acf_buffer = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(acf_buffer.lock),
|
||||
@@ -148,51 +142,6 @@ static void add_record(struct page_pinner_buffer *pp_buf,
|
||||
spin_unlock_irqrestore(&pp_buf->lock, flags);
|
||||
}
|
||||
|
||||
static void check_longterm_pin(struct page_pinner *page_pinner,
|
||||
struct page *page)
|
||||
{
|
||||
s64 now, delta = 0;
|
||||
struct captured_pinner record;
|
||||
|
||||
now = ktime_to_us(ktime_get_boottime());
|
||||
|
||||
/* get/put_page can be raced. Ignore that case */
|
||||
if (page_pinner->ts_usec < now)
|
||||
delta = now - page_pinner->ts_usec;
|
||||
|
||||
if (delta <= threshold_usec)
|
||||
return;
|
||||
|
||||
record.handle = page_pinner->handle;
|
||||
record.elapsed = delta;
|
||||
record.state = PP_PUT;
|
||||
capture_page_state(page, &record);
|
||||
|
||||
add_record(<_buffer, &record);
|
||||
}
|
||||
|
||||
void __unset_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
struct page_pinner *page_pinner;
|
||||
struct page_ext *page_ext;
|
||||
int i;
|
||||
|
||||
page_ext = lookup_page_ext(page);
|
||||
if (unlikely(!page_ext))
|
||||
return;
|
||||
|
||||
for (i = 0; i < (1 << order); i++) {
|
||||
if (!test_bit(PAGE_EXT_GET, &page_ext->flags))
|
||||
continue;
|
||||
|
||||
page_pinner = get_page_pinner(page_ext);
|
||||
check_longterm_pin(page_pinner, page);
|
||||
clear_bit(PAGE_EXT_GET, &page_ext->flags);
|
||||
page_pinner->ts_usec = 0;
|
||||
page_ext = page_ext_next(page_ext);
|
||||
}
|
||||
}
|
||||
|
||||
void __free_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
struct page_pinner *page_pinner;
|
||||
@@ -206,8 +155,7 @@ void __free_page_pinner(struct page *page, unsigned int order)
|
||||
for (i = 0; i < (1 << order); i++) {
|
||||
struct captured_pinner record;
|
||||
|
||||
if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags) &&
|
||||
!test_bit(PAGE_EXT_GET, &page_ext->flags))
|
||||
if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags))
|
||||
continue;
|
||||
|
||||
page_pinner = get_page_pinner(page_ext);
|
||||
@@ -226,30 +174,6 @@ void __free_page_pinner(struct page *page, unsigned int order)
|
||||
atomic_set(&page_pinner->count, 0);
|
||||
page_pinner->ts_usec = 0;
|
||||
clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags);
|
||||
clear_bit(PAGE_EXT_GET, &page_ext->flags);
|
||||
page_ext = page_ext_next(page_ext);
|
||||
}
|
||||
}
|
||||
|
||||
noinline void __set_page_pinner(struct page *page, unsigned int order)
|
||||
{
|
||||
struct page_pinner *page_pinner;
|
||||
struct page_ext *page_ext = lookup_page_ext(page);
|
||||
s64 usec = ktime_to_us(ktime_get_boottime());
|
||||
int i;
|
||||
|
||||
depot_stack_handle_t handle;
|
||||
|
||||
if (unlikely(!page_ext))
|
||||
return;
|
||||
|
||||
handle = save_stack(GFP_NOWAIT|__GFP_NOWARN);
|
||||
for (i = 0; i < (1 << order); i++) {
|
||||
page_pinner = get_page_pinner(page_ext);
|
||||
page_pinner->handle = handle;
|
||||
page_pinner->ts_usec = usec;
|
||||
set_bit(PAGE_EXT_GET, &page_ext->flags);
|
||||
atomic_inc(&page_pinner->count);
|
||||
page_ext = page_ext_next(page_ext);
|
||||
}
|
||||
}
|
||||
@@ -414,43 +338,7 @@ void __page_pinner_put_page(struct page *page)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__page_pinner_put_page);
|
||||
|
||||
static ssize_t
|
||||
read_longterm_page_pinner(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
loff_t i, idx;
|
||||
struct captured_pinner record;
|
||||
unsigned long flags;
|
||||
|
||||
if (!static_branch_unlikely(&page_pinner_inited))
|
||||
return -EINVAL;
|
||||
|
||||
if (*ppos >= PP_BUF_SIZE)
|
||||
return 0;
|
||||
|
||||
i = *ppos;
|
||||
*ppos = i + 1;
|
||||
|
||||
/*
|
||||
* reading the records in the reverse order with newest one
|
||||
* being read first followed by older ones
|
||||
*/
|
||||
idx = (lt_buffer.index - 1 - i + PP_BUF_SIZE) %
|
||||
PP_BUF_SIZE;
|
||||
spin_lock_irqsave(<_buffer.lock, flags);
|
||||
record = lt_buffer.buffer[idx];
|
||||
spin_unlock_irqrestore(<_buffer.lock, flags);
|
||||
if (!record.handle)
|
||||
return 0;
|
||||
|
||||
return print_page_pinner(buf, count, &record);
|
||||
}
|
||||
|
||||
static const struct file_operations proc_longterm_pinner_operations = {
|
||||
.read = read_longterm_page_pinner,
|
||||
};
|
||||
|
||||
static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf,
|
||||
static ssize_t read_buffer(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
loff_t i, idx;
|
||||
@@ -482,33 +370,10 @@ static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf,
|
||||
return print_page_pinner(buf, count, &record);
|
||||
}
|
||||
|
||||
static const struct file_operations proc_alloc_contig_failed_operations = {
|
||||
.read = read_alloc_contig_failed,
|
||||
static const struct file_operations proc_buffer_operations = {
|
||||
.read = read_buffer,
|
||||
};
|
||||
|
||||
static int pp_threshold_set(void *data, unsigned long long val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
threshold_usec = (s64)val;
|
||||
|
||||
spin_lock_irqsave(<_buffer.lock, flags);
|
||||
memset(lt_buffer.buffer, 0,
|
||||
sizeof(struct captured_pinner) * PP_BUF_SIZE);
|
||||
lt_buffer.index = 0;
|
||||
spin_unlock_irqrestore(<_buffer.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pp_threshold_get(void *data, unsigned long long *val)
|
||||
{
|
||||
*val = (unsigned long long)threshold_usec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(pp_threshold_fops, pp_threshold_get,
|
||||
pp_threshold_set, "%lld\n");
|
||||
|
||||
static int failure_tracking_set(void *data, u64 val)
|
||||
{
|
||||
bool on;
|
||||
@@ -541,15 +406,9 @@ static int __init page_pinner_init(void)
|
||||
|
||||
pp_debugfs_root = debugfs_create_dir("page_pinner", NULL);
|
||||
|
||||
debugfs_create_file("longterm_pinner", 0444, pp_debugfs_root, NULL,
|
||||
&proc_longterm_pinner_operations);
|
||||
|
||||
debugfs_create_file("threshold", 0644, pp_debugfs_root, NULL,
|
||||
&pp_threshold_fops);
|
||||
|
||||
debugfs_create_file("alloc_contig_failed", 0444,
|
||||
debugfs_create_file("buffer", 0444,
|
||||
pp_debugfs_root, NULL,
|
||||
&proc_alloc_contig_failed_operations);
|
||||
&proc_buffer_operations);
|
||||
|
||||
debugfs_create_file("failure_tracking", 0644,
|
||||
pp_debugfs_root, NULL,
|
||||
|
||||
Reference in New Issue
Block a user