Skip to content

Commit 8ab37b1

Browse files
committed
[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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent 7d4c455 commit 8ab37b1

8 files changed

+73
-30
lines changed

src/cmd/link/internal/ld/outbuf.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ import (
1313
"os"
1414
)
1515

16+
// If fallocate is not supported on this platform, return this error.
17+
// Note this is the same error returned by filesystems that don't support
18+
// fallocate, and that is intentional. The error is ignored where needed, and
19+
// OutBuf writes to heap memory.
20+
const fallocateNotSupportedErr = "operation not supported"
21+
const outbufMode = 0775
22+
1623
// OutBuf is a buffered file writer.
1724
//
1825
// 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 {
7077
if out.f != nil {
7178
return errors.New("cannot open more than one file")
7279
}
73-
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
80+
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, outbufMode)
7481
if err != nil {
7582
return err
7683
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package ld
6+
7+
import (
8+
"syscall"
9+
"unsafe"
10+
)
11+
12+
func (out *OutBuf) fallocate(size uint64) error {
13+
store := &syscall.Fstore_t{
14+
Flags: syscall.F_ALLOCATEALL,
15+
Posmode: syscall.F_PEOFPOSMODE,
16+
Offset: 0,
17+
Length: int64(size),
18+
}
19+
20+
_, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
21+
if err != 0 {
22+
return err
23+
}
24+
25+
return nil
26+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package ld
6+
7+
import "syscall"
8+
9+
func (out *OutBuf) fallocate(size uint64) error {
10+
return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size))
11+
}

src/cmd/link/internal/ld/outbuf_mmap.go

+11-20
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ package ld
88

99
import (
1010
"syscall"
11-
"unsafe"
1211
)
1312

1413
func (out *OutBuf) Mmap(filesize uint64) error {
15-
err := out.f.Truncate(int64(filesize))
14+
err := out.fallocate(filesize)
15+
if err != nil {
16+
// Some file systems do not support fallocate. We ignore that error as linking
17+
// can still take place, but you might SIGBUS when you write to the mmapped
18+
// area.
19+
if err.Error() != fallocateNotSupportedErr {
20+
return err
21+
}
22+
}
23+
err = out.f.Truncate(int64(filesize))
1624
if err != nil {
1725
Exitf("resize output file failed: %v", err)
1826
}
@@ -24,27 +32,10 @@ func (out *OutBuf) munmap() {
2432
if out.buf == nil {
2533
return
2634
}
27-
err := out.Msync()
28-
if err != nil {
29-
Exitf("msync output file failed: %v", err)
30-
}
3135
syscall.Munmap(out.buf)
3236
out.buf = nil
33-
_, err = out.f.Seek(out.off, 0)
37+
_, err := out.f.Seek(out.off, 0)
3438
if err != nil {
3539
Exitf("seek output file failed: %v", err)
3640
}
3741
}
38-
39-
func (out *OutBuf) Msync() error {
40-
if out.buf == nil {
41-
return nil
42-
}
43-
// TODO: netbsd supports mmap and msync, but the syscall package doesn't define MSYNC.
44-
// It is excluded from the build tag for now.
45-
_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&out.buf[0])), uintptr(len(out.buf)), syscall.MS_SYNC)
46-
if errno != 0 {
47-
return errno
48-
}
49-
return nil
50-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build !darwin,!linux
6+
7+
package ld
8+
9+
import "errors"
10+
11+
func (out *OutBuf) fallocate(size uint64) error {
12+
return errors.New(fallocateNotSupportedErr)
13+
}

src/cmd/link/internal/ld/outbuf_nommap.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@ func (out *OutBuf) Mmap(filesize uint64) error {
1212
return nil
1313
}
1414

15-
func (out *OutBuf) munmap() { panic("unreachable") }
16-
func (out *OutBuf) Msync() error { panic("unreachable") }
15+
func (out *OutBuf) munmap() { panic("unreachable") }

src/cmd/link/internal/ld/outbuf_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ func TestMMap(t *testing.T) {
3333
if err := ob.Mmap(1 << 20); err != nil {
3434
t.Errorf("error mmapping file %v", err)
3535
}
36+
if !ob.isMmapped() {
37+
t.Errorf("should be mmapped")
38+
}
3639
}
3740

3841
// TestWriteLoc ensures that the math surrounding writeLoc is correct.

src/cmd/link/internal/ld/outbuf_windows.go

-7
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,3 @@ func (out *OutBuf) munmap() {
4141
Exitf("UnmapViewOfFile failed: %v", err)
4242
}
4343
}
44-
45-
func (out *OutBuf) Msync() error {
46-
if out.buf == nil {
47-
return nil
48-
}
49-
return syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0)
50-
}

0 commit comments

Comments
 (0)