* [PATCH 1/2] linux-user: return ENOMEM from madvise on unmapped ranges
2026-08-31 21:20 [PATCH 0/2] linux-user: return ENOMEM from madvise on unmapped ranges Roi Klevansky
@ 2026-08-31 21:20 ` Roi Klevansky
2026-08-31 21:20 ` [PATCH 2/2] tests/tcg: add linux-user test for madvise returning ENOMEM Roi Klevansky
1 sibling, 0 replies; 3+ messages in thread
From: Roi Klevansky @ 2026-08-31 21:20 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Roi Klevansky
The kernel fails with ENOMEM when madvise() is called with a partially
or fully unmapped address range. This fix allows target_madvise() to
emulate this behavior by calling page_check_range() upfront while still
allowing advice specific errors to take precedence.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4382
Signed-off-by: Roi Klevansky <roiklevansky@gmail.com>
---
linux-user/mmap.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index cc0c2ee6c2..e5195cf501 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -1305,8 +1305,14 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
* success, which is broken but some userspace programs fail to work
* otherwise. Completely implementing such emulation is quite complicated
* though.
+ *
+ * When some (or all) of the pages in the range are not mapped, madvise
+ * should fail with -ENOMEM. If another error occurs, its value is
+ * returned instead.
*/
mmap_lock();
+ ret = page_check_range(start, len, PAGE_VALID) ? 0 : -TARGET_ENOMEM;
+
switch (advice) {
case MADV_NORMAL:
case MADV_RANDOM:
@@ -1316,7 +1322,6 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
case MADV_FREE:
case MADV_COLD:
case MADV_PAGEOUT:
- ret = 0; /* OK */
break;
case MADV_REMOVE:
ret = -EOPNOTSUPP;
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 2/2] tests/tcg: add linux-user test for madvise returning ENOMEM
2026-08-31 21:20 [PATCH 0/2] linux-user: return ENOMEM from madvise on unmapped ranges Roi Klevansky
2026-08-31 21:20 ` [PATCH 1/2] " Roi Klevansky
@ 2026-08-31 21:20 ` Roi Klevansky
1 sibling, 0 replies; 3+ messages in thread
From: Roi Klevansky @ 2026-08-31 21:20 UTC (permalink / raw)
To: qemu-devel
Cc: Alex Bennée, Laurent Vivier, Helge Deller, Pierrick Bouvier,
Roi Klevansky
Add tests for madvise() under linux-user with partially and fully
unmapped address ranges, making sure it returns ENOMEM, just like
the kernel does.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4382
Signed-off-by: Roi Klevansky <roiklevansky@gmail.com>
---
tests/tcg/multiarch/linux/linux-madvise.c | 43 +++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/tests/tcg/multiarch/linux/linux-madvise.c b/tests/tcg/multiarch/linux/linux-madvise.c
index 539fb3b772..b7a52abb6c 100644
--- a/tests/tcg/multiarch/linux/linux-madvise.c
+++ b/tests/tcg/multiarch/linux/linux-madvise.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
@@ -63,10 +64,52 @@ static void test_file(void)
assert(ret == 0);
}
+static void test_mapped_and_unmapped(void)
+{
+ int pagesize = getpagesize();
+ void *page;
+ int ret;
+
+ page = mmap(NULL, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ assert(page != MAP_FAILED);
+
+ ret = madvise(page, pagesize, MADV_NORMAL);
+ assert(ret == 0);
+
+ ret = munmap(page, pagesize);
+ assert(ret == 0);
+
+ ret = madvise(page, pagesize, MADV_NORMAL);
+ assert(ret == -1);
+ assert(errno == ENOMEM);
+}
+
+static void test_partially_unmapped_enomem(void)
+{
+ int pagesize = getpagesize();
+ void *page;
+ int ret;
+
+ page = mmap(NULL, 3 * pagesize, PROT_READ,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ assert(page != MAP_FAILED);
+ ret = munmap((char *)page + pagesize, pagesize);
+ assert(ret == 0);
+
+ ret = madvise(page, 3 * pagesize, MADV_NORMAL);
+ assert(ret == -1);
+ assert(errno == ENOMEM);
+
+ ret = munmap(page, 3 * pagesize);
+ assert(ret == 0);
+}
+
int main(void)
{
test_anonymous();
test_file();
+ test_mapped_and_unmapped();
+ test_partially_unmapped_enomem();
return EXIT_SUCCESS;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread