qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: joel@jms.id.au, akihiko.odaki@daynix.com, laurent@vivier.eu,
	deller@gmx.de
Subject: [PATCH v8 06/17] linux-user: Do not align brk with host page size
Date: Thu,  3 Aug 2023 18:45:06 -0700	[thread overview]
Message-ID: <20230804014517.6361-7-richard.henderson@linaro.org> (raw)
In-Reply-To: <20230804014517.6361-1-richard.henderson@linaro.org>

From: Akihiko Odaki <akihiko.odaki@daynix.com>

do_brk() minimizes calls into target_mmap() by aligning the address
with host page size, which is potentially larger than the target page
size. However, the current implementation of this optimization has two
bugs:

- The start of brk is rounded up with the host page size while brk
  advertises an address aligned with the target page size as the
  beginning of brk. This makes the beginning of brk unmapped.
- Content clearing after mapping is flawed. The size to clear is
  specified as HOST_PAGE_ALIGN(brk_page) - brk_page, but brk_page is
  aligned with the host page size so it is always zero.

This optimization actually has no practical benefit. It makes difference
when brk() is called multiple times with values in a range of the host
page size. However, sophisticated memory allocators try to avoid to
make such frequent brk() calls. For example, glibc 2.37 calls brk() to
shrink the heap only when there is a room more than 128 KiB. It is
rare to have a page size larger than 128 KiB if it happens.

Let's remove the optimization to fix the bugs and make the code simpler.

Fixes: 86f04735ac ("linux-user: Fix brk() to release pages")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1616
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20230802071754.14876-7-akihiko.odaki@daynix.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/elfload.c |  4 ++--
 linux-user/syscall.c | 54 ++++++++++----------------------------------
 2 files changed, 14 insertions(+), 44 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 861ec07abc..2aee2298ec 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -3678,8 +3678,8 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
      * to mmap pages in this space.
      */
     if (info->reserve_brk) {
-        abi_ulong start_brk = HOST_PAGE_ALIGN(info->brk);
-        abi_ulong end_brk = HOST_PAGE_ALIGN(info->brk + info->reserve_brk);
+        abi_ulong start_brk = TARGET_PAGE_ALIGN(info->brk);
+        abi_ulong end_brk = TARGET_PAGE_ALIGN(info->brk + info->reserve_brk);
         target_munmap(start_brk, end_brk - start_brk);
     }
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e1436a3962..7c2c2f6e2f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -802,81 +802,51 @@ static inline int host_to_target_sock_type(int host_type)
 }
 
 static abi_ulong target_brk, initial_target_brk;
-static abi_ulong brk_page;
 
 void target_set_brk(abi_ulong new_brk)
 {
     target_brk = TARGET_PAGE_ALIGN(new_brk);
     initial_target_brk = target_brk;
-    brk_page = HOST_PAGE_ALIGN(target_brk);
 }
 
 /* do_brk() must return target values and target errnos. */
 abi_long do_brk(abi_ulong brk_val)
 {
     abi_long mapped_addr;
-    abi_ulong new_alloc_size;
-    abi_ulong new_brk, new_host_brk_page;
+    abi_ulong new_brk;
+    abi_ulong old_brk;
 
     /* brk pointers are always untagged */
 
-    /* return old brk value if brk_val unchanged */
-    if (brk_val == target_brk) {
-        return target_brk;
-    }
-
     /* do not allow to shrink below initial brk value */
     if (brk_val < initial_target_brk) {
         return target_brk;
     }
 
     new_brk = TARGET_PAGE_ALIGN(brk_val);
-    new_host_brk_page = HOST_PAGE_ALIGN(brk_val);
+    old_brk = TARGET_PAGE_ALIGN(target_brk);
 
-    /* brk_val and old target_brk might be on the same page */
-    if (new_brk == TARGET_PAGE_ALIGN(target_brk)) {
-        /* empty remaining bytes in (possibly larger) host page */
-        memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk);
+    /* new and old target_brk might be on the same page */
+    if (new_brk == old_brk) {
         target_brk = brk_val;
         return target_brk;
     }
 
     /* Release heap if necesary */
-    if (new_brk < target_brk) {
-        /* empty remaining bytes in (possibly larger) host page */
-        memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk);
-
-        /* free unused host pages and set new brk_page */
-        target_munmap(new_host_brk_page, brk_page - new_host_brk_page);
-        brk_page = new_host_brk_page;
+    if (new_brk < old_brk) {
+        target_munmap(new_brk, old_brk - new_brk);
 
         target_brk = brk_val;
         return target_brk;
     }
 
-    if (new_host_brk_page > brk_page) {
-        new_alloc_size = new_host_brk_page - brk_page;
-        mapped_addr = target_mmap(brk_page, new_alloc_size,
-                                  PROT_READ | PROT_WRITE,
-                                  MAP_FIXED_NOREPLACE | MAP_ANON | MAP_PRIVATE,
-                                  -1, 0);
-    } else {
-        new_alloc_size = 0;
-        mapped_addr = brk_page;
-    }
-
-    if (mapped_addr == brk_page) {
-        /* Heap contents are initialized to zero, as for anonymous
-         * mapped pages.  Technically the new pages are already
-         * initialized to zero since they *are* anonymous mapped
-         * pages, however we have to take care with the contents that
-         * come from the remaining part of the previous page: it may
-         * contains garbage data due to a previous heap usage (grown
-         * then shrunken).  */
-        memset(g2h_untagged(brk_page), 0, HOST_PAGE_ALIGN(brk_page) - brk_page);
+    mapped_addr = target_mmap(old_brk, new_brk - old_brk,
+                              PROT_READ | PROT_WRITE,
+                              MAP_FIXED_NOREPLACE | MAP_ANON | MAP_PRIVATE,
+                              -1, 0);
 
+    if (mapped_addr == old_brk) {
         target_brk = brk_val;
-        brk_page = new_host_brk_page;
         return target_brk;
     }
 
-- 
2.34.1



  parent reply	other threads:[~2023-08-04  1:47 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-04  1:45 [PATCH for-8.1 v8 00/17] linux-user: brk fixes Richard Henderson
2023-08-04  1:45 ` [PATCH v8 01/17] linux-user: Unset MAP_FIXED_NOREPLACE for host Richard Henderson
2023-08-04  1:45 ` [PATCH v8 02/17] linux-user: Fix MAP_FIXED_NOREPLACE on old kernels Richard Henderson
2023-08-04  1:45 ` [PATCH v8 03/17] linux-user: Do not call get_errno() in do_brk() Richard Henderson
2023-08-04  1:45 ` [PATCH v8 04/17] linux-user: Use MAP_FIXED_NOREPLACE for do_brk() Richard Henderson
2023-08-04  1:45 ` [PATCH v8 05/17] linux-user: Do nothing if too small brk is specified Richard Henderson
2023-08-04  1:45 ` Richard Henderson [this message]
2023-08-04  1:45 ` [PATCH v8 07/17] linux-user: Remove last_brk Richard Henderson
2023-08-04  5:09   ` Akihiko Odaki
2023-08-04  8:51   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 08/17] linux-user: Adjust task_unmapped_base for reserved_va Richard Henderson
2023-08-04  5:14   ` Akihiko Odaki
2023-08-04  1:45 ` [PATCH v8 09/17] linux-user: Define TASK_UNMAPPED_BASE in $guest/target_mman.h Richard Henderson
2023-08-04  5:17   ` Akihiko Odaki
2023-08-04 10:17   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 10/17] linux-user: Define ELF_ET_DYN_BASE " Richard Henderson
2023-08-04  5:20   ` Akihiko Odaki
2023-08-04 14:09     ` Richard Henderson
2023-08-04  9:50   ` Helge Deller
2023-08-04 14:09     ` Richard Henderson
2023-08-04  1:45 ` [PATCH v8 11/17] linux-user: Use MAP_FIXED_NOREPLACE for initial image mmap Richard Henderson
2023-08-04  5:22   ` Akihiko Odaki
2023-08-04 10:18   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 12/17] linux-user: Use elf_et_dyn_base for ET_DYN with interpreter Richard Henderson
2023-08-04  5:24   ` Akihiko Odaki
2023-08-04 10:20   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 13/17] linux-user: Adjust initial brk when interpreter is close to executable Richard Henderson
2023-08-04  5:26   ` Akihiko Odaki
2023-08-04  1:45 ` [PATCH v8 14/17] linux-user: Properly set image_info.brk in flatload Richard Henderson
2023-08-04  5:27   ` Akihiko Odaki
2023-08-04 10:22   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 15/17] linux-user: Do not adjust image mapping for host page size Richard Henderson
2023-08-04  5:28   ` Akihiko Odaki
2023-08-04 10:23   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 16/17] linux-user: Do not adjust zero_bss " Richard Henderson
2023-08-04  5:56   ` Akihiko Odaki
2023-08-04 10:24   ` Helge Deller
2023-08-04  1:45 ` [PATCH v8 17/17] linux-user: Use zero_bss for PT_LOAD with no file contents too Richard Henderson
2023-08-04  6:02   ` Akihiko Odaki
2023-08-04 10:25   ` Helge Deller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230804014517.6361-7-richard.henderson@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=akihiko.odaki@daynix.com \
    --cc=deller@gmx.de \
    --cc=joel@jms.id.au \
    --cc=laurent@vivier.eu \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).