ANDROID: 16K: Emulate pread() for pagemap
pread() can read from a specified offset of the file without changing the files offset position. In the case of reading /proc/*/pagemap with pread() in an emulated 16KB x86_64 device, userspace believes the pages are large than they actually are; we adjust the start offset of the pread to emulate reading the correct page map entries. Adjustment of the count is handled by .pagemap_read() which will be called by the VFS layer. This is effectively a no-op in the page size isn't being emulated. Bug: 383389337 Bug: 385167611 Test: atest vts_ltp_test_x86_64:syscalls.msync04_64bit#syscalls.msync04_64bit Test: atest vts_ltp_test_x86_64:syscalls.mmap12_64bit#syscalls.mmap12_64bit Test: atest libmeminfo_test Test: atest bionic-unit-tests:DlExtRelroSharingTest#VerifyMemorySaving Note: bionic-unit-tests must be run as root (add require_root: true) Change-Id: I139d510d7fdb7040236e01a2dc9ee9d5c9c207fd Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
669f0c4355
commit
d684b3125e
@@ -2923,6 +2923,11 @@ const struct file_operations proc_pagemap_operations = {
|
||||
.unlocked_ioctl = do_pagemap_cmd,
|
||||
.compat_ioctl = do_pagemap_cmd,
|
||||
};
|
||||
|
||||
bool __is_emulated_pagemap_file(struct file *file)
|
||||
{
|
||||
return __PAGE_SIZE != PAGE_SIZE && file->f_op == &proc_pagemap_operations;
|
||||
}
|
||||
#endif /* CONFIG_PROC_PAGE_MONITOR */
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/page_size_compat.h>
|
||||
#include <linux/splice.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mount.h>
|
||||
@@ -760,6 +761,17 @@ ssize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count,
|
||||
f = fdget(fd);
|
||||
if (fd_file(f)) {
|
||||
ret = -ESPIPE;
|
||||
|
||||
/*
|
||||
* If userspace thinks the pages are larger than they actually are,
|
||||
* adjust the offset and count to compensate.
|
||||
*
|
||||
* NOTE: We only need to adjust the position here since pagemap_read()
|
||||
* handles updating the count.
|
||||
*/
|
||||
if (__is_emulated_pagemap_file(fd_file(f)))
|
||||
pos *= __PAGE_SIZE / PAGE_SIZE;
|
||||
|
||||
if (fd_file(f)->f_mode & FMODE_PREAD)
|
||||
ret = vfs_read(fd_file(f), buf, count, &pos);
|
||||
fdput(f);
|
||||
|
||||
@@ -165,6 +165,15 @@ extern void __fold_filemap_fixup_entry(struct vma_iterator *iter, unsigned long
|
||||
|
||||
extern int __fixup_swap_header(struct file *swap_file, struct address_space *mapping);
|
||||
|
||||
#ifdef CONFIG_PROC_PAGE_MONITOR
|
||||
extern bool __is_emulated_pagemap_file(struct file *file);
|
||||
#else
|
||||
static inline bool __is_emulated_pagemap_file(struct file *file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __LINUX_PAGE_SIZE_COMPAT_H */
|
||||
|
||||
Reference in New Issue
Block a user