mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
selftests/mm: confirm VA exhaustion without reliance on correctness of mmap()
Currently, VA exhaustion is being checked by passing a hint to mmap() and expecting it to fail. While populating the lower VA space, mmap() fails because we have exhausted the space. Then, in validate_lower_address_hint(), because mmap() fails, we confirm that we have indeed exhausted the space. There is a circular logic involved here. Assume that there is a bug in mmap(), also assume that it exists independent of whether you pass a hint address or not; that for some reason it is not able to find a 1GB chunk. My idea is to assert the exhaustion against some other method. This patch makes a stricter test by successful write() calls from /proc/self/maps to a dump file, confirming that a free chunk is indeed not available. [dev.jain@arm.com: replace SZ_1GB with MAP_CHUNK_SIZE, tidy-up] Link: https://lkml.kernel.org/r/20240325042653.867055-1-dev.jain@arm.com Link: https://lkml.kernel.org/r/20240321103522.516097-1-dev.jain@arm.com Signed-off-by: Dev Jain <dev.jain@arm.com> Cc: Anshuman Khandual <anshuman.khandual@arm.com> Cc: Shuah Khan <shuah@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
42a346b41c
commit
0104096498
@ -12,6 +12,8 @@
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
/*
|
||||
@ -93,6 +95,66 @@ static int validate_lower_address_hint(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int validate_complete_va_space(void)
|
||||
{
|
||||
unsigned long start_addr, end_addr, prev_end_addr;
|
||||
char line[400];
|
||||
char prot[6];
|
||||
FILE *file;
|
||||
int fd;
|
||||
|
||||
fd = open("va_dump", O_CREAT | O_WRONLY, 0600);
|
||||
unlink("va_dump");
|
||||
if (fd < 0) {
|
||||
ksft_test_result_skip("cannot create or open dump file\n");
|
||||
ksft_finished();
|
||||
}
|
||||
|
||||
file = fopen("/proc/self/maps", "r");
|
||||
if (file == NULL)
|
||||
ksft_exit_fail_msg("cannot open /proc/self/maps\n");
|
||||
|
||||
prev_end_addr = 0;
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
unsigned long hop;
|
||||
|
||||
if (sscanf(line, "%lx-%lx %s[rwxp-]",
|
||||
&start_addr, &end_addr, prot) != 3)
|
||||
ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
|
||||
|
||||
/* end of userspace mappings; ignore vsyscall mapping */
|
||||
if (start_addr & (1UL << 63))
|
||||
return 0;
|
||||
|
||||
/* /proc/self/maps must have gaps less than MAP_CHUNK_SIZE */
|
||||
if (start_addr - prev_end_addr >= MAP_CHUNK_SIZE)
|
||||
return 1;
|
||||
|
||||
prev_end_addr = end_addr;
|
||||
|
||||
if (prot[0] != 'r')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Confirm whether MAP_CHUNK_SIZE chunk can be found or not.
|
||||
* If write succeeds, no need to check MAP_CHUNK_SIZE - 1
|
||||
* addresses after that. If the address was not held by this
|
||||
* process, write would fail with errno set to EFAULT.
|
||||
* Anyways, if write returns anything apart from 1, exit the
|
||||
* program since that would mean a bug in /proc/self/maps.
|
||||
*/
|
||||
hop = 0;
|
||||
while (start_addr + hop < end_addr) {
|
||||
if (write(fd, (void *)(start_addr + hop), 1) != 1)
|
||||
return 1;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
hop += MAP_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *ptr[NR_CHUNKS_LOW];
|
||||
@ -133,6 +195,10 @@ int main(int argc, char *argv[])
|
||||
validate_addr(hptr[i], 1);
|
||||
}
|
||||
hchunks = i;
|
||||
if (validate_complete_va_space()) {
|
||||
ksft_test_result_fail("BUG in mmap() or /proc/self/maps\n");
|
||||
ksft_finished();
|
||||
}
|
||||
|
||||
for (i = 0; i < lchunks; i++)
|
||||
munmap(ptr[i], MAP_CHUNK_SIZE);
|
||||
|
Loading…
Reference in New Issue
Block a user