1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2015-2017 Red Hat, Inc. 4 * 5 * DESCRIPTION 6 * 7 * There is a race condition if we map a same file on different processes. 8 * Region tracking is protected by mmap_sem and hugetlb_instantiation_mutex. 9 * When we do mmap, we don't grab a hugetlb_instantiation_mutex, but only 10 * mmap_sem (exclusively). This doesn't prevent other tasks from modifying 11 * the region structure, so it can be modified by two processes concurrently. 12 * 13 * This bug was fixed on stable kernel by commits: 14 * f522c3ac00a4(mm, hugetlb: change variable name reservations to resv) 15 * 9119a41e9091(mm, hugetlb: unify region structure handling) 16 * 7b24d8616be3(mm, hugetlb: fix race in region tracking) 17 * 1406ec9ba6c6(mm, hugetlb: improve, cleanup resv_map parameters) 18 * 19 * AUTHOR: 20 * Herton R. Krzesinski <herton@redhat.com> 21 * Li Wang <liwang@redhat.com> 22 */ 23 24#define _GNU_SOURCE 25#include <pthread.h> 26#include <stdio.h> 27#include "hugetlb.h" 28#include "lapi/mmap.h" 29 30static long hpage_size; 31 32struct mp { 33 char *addr; 34 int sz; 35}; 36 37#define ARSZ 50 38#define LOOP 5 39 40static void setup(void) 41{ 42 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; 43} 44 45static void *thr(void *arg) 46{ 47 struct mp *mmap_sz = arg; 48 int i, lim, a, b, c; 49 50 srand(time(NULL)); 51 lim = rand() % 10; 52 for (i = 0; i < lim; i++) { 53 a = rand() % mmap_sz->sz; 54 for (c = 0; c <= a; c++) { 55 b = rand() % mmap_sz->sz; 56 *(mmap_sz->addr + b * hpage_size) = rand(); 57 } 58 } 59 return NULL; 60} 61 62static void do_mmap(unsigned int j LTP_ATTRIBUTE_UNUSED) 63{ 64 int i, sz = ARSZ + 1; 65 void *addr, *new_addr; 66 struct mp mmap_sz[ARSZ]; 67 pthread_t tid[ARSZ]; 68 69 addr = mmap(NULL, sz * hpage_size, 70 PROT_READ | PROT_WRITE, 71 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 72 -1, 0); 73 74 if (addr == MAP_FAILED) { 75 if (errno == ENOMEM) { 76 tst_brk(TCONF, 77 "Cannot allocate hugepage, memory too fragmented?"); 78 } 79 80 tst_brk(TBROK | TERRNO, "Cannot allocate hugepage"); 81 } 82 83 for (i = 0; i < ARSZ; ++i, --sz) { 84 mmap_sz[i].sz = sz; 85 mmap_sz[i].addr = addr; 86 87 TEST(pthread_create(&tid[i], NULL, thr, &mmap_sz[i])); 88 if (TST_RET) 89 tst_brk(TBROK | TRERRNO, 90 "pthread_create failed"); 91 92 new_addr = mmap(addr, (sz - 1) * hpage_size, 93 PROT_READ | PROT_WRITE, 94 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED, 95 -1, 0); 96 97 if (new_addr == MAP_FAILED) 98 tst_brk(TFAIL | TERRNO, "mmap failed"); 99 100 addr = new_addr; 101 } 102 103 for (i = 0; i < ARSZ; ++i) { 104 TEST(pthread_join(tid[i], NULL)); 105 if (TST_RET) 106 tst_brk(TBROK | TRERRNO, 107 "pthread_join failed"); 108 } 109 110 if (munmap(addr, sz * hpage_size) == -1) 111 tst_brk(TFAIL | TERRNO, "huge munmap failed"); 112 113 tst_res(TPASS, "No regression found."); 114} 115 116static struct tst_test test = { 117 .needs_root = 1, 118 .tcnt = LOOP, 119 .needs_tmpdir = 1, 120 .test = do_mmap, 121 .setup = setup, 122 .hugepages = {(ARSZ + 1) * LOOP, TST_NEEDS}, 123 .tags = (const struct tst_tag[]) { 124 {"linux-git", "f522c3ac00a4"}, 125 {"linux-git", "9119a41e9091"}, 126 {"linux-git", "7b24d8616be3"}, 127 {"linux-git", "1406ec9ba6c6"}, 128 {} 129 } 130}; 131