mirror of
https://github.com/golang/go
synced 2024-11-23 15:40:06 -07:00
cmd/link: fix size calculation for file space preallocation on darwin
On darwin, we preallocate file storage space with fcntl F_ALLOCATEALL in F_PEOFPOSMODE mode. This is specified as allocating from the physical end of the file. So the size we give it should be the increment, instead of the total size. Fixes #39044. Change-Id: I10c7ee8d51f237b4a7604233ac7abc6f91dcd602 Reviewed-on: https://go-review.googlesource.com/c/go/+/234481 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
parent
fed33d76bc
commit
39ea0ea05d
50
src/cmd/link/internal/ld/fallocate_test.go
Normal file
50
src/cmd/link/internal/ld/fallocate_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
// 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 (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFallocate(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "TestFallocate")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
filename := filepath.Join(dir, "a.out")
|
||||
out := NewOutBuf(nil)
|
||||
err = out.Open(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Open file failed: %v", err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
// Mmap 1 MiB initially, and grow to 2 and 3 MiB.
|
||||
// Check if the file size and disk usage is expected.
|
||||
for _, sz := range []int64{1 << 20, 2 << 20, 3 << 20} {
|
||||
err = out.Mmap(uint64(sz))
|
||||
if err != nil {
|
||||
t.Fatalf("Mmap failed: %v", err)
|
||||
}
|
||||
stat, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Stat failed: %v", err)
|
||||
}
|
||||
if got := stat.Size(); got != sz {
|
||||
t.Errorf("unexpected file size: got %d, want %d", got, sz)
|
||||
}
|
||||
if got, want := stat.Sys().(*syscall.Stat_t).Blocks, (sz+511)/512; got != want {
|
||||
t.Errorf("unexpected disk usage: got %d blocks, want %d", got, want)
|
||||
}
|
||||
out.munmap()
|
||||
}
|
||||
}
|
@ -10,16 +10,25 @@ import (
|
||||
)
|
||||
|
||||
func (out *OutBuf) fallocate(size uint64) error {
|
||||
stat, err := out.f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cursize := uint64(stat.Size())
|
||||
if size <= cursize {
|
||||
return nil
|
||||
}
|
||||
|
||||
store := &syscall.Fstore_t{
|
||||
Flags: syscall.F_ALLOCATEALL,
|
||||
Posmode: syscall.F_PEOFPOSMODE,
|
||||
Offset: 0,
|
||||
Length: int64(size),
|
||||
Length: int64(size - cursize), // F_PEOFPOSMODE allocates from the end of the file, so we want the size difference here
|
||||
}
|
||||
|
||||
_, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
|
||||
if err != 0 {
|
||||
return err
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user