mm: Support address range reclaim

This patch adds address range reclaim of a process.
The requirement is following as,

Like webkit1, it uses a address space for handling multi tabs.
IOW, it uses *one* process model so all tabs shares address space
of the process. In such scenario, per-process reclaim is rather
coarse-grained so this patch supports more fine-grained reclaim
for being able to reclaim target address range of the process.
For reclaim target range, you should use following format.

	echo [addr] [size-byte] > /proc/pid/reclaim
The addr should be page-aligned.

So now reclaim konb's interface is following as.

echo file > /proc/pid/reclaim
	reclaim file-backed pages only
echo anon > /proc/pid/reclaim
	reclaim anonymous pages only
echo all > /proc/pid/reclaim
	reclaim all pages
echo 0x100000 8K > /proc/pid/reclaim
	reclaim pages in (0x100000 - 0x102000)

Change-Id: I111131d31be1cfcfa246617b634a9a8bc4078098
Signed-off-by: Minchan Kim <[email protected]>
Patch-mainline: linux-mm @ 9 May 2013 08:39:01
[[email protected]: trivial merge conflict fixes]
Signed-off-by: Vinayak Menon <[email protected]>
This commit is contained in:
Minchan Kim 2013-05-09 16:21:28 +09:00 • committed by Gerrit - the friendly Code Review server
commit c97020e651
2 changed files with 70 additions and 12 deletions

View file

@ -20,6 +20,7 @@
#include <linux/uaccess.h>
#include <linux/pkeys.h>
#include <linux/mm_inline.h>
#include <linux/ctype.h>
#include <asm/elf.h>
#include <asm/tlb.h>
@ -1765,11 +1766,16 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct task_struct *task;
char buffer[PROC_NUMBUF];
char buffer[200];
struct mm_struct *mm;
struct vm_area_struct *vma;
enum reclaim_type type;
char *type_buf;
unsigned long start = 0;
unsigned long end = 0;
const struct mm_walk_ops reclaim_walk_ops = {
.pmd_entry = reclaim_pte_range,
};
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
@ -1785,40 +1791,89 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf,
type = RECLAIM_ANON;
else if (!strcmp(type_buf, "all"))
type = RECLAIM_ALL;
else if (isdigit(*type_buf))
type = RECLAIM_RANGE;
else
return -EINVAL;
goto out_err;
if (type == RECLAIM_RANGE) {
char *token;
unsigned long long len, len_in, tmp;
token = strsep(&type_buf, " ");
if (!token)
goto out_err;
tmp = memparse(token, &token);
if (tmp & ~PAGE_MASK || tmp > ULONG_MAX)
goto out_err;
start = tmp;
token = strsep(&type_buf, " ");
if (!token)
goto out_err;
len_in = memparse(token, &token);
len = (len_in + ~PAGE_MASK) & PAGE_MASK;
if (len > ULONG_MAX)
goto out_err;
/*
* Check to see whether len was rounded up from small -ve
* to zero.
*/
if (len_in && !len)
goto out_err;
end = start + len;
if (end < start)
goto out_err;
}
task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
mm = get_task_mm(task);
if (mm) {
const struct mm_walk_ops reclaim_walk_ops = {
.pmd_entry = reclaim_pte_range,
};
if (!mm)
goto out;
down_read(&mm->mmap_sem);
down_read(&mm->mmap_sem);
if (type == RECLAIM_RANGE) {
vma = find_vma(mm, start);
while (vma) {
if (vma->vm_start > end)
break;
if (is_vm_hugetlb_page(vma))
continue;
walk_page_range(mm, max(vma->vm_start, start),
min(vma->vm_end, end),
&reclaim_walk_ops, vma);
vma = vma->vm_next;
}
} else {
for (vma = mm->mmap; vma; vma = vma->vm_next) {
if (is_vm_hugetlb_page(vma))
continue;
if (type == RECLAIM_ANON && vma->vm_file)
continue;
if (type == RECLAIM_FILE && !vma->vm_file)
continue;
walk_page_range(mm, vma->vm_start, vma->vm_end,
&reclaim_walk_ops, vma);
}
flush_tlb_mm(mm);
up_read(&mm->mmap_sem);
mmput(mm);
}
put_task_struct(task);
flush_tlb_mm(mm);
up_read(&mm->mmap_sem);
mmput(mm);
out:
put_task_struct(task);
return count;
out_err:
return -EINVAL;
}
const struct file_operations proc_reclaim_operations = {