gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/hostmm/membarrier.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hostmm 16 17 import ( 18 "golang.org/x/sys/unix" 19 "gvisor.dev/gvisor/pkg/abi/linux" 20 "gvisor.dev/gvisor/pkg/log" 21 ) 22 23 var ( 24 haveMembarrierGlobal = false 25 haveMembarrierPrivateExpedited = false 26 ) 27 28 func init() { 29 supported, _, e := unix.RawSyscall(unix.SYS_MEMBARRIER, linux.MEMBARRIER_CMD_QUERY, 0 /* flags */, 0 /* unused */) 30 if e != 0 { 31 if e != unix.ENOSYS { 32 log.Warningf("membarrier(MEMBARRIER_CMD_QUERY) failed: %s", e.Error()) 33 } 34 return 35 } 36 // We don't use MEMBARRIER_CMD_GLOBAL_EXPEDITED because this sends IPIs to 37 // all CPUs running tasks that have previously invoked 38 // MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, which presents a DOS risk. 39 // (MEMBARRIER_CMD_GLOBAL is synchronize_rcu(), i.e. it waits for an RCU 40 // grace period to elapse without bothering other CPUs. 41 // MEMBARRIER_CMD_PRIVATE_EXPEDITED sends IPIs only to CPUs running tasks 42 // sharing the caller's MM.) 43 if supported&linux.MEMBARRIER_CMD_GLOBAL != 0 { 44 haveMembarrierGlobal = true 45 } 46 if req := uintptr(linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED | linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED); supported&req == req { 47 if _, _, e := unix.RawSyscall(unix.SYS_MEMBARRIER, linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0 /* flags */, 0 /* unused */); e != 0 { 48 log.Warningf("membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED) failed: %s", e.Error()) 49 } else { 50 haveMembarrierPrivateExpedited = true 51 } 52 } 53 } 54 55 // HaveGlobalMemoryBarrier returns true if GlobalMemoryBarrier is supported. 56 func HaveGlobalMemoryBarrier() bool { 57 return haveMembarrierGlobal 58 } 59 60 // GlobalMemoryBarrier blocks until "all running threads [in the host OS] have 61 // passed through a state where all memory accesses to user-space addresses 62 // match program order between entry to and return from [GlobalMemoryBarrier]", 63 // as for membarrier(2). 64 // 65 // Preconditions: HaveGlobalMemoryBarrier() == true. 66 func GlobalMemoryBarrier() error { 67 if _, _, e := unix.Syscall(unix.SYS_MEMBARRIER, linux.MEMBARRIER_CMD_GLOBAL, 0 /* flags */, 0 /* unused */); e != 0 { 68 return e 69 } 70 return nil 71 } 72 73 // HaveProcessMemoryBarrier returns true if ProcessMemoryBarrier is supported. 74 func HaveProcessMemoryBarrier() bool { 75 return haveMembarrierPrivateExpedited 76 } 77 78 // ProcessMemoryBarrier is equivalent to GlobalMemoryBarrier, but only 79 // synchronizes with threads sharing a virtual address space (from the host OS' 80 // perspective) with the calling thread. 81 // 82 // Preconditions: HaveProcessMemoryBarrier() == true. 83 func ProcessMemoryBarrier() error { 84 if _, _, e := unix.RawSyscall(unix.SYS_MEMBARRIER, linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0 /* flags */, 0 /* unused */); e != 0 { 85 return e 86 } 87 return nil 88 }