tstest/integration: use hard links for binary copies to avoid /tmp exhaustion

When running many parallel integration tests, each subtest copies ~70MB
of binaries (tailscale + tailscaled) to its temp directory. With 24+
parallel subtests, this quickly exhausts /tmp space, causing "no space
left on device" errors that appear as test flakes.

Try hard linking first before falling back to copying. Hard links share
the same inode and don't consume additional disk space.

Change-Id: I8cddd993af40f99a34f9e994b2f5a6f5daf294bf
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This commit is contained in:
Avery Pennarun 2026-04-13 03:52:53 +02:00
parent 62644cb97b
commit b9f468240f

View File

@ -93,13 +93,14 @@ func (b BinaryInfo) CopyTo(dir string) (BinaryInfo, error) {
ret.Path = filepath.Join(dir, path.Base(b.Path))
switch runtime.GOOS {
case "linux":
// TODO(bradfitz): be fancy and use linkat with AT_EMPTY_PATH to avoid
// copying? I couldn't get it to work, though.
// For now, just do the same thing as every other Unix and copy
// the binary.
fallthrough
case "darwin", "freebsd", "openbsd", "netbsd":
case "linux", "darwin", "freebsd", "openbsd", "netbsd":
// Try hard link first to save disk space. Hard links share the same
// inode so they don't consume additional disk space, which is
// important when running many parallel integration tests.
if err := os.Link(b.Path, ret.Path); err == nil {
return ret, nil
}
// Fall back to copying if hard link fails (e.g., cross-device).
f, err := os.OpenFile(ret.Path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o755)
if err != nil {
return BinaryInfo{}, err