]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix size calculation for file space preallocation on darwin
authorCherry Zhang <cherryyz@google.com>
Mon, 18 May 2020 19:23:46 +0000 (15:23 -0400)
committerCherry Zhang <cherryyz@google.com>
Thu, 21 May 2020 14:48:43 +0000 (14:48 +0000)
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>
src/cmd/link/internal/ld/fallocate_test.go [new file with mode: 0644]
src/cmd/link/internal/ld/outbuf_darwin.go

diff --git a/src/cmd/link/internal/ld/fallocate_test.go b/src/cmd/link/internal/ld/fallocate_test.go
new file mode 100644 (file)
index 0000000..a064bea
--- /dev/null
@@ -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()
+       }
+}
index 299902ec62671f2e4d50b2ad906fbc620e48d07d..9a74ba875e265cf7648fa043f915608672261472 100644 (file)
@@ -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