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:
Minchan Kim
2022-03-29 21:50:32 -07:00
committed by Todd Kjos
parent e17f903a92
commit 5c70ecb399
13 changed files with 26 additions and 231 deletions

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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)
{
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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() */

View File

@@ -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(&lt_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(&lt_buffer.lock, flags);
record = lt_buffer.buffer[idx];
spin_unlock_irqrestore(&lt_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(&lt_buffer.lock, flags);
memset(lt_buffer.buffer, 0,
sizeof(struct captured_pinner) * PP_BUF_SIZE);
lt_buffer.index = 0;
spin_unlock_irqrestore(&lt_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,