From 962976f2dfc10adf18b97d8098880a99ccede24f Mon Sep 17 00:00:00 2001 From: Gyu-Ho Lee Date: Mon, 27 Nov 2017 06:23:31 -0800 Subject: [PATCH] pkg/fileutil: fix preallocate under OS X kernel ftruncate changes st_blocks, and following fallocate syscalls would return EINVAL when allocated block size is already greater than requested block size (e.g. st_blocks==8, requested blocks are 2). Signed-off-by: Gyu-Ho Lee --- pkg/fileutil/preallocate_darwin.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) 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 }