1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2015 Yi Zhang <wetpzy@gmail.com> 4f08c3bdfSopenharmony_ci * Li Wang <liwang@redhat.com> 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * DESCRIPTION: 7f08c3bdfSopenharmony_ci * 8f08c3bdfSopenharmony_ci * It is a regression test for commit: 9f08c3bdfSopenharmony_ci * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ 10f08c3bdfSopenharmony_ci * commit/?id=13d60f4 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * The implementation of futex doesn't produce unique keys for futexes 13f08c3bdfSopenharmony_ci * in shared huge pages, so threads waiting on different futexes may 14f08c3bdfSopenharmony_ci * end up on the same wait list. This results in incorrect threads being 15f08c3bdfSopenharmony_ci * woken by FUTEX_WAKE. 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * Needs to be run as root unless there are already enough huge pages available. 18f08c3bdfSopenharmony_ci * In the fail case, which happens in the CentOS-6.6 kernel (2.6.32-504.8.1), 19f08c3bdfSopenharmony_ci * the tests hangs until it times out after a 30-second wait. 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci */ 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci#include <stdio.h> 24f08c3bdfSopenharmony_ci#include <fcntl.h> 25f08c3bdfSopenharmony_ci#include <sys/time.h> 26f08c3bdfSopenharmony_ci#include <string.h> 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#include "futextest.h" 29f08c3bdfSopenharmony_ci#include "futex_utils.h" 30f08c3bdfSopenharmony_ci#include "lapi/mmap.h" 31f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 32f08c3bdfSopenharmony_ci#include "tst_safe_pthread.h" 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic futex_t *futex1, *futex2; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistatic struct tst_ts to; 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic struct futex_test_variants variants[] = { 39f08c3bdfSopenharmony_ci#if (__NR_futex != __LTP__NR_INVALID_SYSCALL) 40f08c3bdfSopenharmony_ci { .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 41f08c3bdfSopenharmony_ci#endif 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL) 44f08c3bdfSopenharmony_ci { .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 45f08c3bdfSopenharmony_ci#endif 46f08c3bdfSopenharmony_ci}; 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_cistatic void setup(void) 49f08c3bdfSopenharmony_ci{ 50f08c3bdfSopenharmony_ci struct futex_test_variants *tv = &variants[tst_variant]; 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing variant: %s", tv->desc); 53f08c3bdfSopenharmony_ci futex_supported_by_kernel(tv->fntype); 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci to = tst_ts_from_ns(tv->tstype, 30 * NSEC_PER_SEC); 56f08c3bdfSopenharmony_ci} 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_cistatic void *wait_thread1(void *arg LTP_ATTRIBUTE_UNUSED) 59f08c3bdfSopenharmony_ci{ 60f08c3bdfSopenharmony_ci struct futex_test_variants *tv = &variants[tst_variant]; 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci futex_wait(tv->fntype, futex1, *futex1, &to, 0); 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci return NULL; 65f08c3bdfSopenharmony_ci} 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic void *wait_thread2(void *arg LTP_ATTRIBUTE_UNUSED) 68f08c3bdfSopenharmony_ci{ 69f08c3bdfSopenharmony_ci struct futex_test_variants *tv = &variants[tst_variant]; 70f08c3bdfSopenharmony_ci int res; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci errno = 0; 73f08c3bdfSopenharmony_ci res = futex_wait(tv->fntype, futex2, *futex2, &to, 0); 74f08c3bdfSopenharmony_ci if (!res) 75f08c3bdfSopenharmony_ci tst_res(TPASS, "Hi hydra, thread2 awake!"); 76f08c3bdfSopenharmony_ci else 77f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "Bug: wait_thread2 did not wake after 30 secs."); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci return NULL; 80f08c3bdfSopenharmony_ci} 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_cistatic void wakeup_thread2(void) 83f08c3bdfSopenharmony_ci{ 84f08c3bdfSopenharmony_ci struct futex_test_variants *tv = &variants[tst_variant]; 85f08c3bdfSopenharmony_ci void *addr; 86f08c3bdfSopenharmony_ci int hpsz, pgsz; 87f08c3bdfSopenharmony_ci pthread_t th1, th2; 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci hpsz = tst_get_hugepage_size(); 90f08c3bdfSopenharmony_ci tst_res(TINFO, "Hugepagesize %i", hpsz); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci /*allocate some shared memory*/ 93f08c3bdfSopenharmony_ci addr = mmap(NULL, hpsz, PROT_WRITE | PROT_READ, 94f08c3bdfSopenharmony_ci MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci if (addr == MAP_FAILED) { 97f08c3bdfSopenharmony_ci if (errno == ENOMEM) 98f08c3bdfSopenharmony_ci tst_brk(TCONF, "Cannot allocate hugepage, memory too fragmented?"); 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "Cannot allocate hugepage"); 101f08c3bdfSopenharmony_ci } 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci pgsz = getpagesize(); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci /*apply the first subpage to futex1*/ 106f08c3bdfSopenharmony_ci futex1 = addr; 107f08c3bdfSopenharmony_ci *futex1 = 0; 108f08c3bdfSopenharmony_ci /*apply the second subpage to futex2*/ 109f08c3bdfSopenharmony_ci futex2 = (futex_t *)((char *)addr + pgsz); 110f08c3bdfSopenharmony_ci *futex2 = 0; 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci /*thread1 block on futex1 first,then thread2 block on futex2*/ 113f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(&th1, NULL, wait_thread1, NULL); 114f08c3bdfSopenharmony_ci SAFE_PTHREAD_CREATE(&th2, NULL, wait_thread2, NULL); 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci while (wait_for_threads(2)) 117f08c3bdfSopenharmony_ci usleep(1000); 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci futex_wake(tv->fntype, futex2, 1, 0); 120f08c3bdfSopenharmony_ci SAFE_PTHREAD_JOIN(th2, NULL); 121f08c3bdfSopenharmony_ci futex_wake(tv->fntype, futex1, 1, 0); 122f08c3bdfSopenharmony_ci SAFE_PTHREAD_JOIN(th1, NULL); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci SAFE_MUNMAP(addr, hpsz); 125f08c3bdfSopenharmony_ci} 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_cistatic struct tst_test test = { 128f08c3bdfSopenharmony_ci .setup = setup, 129f08c3bdfSopenharmony_ci .test_all = wakeup_thread2, 130f08c3bdfSopenharmony_ci .test_variants = ARRAY_SIZE(variants), 131f08c3bdfSopenharmony_ci .needs_root = 1, 132f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 133f08c3bdfSopenharmony_ci .hugepages = {1, TST_NEEDS}, 134f08c3bdfSopenharmony_ci}; 135