khenaidoo | 59ce9dd | 2019-11-11 13:05:32 -0500 | [diff] [blame] | 1 | // Copyright 2016 The etcd Authors |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // +build darwin |
| 16 | |
| 17 | package fileutil |
| 18 | |
| 19 | import ( |
| 20 | "os" |
| 21 | "syscall" |
| 22 | "unsafe" |
| 23 | ) |
| 24 | |
| 25 | func preallocExtend(f *os.File, sizeInBytes int64) error { |
| 26 | if err := preallocFixed(f, sizeInBytes); err != nil { |
| 27 | return err |
| 28 | } |
| 29 | return preallocExtendTrunc(f, sizeInBytes) |
| 30 | } |
| 31 | |
| 32 | func preallocFixed(f *os.File, sizeInBytes int64) error { |
| 33 | // allocate all requested space or no space at all |
| 34 | // TODO: allocate contiguous space on disk with F_ALLOCATECONTIG flag |
| 35 | fstore := &syscall.Fstore_t{ |
| 36 | Flags: syscall.F_ALLOCATEALL, |
| 37 | Posmode: syscall.F_PEOFPOSMODE, |
| 38 | Length: sizeInBytes} |
| 39 | p := unsafe.Pointer(fstore) |
| 40 | _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(p)) |
| 41 | if errno == 0 || errno == syscall.ENOTSUP { |
| 42 | return nil |
| 43 | } |
| 44 | |
| 45 | // wrong argument to fallocate syscall |
| 46 | if errno == syscall.EINVAL { |
| 47 | // filesystem "st_blocks" are allocated in the units of |
| 48 | // "Allocation Block Size" (run "diskutil info /" command) |
| 49 | var stat syscall.Stat_t |
| 50 | syscall.Fstat(int(f.Fd()), &stat) |
| 51 | |
| 52 | // syscall.Statfs_t.Bsize is "optimal transfer block size" |
| 53 | // and contains matching 4096 value when latest OS X kernel |
| 54 | // supports 4,096 KB filesystem block size |
| 55 | var statfs syscall.Statfs_t |
| 56 | syscall.Fstatfs(int(f.Fd()), &statfs) |
| 57 | blockSize := int64(statfs.Bsize) |
| 58 | |
| 59 | if stat.Blocks*blockSize >= sizeInBytes { |
| 60 | // enough blocks are already allocated |
| 61 | return nil |
| 62 | } |
| 63 | } |
| 64 | return errno |
| 65 | } |