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 <k...@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:
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to