"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.
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
}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+}
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)
}
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
-}
--- /dev/null
+// 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)
+}
return nil
}
-func (out *OutBuf) munmap() { panic("unreachable") }
-func (out *OutBuf) Msync() error { panic("unreachable") }
+func (out *OutBuf) munmap() { panic("unreachable") }
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.
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)
-}