|
@@ -465,6 +465,10 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define CLEAR_REFS_ALL 1
|
|
|
+#define CLEAR_REFS_ANON 2
|
|
|
+#define CLEAR_REFS_MAPPED 3
|
|
|
+
|
|
|
static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|
|
size_t count, loff_t *ppos)
|
|
|
{
|
|
@@ -472,13 +476,15 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|
|
char buffer[PROC_NUMBUF], *end;
|
|
|
struct mm_struct *mm;
|
|
|
struct vm_area_struct *vma;
|
|
|
+ int type;
|
|
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
if (count > sizeof(buffer) - 1)
|
|
|
count = sizeof(buffer) - 1;
|
|
|
if (copy_from_user(buffer, buf, count))
|
|
|
return -EFAULT;
|
|
|
- if (!simple_strtol(buffer, &end, 0))
|
|
|
+ type = simple_strtol(buffer, &end, 0);
|
|
|
+ if (type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED)
|
|
|
return -EINVAL;
|
|
|
if (*end == '\n')
|
|
|
end++;
|
|
@@ -494,9 +500,23 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|
|
down_read(&mm->mmap_sem);
|
|
|
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
|
|
clear_refs_walk.private = vma;
|
|
|
- if (!is_vm_hugetlb_page(vma))
|
|
|
- walk_page_range(vma->vm_start, vma->vm_end,
|
|
|
- &clear_refs_walk);
|
|
|
+ if (is_vm_hugetlb_page(vma))
|
|
|
+ continue;
|
|
|
+ /*
|
|
|
+ * Writing 1 to /proc/pid/clear_refs affects all pages.
|
|
|
+ *
|
|
|
+ * Writing 2 to /proc/pid/clear_refs only affects
|
|
|
+ * Anonymous pages.
|
|
|
+ *
|
|
|
+ * Writing 3 to /proc/pid/clear_refs only affects file
|
|
|
+ * mapped pages.
|
|
|
+ */
|
|
|
+ if (type == CLEAR_REFS_ANON && vma->vm_file)
|
|
|
+ continue;
|
|
|
+ if (type == CLEAR_REFS_MAPPED && !vma->vm_file)
|
|
|
+ continue;
|
|
|
+ walk_page_range(vma->vm_start, vma->vm_end,
|
|
|
+ &clear_refs_walk);
|
|
|
}
|
|
|
flush_tlb_mm(mm);
|
|
|
up_read(&mm->mmap_sem);
|