1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2023 SUSE LLC 4 * Author: Vlastimil Babka <vbabka@suse.cz> 5 * https://bugzilla.suse.com/attachment.cgi?id=867254 6 * LTP port: Petr Vorel <pvorel@suse.cz> 7 */ 8 9/*\ 10 * [Description] 11 * 12 * Bug reproducer for 7e7757876f25 ("mm/mremap: fix vm_pgoff in vma_merge() case 3") 13 */ 14 15#define _GNU_SOURCE 16#include <unistd.h> 17#include <stdlib.h> 18#include <stdio.h> 19#include <fcntl.h> 20#include <sys/mman.h> 21 22#include "tst_test.h" 23#include "tst_safe_macros.h" 24 25#define NUM_PAGES 3 26 27static int fd; 28static char *buf, *buf2; 29static int page_size, mmap_size, mremap_size; 30 31static struct tcase { 32 size_t incompatible; 33 const char *desc; 34} tcases[] = { 35 { 36 .desc = "all pages with compatible mapping", 37 }, 38 { 39 .incompatible = 3, 40 .desc = "third page's mapping incompatible", 41 }, 42 { 43 .incompatible = 1, 44 .desc = "first page's mapping incompatible", 45 }, 46}; 47 48static int check_pages(void) 49{ 50 int fail = 0, i; 51 char val; 52 53 for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { 54 val = buf[i * page_size]; 55 if (val != 0x30 + i) { 56 tst_res(TFAIL, "page %d wrong value %d (0x%x)", i, val - 0x30, val); 57 fail = 1; 58 } 59 } 60 61 return fail; 62} 63 64static void do_test(unsigned int n) 65{ 66 struct tcase *tc = &tcases[n]; 67 int ret; 68 69 tst_res(TINFO, "%s", tc->desc); 70 71 buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 72 73 buf2 = mremap(buf + page_size, page_size, page_size, 74 MREMAP_MAYMOVE|MREMAP_FIXED, buf + mremap_size); 75 if (buf2 == MAP_FAILED) 76 tst_brk(TBROK, "mremap() failed"); 77 78 if (tc->incompatible) { 79 ret = mprotect(buf + (tc->incompatible-1)*page_size, page_size, PROT_READ); 80 if (ret == -1) 81 tst_brk(TBROK, "mprotect() failed"); 82 } 83 84 buf2 = mremap(buf + mremap_size, page_size, page_size, 85 MREMAP_MAYMOVE|MREMAP_FIXED, buf + page_size); 86 if (buf2 == MAP_FAILED) 87 tst_brk(TBROK, "mremap() failed"); 88 89 if (!check_pages()) 90 tst_res(TPASS, "mmap/mremap work properly"); 91 92 SAFE_MUNMAP(buf, mremap_size); 93} 94 95static void setup(void) 96{ 97 int ret, i; 98 99 page_size = getpagesize(); 100 mmap_size = (NUM_PAGES+1) * page_size; 101 mremap_size = NUM_PAGES * page_size; 102 103 fd = SAFE_OPEN("testfile", O_CREAT | O_RDWR | O_TRUNC, 0600); 104 105 ret = fallocate(fd, 0, 0, mmap_size); 106 if (ret == -1) 107 tst_brk(TBROK, "fallocate() failed"); 108 109 buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 110 111 for (i = 0; i < (int)ARRAY_SIZE(tcases)+1; i++) 112 buf[i*page_size] = 0x30 + i; 113 114 /* clear the page tables */ 115 SAFE_MUNMAP(buf, mmap_size); 116} 117 118static void cleanup(void) 119{ 120 if (fd > 0) 121 SAFE_CLOSE(fd); 122} 123 124static struct tst_test test = { 125 .setup = setup, 126 .cleanup = cleanup, 127 .test = do_test, 128 .needs_tmpdir = 1, 129 .tcnt = ARRAY_SIZE(tcases), 130 .tags = (struct tst_tag[]) { 131 {"linux-git", "7e7757876f25"}, 132 {} 133 }, 134}; 135