From 892a4f6a750abceeda4c1ee8324f58f82fd6bd89 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 21 Jun 2022 16:42:05 +0200 Subject: linux-user: Add partial support for MADV_DONTNEED Currently QEMU ignores madvise(MADV_DONTNEED), which break apps that rely on this for zeroing out memory [1]. Improve the situation by doing a passthrough when the range in question is a host-page-aligned anonymous mapping. This is based on the patches from Simon Hausmann [2] and Chris Fallin [3]. The structure is taken from Simon's patch. The PAGE_MAP_ANONYMOUS bits are superseded by commit 26bab757d41b ("linux-user: Introduce PAGE_ANON"). In the end the patch acts like the one from Chris: we either pass-through the entire syscall, or do nothing, since doing this only partially would not help the affected applications much. Finally, add some extra checks to match the behavior of the Linux kernel [4]. [1] https://gitlab.com/qemu-project/qemu/-/issues/326 [2] https://patchew.org/QEMU/20180827084037.25316-1-simon.hausmann@qt.io/ [3] https://github.com/bytecodealliance/wasmtime/blob/v0.37.0/ci/qemu-madvise.patch [4] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/madvise.c?h=v5.19-rc3#n1368 Signed-off-by: Ilya Leoshkevich Reviewed-by: Laurent Vivier Message-Id: <20220621144205.158452-1-iii@linux.ibm.com> Signed-off-by: Laurent Vivier --- linux-user/mmap.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'linux-user/mmap.c') diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 48e1373796..4e7a6be6ee 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -835,3 +835,67 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, mmap_unlock(); return new_addr; } + +static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end) +{ + ulong addr; + + if ((start | end) & ~qemu_host_page_mask) { + return false; + } + + for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + if (!(page_get_flags(addr) & PAGE_ANON)) { + return false; + } + } + + return true; +} + +abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) +{ + abi_ulong len, end; + int ret = 0; + + if (start & ~TARGET_PAGE_MASK) { + return -TARGET_EINVAL; + } + len = TARGET_PAGE_ALIGN(len_in); + + if (len_in && !len) { + return -TARGET_EINVAL; + } + + end = start + len; + if (end < start) { + return -TARGET_EINVAL; + } + + if (end == start) { + return 0; + } + + if (!guest_range_valid_untagged(start, len)) { + return -TARGET_EINVAL; + } + + /* + * A straight passthrough may not be safe because qemu sometimes turns + * private file-backed mappings into anonymous mappings. + * + * This is a hint, so ignoring and returning success is ok. + * + * This breaks MADV_DONTNEED, completely implementing which is quite + * complicated. However, there is one low-hanging fruit: host-page-aligned + * anonymous mappings. In this case passthrough is safe, so do it. + */ + mmap_lock(); + if ((advice & MADV_DONTNEED) && + can_passthrough_madv_dontneed(start, end)) { + ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED)); + } + mmap_unlock(); + + return ret; +} -- cgit 1.4.1