From owner-svn-src-head@freebsd.org Wed Jan 4 16:10:53 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 6651AC9E7DF; Wed, 4 Jan 2017 16:10:53 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4102C18C8; Wed, 4 Jan 2017 16:10:53 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v04GAqtd068860; Wed, 4 Jan 2017 16:10:52 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v04GAq8n068859; Wed, 4 Jan 2017 16:10:52 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201701041610.v04GAq8n068859@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 4 Jan 2017 16:10:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r311287 - head/lib/libc/x86/sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Jan 2017 16:10:53 -0000 Author: kib Date: Wed Jan 4 16:10:52 2017 New Revision: 311287 URL: https://svnweb.freebsd.org/changeset/base/311287 Log: __vdso_gettc(): be extra careful with /dev/hpet mappings, never unmap the mapping which might be accessed by other threads. If a pointer to the /dev/hpet register page mapping was stored into the hpet_dev_map, other threads might access the page at any time. Never unmap it, instead, keep track of mappings for all hpet units in smal array. Store pointer to the newly mapped registers page using CAS, to detect parallel mappings. It appeared relatively easy to demonstrate the problem by arranging two threads which perform gettimeofday(2) concurently, first time in the process address space, when HPET is used for timecounter. PR: 215715 Sponsored by: The FreeBSD Foundation MFC after: 1 week Modified: head/lib/libc/x86/sys/__vdso_gettc.c Modified: head/lib/libc/x86/sys/__vdso_gettc.c ============================================================================== --- head/lib/libc/x86/sys/__vdso_gettc.c Wed Jan 4 16:09:45 2017 (r311286) +++ head/lib/libc/x86/sys/__vdso_gettc.c Wed Jan 4 16:10:52 2017 (r311287) @@ -1,6 +1,6 @@ /*- * Copyright (c) 2012 Konstantin Belousov - * Copyright (c) 2016 The FreeBSD Foundation + * Copyright (c) 2016, 2017 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by Konstantin Belousov @@ -42,11 +42,11 @@ __FBSDID("$FreeBSD$"); #include #include #include "un-namespace.h" +#include #include #include #include #ifdef __amd64__ -#include #include #endif #include "libc_private.h" @@ -115,37 +115,47 @@ __vdso_rdtsc32(void) return (rdtsc32()); } -static char *hpet_dev_map = NULL; -static uint32_t hpet_idx = 0xffffffff; +#define HPET_DEV_MAP_MAX 10 +static volatile char *hpet_dev_map[HPET_DEV_MAP_MAX]; static void __vdso_init_hpet(uint32_t u) { static const char devprefix[] = "/dev/hpet"; char devname[64], *c, *c1, t; + volatile char *new_map, *old_map; + uint32_t u1; int fd; c1 = c = stpcpy(devname, devprefix); - u = hpet_idx; + u1 = u; do { - *c++ = u % 10 + '0'; - u /= 10; - } while (u != 0); + *c++ = u1 % 10 + '0'; + u1 /= 10; + } while (u1 != 0); *c = '\0'; for (c--; c1 != c; c1++, c--) { t = *c1; *c1 = *c; *c = t; } + + old_map = hpet_dev_map[u]; + if (old_map != NULL) + return; + fd = _open(devname, O_RDONLY); if (fd == -1) { - hpet_dev_map = MAP_FAILED; + atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u], + (uintptr_t)old_map, (uintptr_t)MAP_FAILED); return; } - if (hpet_dev_map != NULL && hpet_dev_map != MAP_FAILED) - munmap(hpet_dev_map, PAGE_SIZE); - hpet_dev_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); + new_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); _close(fd); + if (atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u], + (uintptr_t)old_map, (uintptr_t)new_map) == 0 && + new_map != MAP_FAILED) + munmap((void *)new_map, PAGE_SIZE); } #ifdef __amd64__ @@ -213,7 +223,8 @@ __vdso_hyperv_tsc(struct hyperv_reftsc * int __vdso_gettc(const struct vdso_timehands *th, u_int *tc) { - uint32_t tmp; + volatile char *map; + uint32_t idx; switch (th->th_algo) { case VDSO_TH_ALGO_X86_TSC: @@ -221,14 +232,19 @@ __vdso_gettc(const struct vdso_timehands __vdso_rdtsc32(); return (0); case VDSO_TH_ALGO_X86_HPET: - tmp = th->th_x86_hpet_idx; - if (hpet_dev_map == NULL || tmp != hpet_idx) { - hpet_idx = tmp; - __vdso_init_hpet(hpet_idx); + idx = th->th_x86_hpet_idx; + if (idx >= HPET_DEV_MAP_MAX) + return (ENOSYS); + map = (volatile char *)atomic_load_acq_ptr( + (volatile uintptr_t *)&hpet_dev_map[idx]); + if (map == NULL) { + __vdso_init_hpet(idx); + map = (volatile char *)atomic_load_acq_ptr( + (volatile uintptr_t *)&hpet_dev_map[idx]); } - if (hpet_dev_map == MAP_FAILED) + if (map == MAP_FAILED) return (ENOSYS); - *tc = *(volatile uint32_t *)(hpet_dev_map + HPET_MAIN_COUNTER); + *tc = *(volatile uint32_t *)(map + HPET_MAIN_COUNTER); return (0); #ifdef __amd64__ case VDSO_TH_ALGO_X86_HVTSC: