Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14e60529 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "proc: update perms of node "reclaim""

parents c2ac24a1 de6408e0
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ Table 1-1: Process specific entries in /proc
 maps		Memory maps to executables and library files	(2.4)
 mem		Memory held by this process
 root		Link to the root directory of this process
 reclaim	Reclaim pages in this process
 stat		Process status
 statm		Process memory status information
 status		Process status in human readable form
@@ -582,6 +583,25 @@ current value:

Any other value written to /proc/PID/clear_refs will have no effect.

The file /proc/PID/reclaim is used to reclaim pages in this process.
To reclaim file-backed pages,
    > echo file > /proc/PID/reclaim

To reclaim anonymous pages,
    > echo anon > /proc/PID/reclaim

To reclaim all pages,
    > echo all > /proc/PID/reclaim

Also, you can specify address range of process so part of address space
will be reclaimed. The format is following as
    > echo addr size-byte > /proc/PID/reclaim

NOTE: addr should be page-aligned.

Below is example which try to reclaim 2M from 0x100000.
    > echo 0x100000 2M > /proc/PID/reclaim

The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
using /proc/kpageflags and number of times a page is mapped using
/proc/kpagecount. For detailed explanation, see
+1 −1
Original line number Diff line number Diff line
@@ -3238,7 +3238,7 @@ static const struct pid_entry tgid_base_stuff[] = {
	REG("mountinfo",  S_IRUGO, proc_mountinfo_operations),
	REG("mountstats", S_IRUSR, proc_mountstats_operations),
#ifdef CONFIG_PROCESS_RECLAIM
	REG("reclaim", 0200, proc_reclaim_operations),
	REG("reclaim", 0222, proc_reclaim_operations),
#endif
#ifdef CONFIG_PROC_PAGE_MONITOR
	REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
+68 −13
Original line number Diff line number Diff line
@@ -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>
@@ -1746,7 +1747,7 @@ static int reclaim_pte_range(pmd_t *pmd, unsigned long addr,
			break;
	}
	pte_unmap_unlock(pte - 1, ptl);
	reclaim_pages_from_list(&page_list);
	reclaim_pages_from_list(&page_list, vma);
	if (addr != end)
		goto cont;

@@ -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);
		for (vma = mm->mmap; vma; vma = vma->vm_next) {
	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);
	}
out:
	put_task_struct(task);

	return count;

out_err:
	return -EINVAL;
}

const struct file_operations proc_reclaim_operations = {
+6 −3
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@

extern int isolate_lru_page(struct page *page);
extern void putback_lru_page(struct page *page);
extern unsigned long reclaim_pages_from_list(struct list_head *page_list);
extern unsigned long reclaim_pages_from_list(struct list_head *page_list,
					     struct vm_area_struct *vma);

/*
 * The anon_vma heads a list of private "related" vmas, to scan if
@@ -199,7 +200,8 @@ static inline void page_dup_rmap(struct page *page, bool compound)
int page_referenced(struct page *, int is_locked,
			struct mem_cgroup *memcg, unsigned long *vm_flags);

bool try_to_unmap(struct page *, enum ttu_flags flags);
bool try_to_unmap(struct page *page, enum ttu_flags flags,
				struct vm_area_struct *vma);

/* Avoid racy checks */
#define PVMW_SYNC		(1 << 0)
@@ -265,6 +267,7 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
 */
struct rmap_walk_control {
	void *arg;
	struct vm_area_struct *target_vma;
	/*
	 * Return false if page table scanning in rmap_walk should be stopped.
	 * Otherwise, return true.
@@ -293,7 +296,7 @@ static inline int page_referenced(struct page *page, int is_locked,
	return 0;
}

#define try_to_unmap(page, refs) false
#define try_to_unmap(page, refs, vma) false

static inline int page_mkclean(struct page *page)
{
+3 −0
Original line number Diff line number Diff line
@@ -845,4 +845,7 @@ config PROCESS_RECLAIM
	 (echo anon > /proc/PID/reclaim) reclaims anonymous pages only.
	 (echo all > /proc/PID/reclaim) reclaims all pages.

	 (echo addr size-byte > /proc/PID/reclaim) reclaims pages in
	 (addr, addr + size-bytes) of the process.

	 Any other value is ignored.
Loading