ANDROID: 16K: Emulate mincore() syscall
Collapse 4 4KiB mincore entries to a single 16KiB entry if emulating a 16KiB page size to userspace. Note: nr_subpages == 1 when not emulating the page size, which makes the change a no-op in the normal case. Bug: 383389337 Bug: 385169772 Test: atest vts_ltp_test_x86_64:syscalls.mincore03_64bit#syscalls.mincore03_64bit Test: atest vts_ltp_test_x86_64:syscalls.mincore04_64bit#syscalls.mincore04_64bit Change-Id: I905b6e0863eb47d03afbb3898063997eb4d3e814 Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
596774b15c
commit
8aab407984
39
mm/mincore.c
39
mm/mincore.c
@@ -18,6 +18,7 @@
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <linux/page_size_compat.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include "swap.h"
|
||||
@@ -205,6 +206,20 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v
|
||||
return (end - addr) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static inline void __collapse_mincore_result(unsigned char *src_vec,
|
||||
unsigned char *res_vec,
|
||||
unsigned long pages,
|
||||
unsigned long nr_subpages)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
if (nr_subpages == 1)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pages; i++)
|
||||
res_vec[i / nr_subpages] |= src_vec[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* The mincore(2) system call.
|
||||
*
|
||||
@@ -235,11 +250,13 @@ SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
|
||||
long retval;
|
||||
unsigned long pages;
|
||||
unsigned char *tmp;
|
||||
unsigned char *res;
|
||||
unsigned long nr_subpages = __PAGE_SIZE / PAGE_SIZE;
|
||||
|
||||
start = untagged_addr(start);
|
||||
|
||||
/* Check the start address: needs to be page-aligned.. */
|
||||
if (start & ~PAGE_MASK)
|
||||
if (start & ~__PAGE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
/* ..and we need to be passed a valid user-space range */
|
||||
@@ -250,13 +267,22 @@ SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
|
||||
pages = len >> PAGE_SHIFT;
|
||||
pages += (offset_in_page(len)) != 0;
|
||||
|
||||
if (!access_ok(vec, pages))
|
||||
if (!access_ok(vec, pages / nr_subpages))
|
||||
return -EFAULT;
|
||||
|
||||
tmp = (void *) __get_free_page(GFP_USER);
|
||||
if (!tmp)
|
||||
return -EAGAIN;
|
||||
|
||||
if (unlikely(nr_subpages > 1)) {
|
||||
res = (void *) __get_free_page(GFP_USER|__GFP_ZERO);
|
||||
if (!res) {
|
||||
free_page((unsigned long) tmp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
} else
|
||||
res = tmp;
|
||||
|
||||
retval = 0;
|
||||
while (pages) {
|
||||
/*
|
||||
@@ -269,15 +295,20 @@ SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
|
||||
|
||||
if (retval <= 0)
|
||||
break;
|
||||
if (copy_to_user(vec, tmp, retval)) {
|
||||
|
||||
__collapse_mincore_result(tmp, res, retval, nr_subpages);
|
||||
|
||||
if (copy_to_user(vec, res, retval / nr_subpages)) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
pages -= retval;
|
||||
vec += retval;
|
||||
vec += retval / nr_subpages;
|
||||
start += retval << PAGE_SHIFT;
|
||||
retval = 0;
|
||||
}
|
||||
if (unlikely(nr_subpages > 1))
|
||||
free_page((unsigned long) res);
|
||||
free_page((unsigned long) tmp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user