Skip to content

Commit 39ea0ea

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Austin Clements <[email protected]> Reviewed-by: Jeremy Faller <[email protected]>
1 parent fed33d7 commit 39ea0ea

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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 (
10+
"io/ioutil"
11+
"os"
12+
"path/filepath"
13+
"syscall"
14+
"testing"
15+
)
16+
17+
func TestFallocate(t *testing.T) {
18+
dir, err := ioutil.TempDir("", "TestFallocate")
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
defer os.RemoveAll(dir)
23+
filename := filepath.Join(dir, "a.out")
24+
out := NewOutBuf(nil)
25+
err = out.Open(filename)
26+
if err != nil {
27+
t.Fatalf("Open file failed: %v", err)
28+
}
29+
defer out.Close()
30+
31+
// Mmap 1 MiB initially, and grow to 2 and 3 MiB.
32+
// Check if the file size and disk usage is expected.
33+
for _, sz := range []int64{1 << 20, 2 << 20, 3 << 20} {
34+
err = out.Mmap(uint64(sz))
35+
if err != nil {
36+
t.Fatalf("Mmap failed: %v", err)
37+
}
38+
stat, err := os.Stat(filename)
39+
if err != nil {
40+
t.Fatalf("Stat failed: %v", err)
41+
}
42+
if got := stat.Size(); got != sz {
43+
t.Errorf("unexpected file size: got %d, want %d", got, sz)
44+
}
45+
if got, want := stat.Sys().(*syscall.Stat_t).Blocks, (sz+511)/512; got != want {
46+
t.Errorf("unexpected disk usage: got %d blocks, want %d", got, want)
47+
}
48+
out.munmap()
49+
}
50+
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,25 @@ import (
1010
)
1111

1212
func (out *OutBuf) fallocate(size uint64) error {
13+
stat, err := out.f.Stat()
14+
if err != nil {
15+
return err
16+
}
17+
cursize := uint64(stat.Size())
18+
if size <= cursize {
19+
return nil
20+
}
21+
1322
store := &syscall.Fstore_t{
1423
Flags: syscall.F_ALLOCATEALL,
1524
Posmode: syscall.F_PEOFPOSMODE,
1625
Offset: 0,
17-
Length: int64(size),
26+
Length: int64(size - cursize), // F_PEOFPOSMODE allocates from the end of the file, so we want the size difference here
1827
}
1928

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
29+
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
30+
if errno != 0 {
31+
return errno
2332
}
2433

2534
return nil

0 commit comments

Comments
 (0)