diff options
author | gVisor bot <gvisor-bot@google.com> | 2019-06-02 06:44:55 +0000 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2019-06-02 06:44:55 +0000 |
commit | ceb0d792f328d1fc0692197d8856a43c3936a571 (patch) | |
tree | 83155f302eff44a78bcc30a3a08f4efe59a79379 /pkg/sentry/syscalls/linux/sys_sync.go | |
parent | deb7ecf1e46862d54f4b102f2d163cfbcfc37f3b (diff) | |
parent | 216da0b733dbed9aad9b2ab92ac75bcb906fd7ee (diff) |
Merge 216da0b7 (automated)
Diffstat (limited to 'pkg/sentry/syscalls/linux/sys_sync.go')
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_sync.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/pkg/sentry/syscalls/linux/sys_sync.go b/pkg/sentry/syscalls/linux/sys_sync.go new file mode 100644 index 000000000..4352482fb --- /dev/null +++ b/pkg/sentry/syscalls/linux/sys_sync.go @@ -0,0 +1,138 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package linux + +import ( + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/arch" + "gvisor.googlesource.com/gvisor/pkg/sentry/fs" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" + "gvisor.googlesource.com/gvisor/pkg/syserror" +) + +// Sync implements linux system call sync(2). +func Sync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + t.MountNamespace().SyncAll(t) + // Sync is always successful. + return 0, nil, nil +} + +// Syncfs implements linux system call syncfs(2). +func Syncfs(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + fd := kdefs.FD(args[0].Int()) + + file := t.FDMap().GetFile(fd) + if file == nil { + return 0, nil, syserror.EBADF + } + defer file.DecRef() + + // Use "sync-the-world" for now, it's guaranteed that fd is at least + // on the root filesystem. + return Sync(t, args) +} + +// Fsync implements linux syscall fsync(2). +func Fsync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + fd := kdefs.FD(args[0].Int()) + + file := t.FDMap().GetFile(fd) + if file == nil { + return 0, nil, syserror.EBADF + } + defer file.DecRef() + + err := file.Fsync(t, 0, fs.FileMaxOffset, fs.SyncAll) + return 0, nil, syserror.ConvertIntr(err, kernel.ERESTARTSYS) +} + +// Fdatasync implements linux syscall fdatasync(2). +// +// At the moment, it just calls Fsync, which is a big hammer, but correct. +func Fdatasync(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + fd := kdefs.FD(args[0].Int()) + + file := t.FDMap().GetFile(fd) + if file == nil { + return 0, nil, syserror.EBADF + } + defer file.DecRef() + + err := file.Fsync(t, 0, fs.FileMaxOffset, fs.SyncData) + return 0, nil, syserror.ConvertIntr(err, kernel.ERESTARTSYS) +} + +// SyncFileRange implements linux syscall sync_file_rage(2) +func SyncFileRange(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { + var err error + + offset := args[1].Int64() + nbytes := args[2].Int64() + uflags := args[3].Uint() + + if offset < 0 || offset+nbytes < offset { + return 0, nil, syserror.EINVAL + } + + if uflags&^(linux.SYNC_FILE_RANGE_WAIT_BEFORE| + linux.SYNC_FILE_RANGE_WRITE| + linux.SYNC_FILE_RANGE_WAIT_AFTER) != 0 { + return 0, nil, syserror.EINVAL + } + + if nbytes == 0 { + nbytes = fs.FileMaxOffset + } + + fd := kdefs.FD(args[0].Int()) + file := t.FDMap().GetFile(fd) + if file == nil { + return 0, nil, syserror.EBADF + } + defer file.DecRef() + + // SYNC_FILE_RANGE_WAIT_BEFORE waits upon write-out of all pages in the + // specified range that have already been submitted to the device + // driver for write-out before performing any write. + if uflags&linux.SYNC_FILE_RANGE_WAIT_BEFORE != 0 && + uflags&linux.SYNC_FILE_RANGE_WAIT_AFTER == 0 { + t.Kernel().EmitUnimplementedEvent(t) + return 0, nil, syserror.ENOSYS + } + + // SYNC_FILE_RANGE_WRITE initiates write-out of all dirty pages in the + // specified range which are not presently submitted write-out. + // + // It looks impossible to implement this functionality without a + // massive rework of the vfs subsystem. file.Fsync() take a file lock + // for the entire operation, so even if it is running in a go routing, + // it blocks other file operations instead of flushing data in the + // background. + // + // It should be safe to skipped this flag while nobody uses + // SYNC_FILE_RANGE_WAIT_BEFORE. + + // SYNC_FILE_RANGE_WAIT_AFTER waits upon write-out of all pages in the + // range after performing any write. + // + // In Linux, sync_file_range() doesn't writes out the file's + // meta-data, but fdatasync() does if a file size is changed. + if uflags&linux.SYNC_FILE_RANGE_WAIT_AFTER != 0 { + err = file.Fsync(t, offset, fs.FileMaxOffset, fs.SyncData) + } + + return 0, nil, syserror.ConvertIntr(err, kernel.ERESTARTSYS) +} |