mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Make hostarch.Page/HugePage/CacheLine* functions generic and canonical.
Also add the missing HugePage equivalents of Page functions. The fix for golang/go#56280, which first appears in Go 1.20, is needed to prevent this CL from regressing performance: Before fix: ``` TEXT gvisor/pkg/sentry/mm/mm.(*MemoryManager).SetNumaPolicy(SB) gvisor/pkg/sentry/mm/syscalls.go ... addr.go:75 0x7f000054e35e 488d053bc2b100 LEAQ gvisor/pkg/hostarch/hostarch..dict.IsPageAligned[gvisor/pkg/hostarch/hostarch.Addr](SB), AX addr.go:75 0x7f000054e365 e8961cc4ff CALL gvisor/pkg/hostarch/hostarch.IsPageAligned[go.shape.uintptr](SB) ``` After fix: ``` TEXT gvisor/pkg/sentry/mm/mm.(*MemoryManager).SetNumaPolicy(SB) gvisor/pkg/sentry/mm/syscalls.go ... addr.go:75 0x7f00004da61a 90 NOPL addr.go:75 0x7f00004da61b 0f1f440000 NOPL 0(AX)(AX*1) sizes_util.go:57 0x7f00004da620 48f7c3ff0f0000 TESTQ $0xfff, BX syscalls.go:1021 0x7f00004da627 0f855f010000 JNE 0x7f00004da78c ``` PiperOrigin-RevId: 507608080
This commit is contained in:
@@ -34,6 +34,7 @@ go_library(
|
||||
"hostarch.go",
|
||||
"hostarch_arm64.go",
|
||||
"hostarch_x86.go",
|
||||
"sizes_util.go",
|
||||
],
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
|
||||
+18
-69
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Addr represents a generic virtual address.
|
||||
// Addr represents an address in an unspecified address space.
|
||||
//
|
||||
// +stateify savable
|
||||
type Addr uintptr
|
||||
@@ -39,51 +39,40 @@ func (v Addr) AddLength(length uint64) (end Addr, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// RoundDown returns the address rounded down to the nearest page boundary.
|
||||
// RoundDown is equivalent to function PageRoundDown.
|
||||
func (v Addr) RoundDown() Addr {
|
||||
return v & ^Addr(PageSize-1)
|
||||
return PageRoundDown(v)
|
||||
}
|
||||
|
||||
// RoundUp returns the address rounded up to the nearest page boundary. ok is
|
||||
// true iff rounding up did not wrap around.
|
||||
func (v Addr) RoundUp() (addr Addr, ok bool) {
|
||||
addr = Addr(v + PageSize - 1).RoundDown()
|
||||
ok = addr >= v
|
||||
return
|
||||
// RoundUp is equivalent to function PageRoundUp.
|
||||
func (v Addr) RoundUp() (Addr, bool) {
|
||||
return PageRoundUp(v)
|
||||
}
|
||||
|
||||
// MustRoundUp is equivalent to RoundUp, but panics if rounding up wraps
|
||||
// around.
|
||||
// MustRoundUp is equivalent to function MustPageRoundUp.
|
||||
func (v Addr) MustRoundUp() Addr {
|
||||
addr, ok := v.RoundUp()
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("hostarch.Addr(%d).RoundUp() wraps", v))
|
||||
}
|
||||
return addr
|
||||
return MustPageRoundUp(v)
|
||||
}
|
||||
|
||||
// HugeRoundDown returns the address rounded down to the nearest huge page
|
||||
// boundary.
|
||||
// HugeRoundDown is equivalent to function HugePageRoundDown.
|
||||
func (v Addr) HugeRoundDown() Addr {
|
||||
return v & ^Addr(HugePageSize-1)
|
||||
return HugePageRoundDown(v)
|
||||
}
|
||||
|
||||
// HugeRoundUp returns the address rounded up to the nearest huge page boundary.
|
||||
// ok is true iff rounding up did not wrap around.
|
||||
func (v Addr) HugeRoundUp() (addr Addr, ok bool) {
|
||||
addr = Addr(v + HugePageSize - 1).HugeRoundDown()
|
||||
ok = addr >= v
|
||||
return
|
||||
// HugeRoundUp is equivalent to function HugePageRoundUp.
|
||||
func (v Addr) HugeRoundUp() (Addr, bool) {
|
||||
return HugePageRoundUp(v)
|
||||
}
|
||||
|
||||
// PageOffset returns the offset of v into the current page.
|
||||
// PageOffset is equivalent to function PageOffset, except that it casts the
|
||||
// result to uint64.
|
||||
func (v Addr) PageOffset() uint64 {
|
||||
return uint64(v & Addr(PageSize-1))
|
||||
return uint64(PageOffset(v))
|
||||
}
|
||||
|
||||
// IsPageAligned returns true if v.PageOffset() == 0.
|
||||
// IsPageAligned is equivalent to function IsPageAligned.
|
||||
func (v Addr) IsPageAligned() bool {
|
||||
return v.PageOffset() == 0
|
||||
return IsPageAligned(v)
|
||||
}
|
||||
|
||||
// AddrRange is a range of Addrs.
|
||||
@@ -106,43 +95,3 @@ func (ar AddrRange) IsPageAligned() bool {
|
||||
func (ar AddrRange) String() string {
|
||||
return fmt.Sprintf("[%#x, %#x)", ar.Start, ar.End)
|
||||
}
|
||||
|
||||
// PageRoundDown/Up are equivalent to Addr.RoundDown/Up, but without the
|
||||
// potentially truncating conversion from uint64 to Addr. This is necessary
|
||||
// because there is no way to define generic "PageRoundDown/Up" functions in Go.
|
||||
|
||||
// PageRoundDown returns x rounded down to the nearest page boundary.
|
||||
func PageRoundDown(x uint64) uint64 {
|
||||
return x &^ (PageSize - 1)
|
||||
}
|
||||
|
||||
// PageRoundUp returns x rounded up to the nearest page boundary.
|
||||
// ok is true iff rounding up did not wrap around.
|
||||
func PageRoundUp(x uint64) (addr uint64, ok bool) {
|
||||
addr = PageRoundDown(x + PageSize - 1)
|
||||
ok = addr >= x
|
||||
return
|
||||
}
|
||||
|
||||
// ToPages returns number of Pages for x.
|
||||
// x is rounded up to the nearest page boundary.
|
||||
func ToPages(x uint64) (uint64, bool) {
|
||||
xRoundedUp, ok := PageRoundUp(x)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return xRoundedUp / PageSize, true
|
||||
}
|
||||
|
||||
// CacheLineRoundDown returns the offset rounded down to the nearest cache line boundary.
|
||||
func CacheLineRoundDown(x uint64) uint64 {
|
||||
return x & ^uint64(CacheLineSize-1)
|
||||
}
|
||||
|
||||
// CacheLineRoundUp returns the offset rounded up to the nearest cache line boundary. ok is true iff
|
||||
// rounding up did not wrap around.
|
||||
func CacheLineRoundUp(x uint64) (val uint64, ok bool) {
|
||||
val = CacheLineRoundDown(x + uint64(CacheLineSize-1))
|
||||
ok = val >= x
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2022 The gVisor Authors.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package hostarch
|
||||
|
||||
// Masks often used when working with alignment in constant expressions.
|
||||
const (
|
||||
PageMask = PageSize - 1
|
||||
HugePageMask = HugePageSize - 1
|
||||
CacheLineMask = CacheLineSize - 1
|
||||
)
|
||||
|
||||
type bytecount interface {
|
||||
~uint | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
type hugebytecount interface {
|
||||
~uint | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
// PageRoundDown returns x rounded down to the nearest multiple of PageSize.
|
||||
func PageRoundDown[T bytecount](x T) T {
|
||||
return x &^ PageMask
|
||||
}
|
||||
|
||||
// PageRoundUp returns x rounded up to the nearest multiple of PageSize. ok is
|
||||
// true iff rounding up does not overflow the range of T.
|
||||
func PageRoundUp[T bytecount](x T) (val T, ok bool) {
|
||||
val = PageRoundDown(x + PageMask)
|
||||
ok = val >= x
|
||||
return
|
||||
}
|
||||
|
||||
// MustPageRoundUp is equivalent to PageRoundUp, but panics if rounding up
|
||||
// overflows.
|
||||
func MustPageRoundUp[T bytecount](x T) T {
|
||||
val, ok := PageRoundUp(x)
|
||||
if !ok {
|
||||
panic("PageRoundUp overflows")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// PageOffset returns the offset of x into its containing page.
|
||||
func PageOffset[T bytecount](x T) T {
|
||||
return x & PageMask
|
||||
}
|
||||
|
||||
// IsPageAligned returns true if x is a multiple of PageSize.
|
||||
func IsPageAligned[T bytecount](x T) bool {
|
||||
return PageOffset(x) == 0
|
||||
}
|
||||
|
||||
// ToPagesRoundUp returns (the number of pages equal to x bytes rounded up,
|
||||
// true). If rounding x up to a multiple of PageSize overflows the range of T,
|
||||
// ToPagesRoundUp returns (unspecified, false).
|
||||
func ToPagesRoundUp[T bytecount](x T) (T, bool) {
|
||||
y := x + PageMask
|
||||
if y < x {
|
||||
return x, false
|
||||
}
|
||||
return y / PageSize, true
|
||||
}
|
||||
|
||||
// HugePageRoundDown returns x rounded down to the nearest multiple of
|
||||
// HugePageSize.
|
||||
func HugePageRoundDown[T hugebytecount](x T) T {
|
||||
return x &^ HugePageMask
|
||||
}
|
||||
|
||||
// HugePageRoundUp returns x rounded up to the nearest multiple of
|
||||
// HugePageSize. ok is true iff rounding up does not overflow the range of T.
|
||||
func HugePageRoundUp[T hugebytecount](x T) (val T, ok bool) {
|
||||
val = HugePageRoundDown(x + HugePageMask)
|
||||
ok = val >= x
|
||||
return
|
||||
}
|
||||
|
||||
// MustHugePageRoundUp is equivalent to HugePageRoundUp, but panics if rounding
|
||||
// up overflows.
|
||||
func MustHugePageRoundUp[T hugebytecount](x T) T {
|
||||
val, ok := HugePageRoundUp(x)
|
||||
if !ok {
|
||||
panic("HugePageRoundUp overflows")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// HugePageOffset returns the offset of x into its containing page.
|
||||
func HugePageOffset[T hugebytecount](x T) T {
|
||||
return x & HugePageMask
|
||||
}
|
||||
|
||||
// IsHugePageAligned returns true if x is a multiple of HugePageSize.
|
||||
func IsHugePageAligned[T hugebytecount](x T) bool {
|
||||
return HugePageOffset(x) == 0
|
||||
}
|
||||
|
||||
// CacheLineRoundDown returns the offset rounded down to the nearest multiple
|
||||
// of CacheLineSize.
|
||||
func CacheLineRoundDown[T bytecount](x T) T {
|
||||
return x &^ CacheLineMask
|
||||
}
|
||||
|
||||
// CacheLineRoundUp returns the offset rounded up to the nearest multiple of
|
||||
// CacheLineSize. ok is true iff rounding up does not overflow the range of T.
|
||||
func CacheLineRoundUp[T bytecount](x T) (val T, ok bool) {
|
||||
val = CacheLineRoundDown(x + CacheLineMask)
|
||||
ok = val >= x
|
||||
return
|
||||
}
|
||||
@@ -244,7 +244,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
}
|
||||
// Convert size in bytes to nearest Page Size bytes
|
||||
// as Linux allocates memory in terms of Page size.
|
||||
maxSizeInPages, ok = hostarch.ToPages(maxSizeInBytes)
|
||||
maxSizeInPages, ok = hostarch.ToPagesRoundUp(maxSizeInBytes)
|
||||
if !ok {
|
||||
ctx.Warningf("tmpfs.FilesystemType.GetFilesystem: Pages RoundUp Overflow error: %q", ok)
|
||||
return nil, nil, linuxerr.EINVAL
|
||||
|
||||
Reference in New Issue
Block a user