From: Jeremy Faller Date: Fri, 17 Apr 2020 20:11:28 +0000 (-0400) Subject: [dev.link] cmd/link: fallocate space, and remove all msync calls X-Git-Tag: go1.15beta1~401^2^2~16 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=8ab37b1bafdd0040530f976f45c417029cda6965;p=gostls13.git [dev.link] cmd/link: fallocate space, and remove all msync calls The fallocate calls will lower the chances of SIGBUS in the linker, but it might still happen on other unsupported platforms and filesystems. Darwin cmd/compile stats: Munmap 16.0ms ± 8% 0.8ms ± 3% -95.19% (p=0.000 n=8+10) TotalTime 484ms ± 2% 462ms ± 2% -4.52% (p=0.000 n=10+9) Updates #37310 Change-Id: I41c6e490adec26fa1ebee49a5b268828f5ba05e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/228385 Run-TryBot: Jeremy Faller TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go index f043168f1a..b58dee368b 100644 --- a/src/cmd/link/internal/ld/outbuf.go +++ b/src/cmd/link/internal/ld/outbuf.go @@ -13,6 +13,13 @@ import ( "os" ) +// If fallocate is not supported on this platform, return this error. +// Note this is the same error returned by filesystems that don't support +// fallocate, and that is intentional. The error is ignored where needed, and +// OutBuf writes to heap memory. +const fallocateNotSupportedErr = "operation not supported" +const outbufMode = 0775 + // OutBuf is a buffered file writer. // // It is simlar to the Writer in cmd/internal/bio with a few small differences. @@ -70,7 +77,7 @@ func (out *OutBuf) Open(name string) error { if out.f != nil { return errors.New("cannot open more than one file") } - f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775) + f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, outbufMode) if err != nil { return err } diff --git a/src/cmd/link/internal/ld/outbuf_darwin.go b/src/cmd/link/internal/ld/outbuf_darwin.go new file mode 100644 index 0000000000..299902ec62 --- /dev/null +++ b/src/cmd/link/internal/ld/outbuf_darwin.go @@ -0,0 +1,26 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ld + +import ( + "syscall" + "unsafe" +) + +func (out *OutBuf) fallocate(size uint64) error { + store := &syscall.Fstore_t{ + Flags: syscall.F_ALLOCATEALL, + Posmode: syscall.F_PEOFPOSMODE, + Offset: 0, + Length: int64(size), + } + + _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store))) + if err != 0 { + return err + } + + return nil +} diff --git a/src/cmd/link/internal/ld/outbuf_linux.go b/src/cmd/link/internal/ld/outbuf_linux.go new file mode 100644 index 0000000000..93e621a70f --- /dev/null +++ b/src/cmd/link/internal/ld/outbuf_linux.go @@ -0,0 +1,11 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ld + +import "syscall" + +func (out *OutBuf) fallocate(size uint64) error { + return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size)) +} diff --git a/src/cmd/link/internal/ld/outbuf_mmap.go b/src/cmd/link/internal/ld/outbuf_mmap.go index a2493d7d16..e6ee041abb 100644 --- a/src/cmd/link/internal/ld/outbuf_mmap.go +++ b/src/cmd/link/internal/ld/outbuf_mmap.go @@ -8,11 +8,19 @@ package ld import ( "syscall" - "unsafe" ) func (out *OutBuf) Mmap(filesize uint64) error { - err := out.f.Truncate(int64(filesize)) + err := out.fallocate(filesize) + if err != nil { + // Some file systems do not support fallocate. We ignore that error as linking + // can still take place, but you might SIGBUS when you write to the mmapped + // area. + if err.Error() != fallocateNotSupportedErr { + return err + } + } + err = out.f.Truncate(int64(filesize)) if err != nil { Exitf("resize output file failed: %v", err) } @@ -24,27 +32,10 @@ func (out *OutBuf) munmap() { if out.buf == nil { return } - err := out.Msync() - if err != nil { - Exitf("msync output file failed: %v", err) - } syscall.Munmap(out.buf) out.buf = nil - _, err = out.f.Seek(out.off, 0) + _, err := out.f.Seek(out.off, 0) if err != nil { Exitf("seek output file failed: %v", err) } } - -func (out *OutBuf) Msync() error { - if out.buf == nil { - return nil - } - // TODO: netbsd supports mmap and msync, but the syscall package doesn't define MSYNC. - // It is excluded from the build tag for now. - _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_SYNC) - if errno != 0 { - return errno - } - return nil -} diff --git a/src/cmd/link/internal/ld/outbuf_nofallocate.go b/src/cmd/link/internal/ld/outbuf_nofallocate.go new file mode 100644 index 0000000000..51b4fe7aff --- /dev/null +++ b/src/cmd/link/internal/ld/outbuf_nofallocate.go @@ -0,0 +1,13 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !darwin,!linux + +package ld + +import "errors" + +func (out *OutBuf) fallocate(size uint64) error { + return errors.New(fallocateNotSupportedErr) +} diff --git a/src/cmd/link/internal/ld/outbuf_nommap.go b/src/cmd/link/internal/ld/outbuf_nommap.go index 472fca22d7..51218d8ae7 100644 --- a/src/cmd/link/internal/ld/outbuf_nommap.go +++ b/src/cmd/link/internal/ld/outbuf_nommap.go @@ -12,5 +12,4 @@ func (out *OutBuf) Mmap(filesize uint64) error { return nil } -func (out *OutBuf) munmap() { panic("unreachable") } -func (out *OutBuf) Msync() error { panic("unreachable") } +func (out *OutBuf) munmap() { panic("unreachable") } diff --git a/src/cmd/link/internal/ld/outbuf_test.go b/src/cmd/link/internal/ld/outbuf_test.go index 58f9b10cfa..d8c21426b3 100644 --- a/src/cmd/link/internal/ld/outbuf_test.go +++ b/src/cmd/link/internal/ld/outbuf_test.go @@ -33,6 +33,9 @@ func TestMMap(t *testing.T) { if err := ob.Mmap(1 << 20); err != nil { t.Errorf("error mmapping file %v", err) } + if !ob.isMmapped() { + t.Errorf("should be mmapped") + } } // TestWriteLoc ensures that the math surrounding writeLoc is correct. diff --git a/src/cmd/link/internal/ld/outbuf_windows.go b/src/cmd/link/internal/ld/outbuf_windows.go index fc4fc5fb3b..a7140cce38 100644 --- a/src/cmd/link/internal/ld/outbuf_windows.go +++ b/src/cmd/link/internal/ld/outbuf_windows.go @@ -41,10 +41,3 @@ func (out *OutBuf) munmap() { Exitf("UnmapViewOfFile failed: %v", err) } } - -func (out *OutBuf) Msync() error { - if out.buf == nil { - return nil - } - return syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0) -}