diff --git a/pkg/fileutil/preallocate_darwin.go b/pkg/fileutil/preallocate_darwin.go index 1ed09c560..5a6dccfa7 100644 --- a/pkg/fileutil/preallocate_darwin.go +++ b/pkg/fileutil/preallocate_darwin.go @@ -30,6 +30,8 @@ func preallocExtend(f *os.File, sizeInBytes int64) error { } func preallocFixed(f *os.File, sizeInBytes int64) error { + // allocate all requested space or no space at all + // TODO: allocate contiguous space on disk with F_ALLOCATECONTIG flag fstore := &syscall.Fstore_t{ Flags: syscall.F_ALLOCATEALL, Posmode: syscall.F_PEOFPOSMODE, @@ -39,5 +41,25 @@ func preallocFixed(f *os.File, sizeInBytes int64) error { if errno == 0 || errno == syscall.ENOTSUP { return nil } + + // wrong argument to fallocate syscall + if errno == syscall.EINVAL { + // filesystem "st_blocks" are allocated in the units of + // "Allocation Block Size" (run "diskutil info /" command) + var stat syscall.Stat_t + syscall.Fstat(int(f.Fd()), &stat) + + // syscall.Statfs_t.Bsize is "optimal transfer block size" + // and contains matching 4096 value when latest OS X kernel + // supports 4,096 KB filesystem block size + var statfs syscall.Statfs_t + syscall.Fstatfs(int(f.Fd()), &statfs) + blockSize := int64(statfs.Bsize) + + if stat.Blocks*blockSize >= sizeInBytes { + // enough blocks are already allocated + return nil + } + } return errno }