svn commit: r311927 - stable/11/lib/libc/x86/sys

Konstantin Belousov kib at FreeBSD.org
Wed Jan 11 11:25:19 UTC 2017


Author: kib
Date: Wed Jan 11 11:25:18 2017
New Revision: 311927
URL: https://svnweb.freebsd.org/changeset/base/311927

Log:
  MFC r311287:
  __vdso_gettc(): be extra careful with /dev/hpet mappings, never unmap
  the mapping which might be accessed by other threads.

Modified:
  stable/11/lib/libc/x86/sys/__vdso_gettc.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/lib/libc/x86/sys/__vdso_gettc.c
==============================================================================
--- stable/11/lib/libc/x86/sys/__vdso_gettc.c	Wed Jan 11 10:20:35 2017	(r311926)
+++ stable/11/lib/libc/x86/sys/__vdso_gettc.c	Wed Jan 11 11:25:18 2017	(r311927)
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2012 Konstantin Belousov <kib at FreeBSD.org>
- * 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 <string.h>
 #include <unistd.h>
 #include "un-namespace.h"
+#include <machine/atomic.h>
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
 #include <dev/acpica/acpi_hpet.h>
 #ifdef __amd64__
-#include <machine/atomic.h>
 #include <dev/hyperv/hyperv.h>
 #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:


More information about the svn-src-stable mailing list