Source file src/cmd/link/internal/ld/fallocate_test.go

     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  //go:build darwin || freebsd || linux || (netbsd && go1.25)
     6  
     7  package ld
     8  
     9  import (
    10  	"errors"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"syscall"
    15  	"testing"
    16  )
    17  
    18  func TestFallocate(t *testing.T) {
    19  	dir := t.TempDir()
    20  	filename := filepath.Join(dir, "a.out")
    21  	out := NewOutBuf(nil)
    22  	err := out.Open(filename)
    23  	if err != nil {
    24  		t.Fatalf("Open file failed: %v", err)
    25  	}
    26  	defer out.Close()
    27  
    28  	// Try fallocate first.
    29  	for {
    30  		err = out.fallocate(1 << 10)
    31  		if errors.Is(err, errors.ErrUnsupported) || err == errNoFallocate { // The underlying file system may not support fallocate
    32  			t.Skip("fallocate is not supported")
    33  		}
    34  		if err == syscall.EINTR {
    35  			continue // try again
    36  		}
    37  		if err != nil {
    38  			t.Fatalf("fallocate failed: %v", err)
    39  		}
    40  		break
    41  	}
    42  
    43  	// Mmap 1 MiB initially, and grow to 2 and 3 MiB.
    44  	// Check if the file size and disk usage is expected.
    45  	for _, sz := range []int64{1 << 20, 2 << 20, 3 << 20} {
    46  		err = out.Mmap(uint64(sz))
    47  		if err != nil {
    48  			t.Fatalf("Mmap failed: %v", err)
    49  		}
    50  		stat, err := os.Stat(filename)
    51  		if err != nil {
    52  			t.Fatalf("Stat failed: %v", err)
    53  		}
    54  		if got := stat.Size(); got != sz {
    55  			t.Errorf("unexpected file size: got %d, want %d", got, sz)
    56  		}
    57  		if runtime.GOOS == "darwin" {
    58  			// Check the number of allocated blocks on Darwin. On Linux (and
    59  			// perhaps BSDs), stat's Blocks field may not be portable as it
    60  			// is an implementation detail of the file system. On Darwin, it
    61  			// is documented as "the actual number of blocks allocated for
    62  			// the file in 512-byte units".
    63  			// The check is introduced when fixing a Darwin-specific bug. On
    64  			// Darwin, the file allocation syscall is a bit tricky. On Linux
    65  			// and BSDs, it is more straightforward and unlikely to go wrong.
    66  			// Given these two reasons, only check it on Darwin.
    67  			//
    68  			// The number of blocks must be enough for the requested size.
    69  			// We used to require an exact match, but it appears that
    70  			// some file systems allocate a few extra blocks in some cases.
    71  			// See issue #41127.
    72  			if got, want := stat.Sys().(*syscall.Stat_t).Blocks, (sz+511)/512; got < want {
    73  				t.Errorf("unexpected disk usage: got %d blocks, want at least %d", got, want)
    74  			}
    75  		}
    76  		out.munmap()
    77  	}
    78  }
    79  

View as plain text