github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_sync.go (about) 1 // Copyright 2018 The gVisor 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 package linux 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 "github.com/SagerNet/gvisor/pkg/sentry/arch" 21 "github.com/SagerNet/gvisor/pkg/sentry/fs" 22 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 23 "github.com/SagerNet/gvisor/pkg/syserror" 24 ) 25 26 // LINT.IfChange 27 28 // Sync implements linux system call sync(2). 29 func Sync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 30 t.MountNamespace().SyncAll(t) 31 // Sync is always successful. 32 return 0, nil, nil 33 } 34 35 // Syncfs implements linux system call syncfs(2). 36 func Syncfs(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 37 fd := args[0].Int() 38 39 file := t.GetFile(fd) 40 if file == nil { 41 return 0, nil, linuxerr.EBADF 42 } 43 defer file.DecRef(t) 44 45 // Use "sync-the-world" for now, it's guaranteed that fd is at least 46 // on the root filesystem. 47 return Sync(t, args) 48 } 49 50 // Fsync implements linux syscall fsync(2). 51 func Fsync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 52 fd := args[0].Int() 53 54 file := t.GetFile(fd) 55 if file == nil { 56 return 0, nil, linuxerr.EBADF 57 } 58 defer file.DecRef(t) 59 60 err := file.Fsync(t, 0, fs.FileMaxOffset, fs.SyncAll) 61 return 0, nil, syserror.ConvertIntr(err, syserror.ERESTARTSYS) 62 } 63 64 // Fdatasync implements linux syscall fdatasync(2). 65 // 66 // At the moment, it just calls Fsync, which is a big hammer, but correct. 67 func Fdatasync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 68 fd := args[0].Int() 69 70 file := t.GetFile(fd) 71 if file == nil { 72 return 0, nil, linuxerr.EBADF 73 } 74 defer file.DecRef(t) 75 76 err := file.Fsync(t, 0, fs.FileMaxOffset, fs.SyncData) 77 return 0, nil, syserror.ConvertIntr(err, syserror.ERESTARTSYS) 78 } 79 80 // SyncFileRange implements linux syscall sync_file_rage(2) 81 func SyncFileRange(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 82 var err error 83 84 fd := args[0].Int() 85 offset := args[1].Int64() 86 nbytes := args[2].Int64() 87 uflags := args[3].Uint() 88 89 if offset < 0 || offset+nbytes < offset { 90 return 0, nil, linuxerr.EINVAL 91 } 92 93 if uflags&^(linux.SYNC_FILE_RANGE_WAIT_BEFORE| 94 linux.SYNC_FILE_RANGE_WRITE| 95 linux.SYNC_FILE_RANGE_WAIT_AFTER) != 0 { 96 return 0, nil, linuxerr.EINVAL 97 } 98 99 if nbytes == 0 { 100 nbytes = fs.FileMaxOffset 101 } 102 103 file := t.GetFile(fd) 104 if file == nil { 105 return 0, nil, linuxerr.EBADF 106 } 107 defer file.DecRef(t) 108 109 // SYNC_FILE_RANGE_WAIT_BEFORE waits upon write-out of all pages in the 110 // specified range that have already been submitted to the device 111 // driver for write-out before performing any write. 112 if uflags&linux.SYNC_FILE_RANGE_WAIT_BEFORE != 0 && 113 uflags&linux.SYNC_FILE_RANGE_WAIT_AFTER == 0 { 114 t.Kernel().EmitUnimplementedEvent(t) 115 return 0, nil, syserror.ENOSYS 116 } 117 118 // SYNC_FILE_RANGE_WRITE initiates write-out of all dirty pages in the 119 // specified range which are not presently submitted write-out. 120 // 121 // It looks impossible to implement this functionality without a 122 // massive rework of the vfs subsystem. file.Fsync() take a file lock 123 // for the entire operation, so even if it is running in a go routing, 124 // it blocks other file operations instead of flushing data in the 125 // background. 126 // 127 // It should be safe to skipped this flag while nobody uses 128 // SYNC_FILE_RANGE_WAIT_BEFORE. 129 _ = nbytes 130 131 // SYNC_FILE_RANGE_WAIT_AFTER waits upon write-out of all pages in the 132 // range after performing any write. 133 // 134 // In Linux, sync_file_range() doesn't writes out the file's 135 // meta-data, but fdatasync() does if a file size is changed. 136 if uflags&linux.SYNC_FILE_RANGE_WAIT_AFTER != 0 { 137 err = file.Fsync(t, offset, fs.FileMaxOffset, fs.SyncData) 138 } 139 140 return 0, nil, syserror.ConvertIntr(err, syserror.ERESTARTSYS) 141 } 142 143 // LINT.ThenChange(vfs2/sync.go)