Skip to content

Commit 3682df1

Browse files
Mike Palligormunkin
authored andcommitted
Linux/ARM64: Make mremap() non-moving due to VA space woes.
This reduces overall performance on ARM64, but we have no choice. Linux kernel default userspace VA is 48 bit, but we'd need 47 bit. mremap() ignores address hints due to a kernel API issue. The mapping may move to an undesired address which will cause an assert or crash. Reported by Raymond W. Ko. (cherry picked from commit 67dbec8) 47-bit VA space is required by LuaJIT for keeping a GC object pointer in TValue. In case of huge blobs that are mapped directly, `mremap()` may move the chunk out of 47-bit range of VA space on ARM64. `mremap()` accepts the fifth argument (new address hint) only with MREMAP_FIXED flag. In that case it unmaps any other mapping to specified address. To avoid this behaviour this patch restricts `mremap()` to relocate the mapping to a new virtual address by setting CALL_MREMAP_NOMOVE flag instead of CALL_MREMAP_MAYMOVE for arm64 architecture. Sergey Kaplun: * added the description and the test for the problem Needed for tarantool/tarantool#6154 Part of tarantool/tarantool#5629 Reviewed-by: Igor Munkin <[email protected]> Reviewed-by: Sergey Ostanevich <[email protected]> Signed-off-by: Igor Munkin <[email protected]>
1 parent 2cacfa8 commit 3682df1

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

src/lj_alloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ static void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, int flags)
378378
#define CALL_MREMAP(addr, osz, nsz, mv) CALL_MREMAP_((addr), (osz), (nsz), (mv))
379379
#define CALL_MREMAP_NOMOVE 0
380380
#define CALL_MREMAP_MAYMOVE 1
381-
#if LJ_64 && !LJ_GC64
381+
#if LJ_64 && (!LJ_GC64 || LJ_TARGET_ARM64)
382382
#define CALL_MREMAP_MV CALL_MREMAP_NOMOVE
383383
#else
384384
#define CALL_MREMAP_MV CALL_MREMAP_MAYMOVE
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
local tap = require('tap')
2+
3+
-- Test file to demonstrate assertion after `mremap()` on arm64.
4+
-- See also, https://github.com/LuaJIT/LuaJIT/issues/671.
5+
6+
local test = tap.test('lj-671-arm64-assert-after-mremap')
7+
test:plan(1)
8+
9+
-- `mremap()` is used on Linux to remap directly mapped big
10+
-- (>=DEFAULT_MMAP_THRESHOLD) memory chunks.
11+
-- The simplest way to test memory move is to allocate the huge
12+
-- memory chunk for string buffer directly and reallocate it
13+
-- after.
14+
-- To allocate a memory buffer with the size up to the threshold
15+
-- for direct mapping `string.rep()` is used with the length that
16+
-- equals to DEFAULT_MMAP_THRESHOLD.
17+
-- Then concatenate the directly mapped result string with the
18+
-- other one to trigger buffer reallocation and its remapping.
19+
20+
local DEFAULT_MMAP_THRESHOLD = 128 * 1024
21+
local s = string.rep('x', DEFAULT_MMAP_THRESHOLD)..'x'
22+
test:ok(s)
23+
24+
os.exit(test:check() and 0 or 1)

0 commit comments

Comments
 (0)