Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools/testing/selftests/vm/: add MAP_POPULATE test

As with many other projects, we use some shmalloc allocator. At some
point we need to make a part of allocated pages back private to process.
And it should be populated straight away. Check that (MAP_PRIVATE |
MAP_POPULATE) actually copies the private page.

[akpm@linux-foundation.org: change message, per review discussion]
Link: http://lkml.kernel.org/r/20180801233636.29354-1-dima@arista.com
Signed-off-by: Dmitry Safonov <dima@arista.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Dmitry Safonov <0x7f454c46@gmail.com>
Cc: Hua Zhong <hzhong@arista.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Stuart Ritchie <sritchie@arista.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dmitry Safonov and committed by
Linus Torvalds
1caed860 03e85f9d

+126
+1
tools/testing/selftests/vm/.gitignore
··· 1 1 hugepage-mmap 2 2 hugepage-shm 3 3 map_hugetlb 4 + map_populate 4 5 thuge-gen 5 6 compaction_test 6 7 mlock2-tests
+1
tools/testing/selftests/vm/Makefile
··· 12 12 TEST_GEN_FILES += hugepage-mmap 13 13 TEST_GEN_FILES += hugepage-shm 14 14 TEST_GEN_FILES += map_hugetlb 15 + TEST_GEN_FILES += map_populate 15 16 TEST_GEN_FILES += mlock-random-test 16 17 TEST_GEN_FILES += mlock2-tests 17 18 TEST_GEN_FILES += on-fault-limit
+113
tools/testing/selftests/vm/map_populate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2018 Dmitry Safonov, Arista Networks 4 + * 5 + * MAP_POPULATE | MAP_PRIVATE should COW VMA pages. 6 + */ 7 + 8 + #define _GNU_SOURCE 9 + #include <errno.h> 10 + #include <fcntl.h> 11 + #include <sys/mman.h> 12 + #include <sys/socket.h> 13 + #include <sys/types.h> 14 + #include <sys/wait.h> 15 + #include <stdio.h> 16 + #include <stdlib.h> 17 + #include <string.h> 18 + #include <unistd.h> 19 + 20 + #ifndef MMAP_SZ 21 + #define MMAP_SZ 4096 22 + #endif 23 + 24 + #define BUG_ON(condition, description) \ 25 + do { \ 26 + if (condition) { \ 27 + fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \ 28 + __LINE__, (description), strerror(errno)); \ 29 + exit(1); \ 30 + } \ 31 + } while (0) 32 + 33 + static int parent_f(int sock, unsigned long *smap, int child) 34 + { 35 + int status, ret; 36 + 37 + ret = read(sock, &status, sizeof(int)); 38 + BUG_ON(ret <= 0, "read(sock)"); 39 + 40 + *smap = 0x22222BAD; 41 + ret = msync(smap, MMAP_SZ, MS_SYNC); 42 + BUG_ON(ret, "msync()"); 43 + 44 + ret = write(sock, &status, sizeof(int)); 45 + BUG_ON(ret <= 0, "write(sock)"); 46 + 47 + waitpid(child, &status, 0); 48 + BUG_ON(!WIFEXITED(status), "child in unexpected state"); 49 + 50 + return WEXITSTATUS(status); 51 + } 52 + 53 + static int child_f(int sock, unsigned long *smap, int fd) 54 + { 55 + int ret, buf = 0; 56 + 57 + smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 58 + MAP_PRIVATE | MAP_POPULATE, fd, 0); 59 + BUG_ON(smap == MAP_FAILED, "mmap()"); 60 + 61 + BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file"); 62 + 63 + ret = write(sock, &buf, sizeof(int)); 64 + BUG_ON(ret <= 0, "write(sock)"); 65 + 66 + ret = read(sock, &buf, sizeof(int)); 67 + BUG_ON(ret <= 0, "read(sock)"); 68 + 69 + BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page"); 70 + BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted"); 71 + 72 + return 0; 73 + } 74 + 75 + int main(int argc, char **argv) 76 + { 77 + int sock[2], child, ret; 78 + FILE *ftmp; 79 + unsigned long *smap; 80 + 81 + ftmp = tmpfile(); 82 + BUG_ON(ftmp == 0, "tmpfile()"); 83 + 84 + ret = ftruncate(fileno(ftmp), MMAP_SZ); 85 + BUG_ON(ret, "ftruncate()"); 86 + 87 + smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 88 + MAP_SHARED, fileno(ftmp), 0); 89 + BUG_ON(smap == MAP_FAILED, "mmap()"); 90 + 91 + *smap = 0xdeadbabe; 92 + /* Probably unnecessary, but let it be. */ 93 + ret = msync(smap, MMAP_SZ, MS_SYNC); 94 + BUG_ON(ret, "msync()"); 95 + 96 + ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock); 97 + BUG_ON(ret, "socketpair()"); 98 + 99 + child = fork(); 100 + BUG_ON(child == -1, "fork()"); 101 + 102 + if (child) { 103 + ret = close(sock[0]); 104 + BUG_ON(ret, "close()"); 105 + 106 + return parent_f(sock[1], smap, child); 107 + } 108 + 109 + ret = close(sock[1]); 110 + BUG_ON(ret, "close()"); 111 + 112 + return child_f(sock[0], smap, fileno(ftmp)); 113 + }
+11
tools/testing/selftests/vm/run_vmtests
··· 168 168 fi 169 169 170 170 echo "--------------------" 171 + echo "running map_populate" 172 + echo "--------------------" 173 + ./map_populate 174 + if [ $? -ne 0 ]; then 175 + echo "[FAIL]" 176 + exitcode=1 177 + else 178 + echo "[PASS]" 179 + fi 180 + 181 + echo "--------------------" 171 182 echo "running mlock2-tests" 172 183 echo "--------------------" 173 184 ./mlock2-tests