summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2020-05-27 17:51:40 +0000
committergVisor bot <gvisor-bot@google.com>2020-05-27 17:51:40 +0000
commit84452958e1397b337a806f815e07ae69c4f4c896 (patch)
tree138422671bc14bd0c66f83c31be1a991888f3359
parentbae1520437ecbd3dd217880cb51eb24b59d26f51 (diff)
parent0bc022b7f3c13bb7c5c8d47d1781820161e7b1ad (diff)
Merge release-20200518.0-45-g0bc022b7 (automated)
-rw-r--r--[-rwxr-xr-x]pkg/abi/abi_linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/abi_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/arch_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/epoll_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/epoll_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/file_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/file_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/ioctl_tun.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_abi_autogen_unsafe.go10
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go6
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go4
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/ptrace_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/ptrace_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/rseq.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/signalfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/abi/linux/xattr.go0
-rw-r--r--[-rwxr-xr-x]pkg/amutex/amutex_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/atomicbitops/atomicbitops.go0
-rw-r--r--[-rwxr-xr-x]pkg/atomicbitops/atomicbitops_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/atomicbitops/atomicbitops_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/atomicbitops/atomicbitops_noasm.go0
-rw-r--r--[-rwxr-xr-x]pkg/atomicbitops/atomicbitops_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/binary/binary_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/bits/bits32.go0
-rw-r--r--[-rwxr-xr-x]pkg/bits/bits64.go0
-rw-r--r--[-rwxr-xr-x]pkg/bits/bits_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/bits/uint64_arch.go0
-rw-r--r--[-rwxr-xr-x]pkg/bits/uint64_arch_arm64_asm.s0
-rw-r--r--[-rwxr-xr-x]pkg/bpf/bpf_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/buffer.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/buffer_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/buffer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/buffer_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/safemem.go82
-rw-r--r--[-rwxr-xr-x]pkg/buffer/view.go0
-rw-r--r--[-rwxr-xr-x]pkg/buffer/view_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/compressio/compressio_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/context/context.go0
-rw-r--r--[-rwxr-xr-x]pkg/context/context_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/control/client/client_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/control/server/server_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/cpuid/cpuid_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/cpuid/cpuid_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/cpuid/cpuid_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/cpuid/cpuid_x86.go0
-rw-r--r--[-rwxr-xr-x]pkg/cpuid/cpuid_x86_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/eventchannel/eventchannel_go_proto/event.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/eventchannel/eventchannel_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/fd/fd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/fdchannel/fdchannel_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/fdchannel/fdchannel_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/fdnotifier/fdnotifier_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/fdnotifier/fdnotifier_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/ctrl_futex.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/flipcall.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/flipcall_linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/flipcall_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/flipcall_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/flipcall_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/futex_linux.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/io.go0
-rw-r--r--[-rwxr-xr-x]pkg/flipcall/packet_window_allocator.go0
-rw-r--r--[-rwxr-xr-x]pkg/fspath/builder.go0
-rw-r--r--[-rwxr-xr-x]pkg/fspath/fspath.go0
-rw-r--r--[-rwxr-xr-x]pkg/fspath/fspath_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/gate/gate_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/gohacks/gohacks_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/gohacks/gohacks_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/ilist/ilist_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/ilist/interface_list.go0
-rwxr-xr-xpkg/linewriter/linewriter_state_autogen.go3
-rw-r--r--[-rwxr-xr-x]pkg/memutil/memutil_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/metric/metric_go_proto/metric.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/metric/metric_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/p9/p9_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/p9/transport_flipcall.go0
-rw-r--r--[-rwxr-xr-x]pkg/pool/pool.go0
-rw-r--r--[-rwxr-xr-x]pkg/pool/pool_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/procid/procid_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/rand/rand_linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/rand/rand_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/refs/refs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/refs/weak_ref_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/atomic_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/atomic_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/memclr_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/memclr_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/memcpy_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/memcpy_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/safecopy.go0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/safecopy_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/safecopy_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/safecopy_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/sighandler_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safecopy/sighandler_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/block_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/io.go0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/safemem.go0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/safemem_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/safemem_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/safemem/seq_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/seccomp/seccomp_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/seccomp/seccomp_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/seccomp/seccomp_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/seccomp/seccomp_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/secio/secio_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_aarch64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_aarch64_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_aarch64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_amd64_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_arm64_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_x86_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_x86_impl.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_x86_impl_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_x86_impl_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/arch_x86_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/registers_go_proto/registers.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/signal.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/signal_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/arch/syscalls_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/control/control_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/device/device_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/full.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/memdev.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/memdev_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/null.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/random.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/devices/memdev/zero.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fdimport/fdimport.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fdimport/fdimport_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/anon/anon_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/dev/dev_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/dev/net_tun.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/dirent_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/event_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fdpipe/fdpipe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/dirty_set_impl.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/file_range_set_impl.go377
-rw-r--r--pkg/sentry/fs/fsutil/frame_ref_set.go40
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/frame_ref_set_impl.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/fsutil_impl_state_autogen.go6
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/fsutil_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/fsutil/fsutil_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/gofer/fifo.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/gofer/gofer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/host.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/host_amd64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/host_arm64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/host_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/host_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/util_amd64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/host/util_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/lock/lock_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/lock/lock_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/lock/lock_state_autogen.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/proc/device/device_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/proc/proc_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/ramfs/ramfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/sys/sys_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/timerfd/timerfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/tmpfs/tmpfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/tty/tty_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/user/user.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fs/user/user_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsbridge/bridge.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsbridge/fs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsbridge/fsbridge_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsbridge/vfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/devpts.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/devpts_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/line_discipline.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/master.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/queue.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/slave.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devpts/terminal.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devtmpfs/devtmpfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/eventfd/eventfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/dentry_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/directory.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/fstree.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/gofer.go52
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/gofer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/handle.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/p9file.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/regular_file.go47
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/socket.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/special_file.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/symlink.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/gofer/time.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/control.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/host.go132
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/host_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/host_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/ioctl_unsafe.go0
-rw-r--r--pkg/sentry/fsimpl/host/mmap.go132
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/socket.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/socket_iovec.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/socket_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/tty.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/host/util_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/fd_impl_util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/fstree.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/inode_impl_util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/kernfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/slot_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/kernfs/symlink.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/pipefs/pipefs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/proc_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/subtasks.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/task.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/task_fds.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/task_files.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/task_net.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/tasks.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/tasks_files.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/proc/tasks_sys.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/signalfd/signalfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/sockfs/sockfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/sys/sys.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/sys/sys_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/timerfd/timerfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/dentry_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/device_file.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/directory.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/fstree.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/named_pipe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/regular_file.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/socket_file.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/symlink.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/tmpfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostcpu/getcpu_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostcpu/hostcpu_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostfd/hostfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostfd/hostfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostfd/hostfd_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostfd/hostfd_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/hostmm/hostmm_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/inet/inet_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/inet/namespace.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/auth/atomicptr_credentials_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/auth/auth_state_autogen.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/auth/auth_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/auth/id_map_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/auth/id_map_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/epoll/epoll_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/epoll/epoll_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/eventfd/eventfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/fasync/fasync_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/futex/atomicptr_bucket_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/futex/futex_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/futex/futex_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/futex/waiter_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_opts.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_opts_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/kernel_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/memevent/memevent_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/memevent/memory_events.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/memevent/memory_events_go_proto/memory_events.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pending_signals_list.go0
-rw-r--r--pkg/sentry/kernel/pipe/pipe.go6
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pipe/pipe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pipe/pipe_unsafe.go (renamed from pkg/sentry/fsimpl/gofer/pagemath.go)28
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pipe/pipe_unsafe_state_autogen.go (renamed from pkg/log/log_state_autogen.go)2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pipe/pipe_util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/pipe/vfs.go219
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/process_group_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/sched/sched_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/semaphore/semaphore_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/semaphore/waiter_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/seqatomic_taskgoroutineschedinfo_unsafe.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/session_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/shm/shm_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/signalfd/signalfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/signalfd/signalfd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/socket_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/task_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/time/time_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/tty.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/kernel/uncaught_signal_go_proto/uncaught_signal.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/limits/limits_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/loader/loader_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/loader/vdso_bin.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/memmap/mappable_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/memmap/mapping_set_impl.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/memmap/memmap_impl_state_autogen.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/memmap/memmap_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/mm/file_refcount_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/mm/io_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/mm/mm_state_autogen.go6
-rw-r--r--[-rwxr-xr-x]pkg/sentry/mm/pma_set.go377
-rw-r--r--pkg/sentry/mm/vma.go4
-rw-r--r--[-rwxr-xr-x]pkg/sentry/mm/vma_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/pgalloc/evictable_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/pgalloc/evictable_range_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/pgalloc/pgalloc_state_autogen.go4
-rw-r--r--[-rwxr-xr-x]pkg/sentry/pgalloc/pgalloc_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/pgalloc/usage_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/file_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/interrupt/interrupt_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/bluepill_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/bluepill_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/filters_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/filters_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_amd64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_arm64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_const_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/kvm_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/machine_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/machine_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/physical_map_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/kvm/physical_map_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/platform_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_arm64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_linux_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ptrace/ptrace_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/defs_impl_amd64.go4
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/defs_impl_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/entry_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/entry_impl_amd64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/entry_impl_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/kernel_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/lib_arm64.go6
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/lib_arm64.s10
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/lib_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_aarch64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_aarch64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pagetables_x86_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pcids.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pcids_aarch64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pcids_aarch64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/pcids_x86.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_empty.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_lookup.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_map.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/pagetables/walker_unmap.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_arm64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_impl_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_impl_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/platform/ring0/ring0_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/sighandling/sighandling_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/sighandling/sighandling_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/control/control_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/control/control_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/hostinet/hostinet_impl_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/hostinet/hostinet_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/hostinet/hostinet_unsafe_state_autogen.go0
-rw-r--r--pkg/sentry/socket/hostinet/socket.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/hostinet/socket_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/hostinet/sockopt_impl.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/extensions.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/netfilter_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/owner_matcher.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/targets.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/tcp_matcher.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netfilter/udp_matcher.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/netlink_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/port/port_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/provider_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/route/route_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/socket_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/uevent/protocol.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netlink/uevent/uevent_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/device.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/netstack.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/netstack_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/netstack_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/provider.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/provider_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/save_restore.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/netstack/stack.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/socket_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/unix/transport/transport_message_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/unix/transport/transport_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/unix/unix_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/socket/unix/unix_vfs2.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/state/state_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/state/state_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/epoll.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/linux64_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/linux64_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/select.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/strace_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/strace_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/strace_go_proto/strace.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/strace/strace_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_clone_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_clone_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_rseq.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_stat_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_stat_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_tls_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_tls_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/sys_xattr.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/epoll.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/eventfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/execve.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/fd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/fscontext.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/getdents.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/ioctl.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/memfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/mmap.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/path.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/pipe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/poll.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/read_write.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/setstat.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/signal.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/socket.go0
-rw-r--r--pkg/sentry/syscalls/linux/vfs2/splice.go286
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/stat.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/stat_amd64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/stat_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/sync.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/timerfd.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2.go4
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_abi_autogen_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/vfs2_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/linux/vfs2/xattr.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/syscalls/syscalls_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/time/seqatomic_parameters_unsafe.go2
-rw-r--r--[-rwxr-xr-x]pkg/sentry/time/time_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/time/time_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/time/time_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/unimpl/unimpl_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/unimpl/unimplemented_syscall_go_proto/unimplemented_syscall.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/uniqueid/uniqueid_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/usage/usage_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/usage/usage_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/anonfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/context.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/debug.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/dentry.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/device.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/epoll.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/epoll_interest_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/file_description.go5
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/file_description_impl_util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/filesystem.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/filesystem_impl_util.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/filesystem_type.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/lock/lock.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/lock/lock_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/memxattr/memxattr_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/memxattr/xattr.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/mount.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/mount_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/options.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/pathname.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/permissions.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/resolving_path.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/vfs.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/vfs_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/vfs/vfs_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sentry/watchdog/watchdog_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sleep/commit_arm64.s0
-rw-r--r--[-rwxr-xr-x]pkg/sleep/sleep_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sleep/sleep_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/state/addr_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/state/addr_set.go377
-rw-r--r--[-rwxr-xr-x]pkg/state/object_go_proto/object.pb.go0
-rw-r--r--[-rwxr-xr-x]pkg/state/statefile/statefile_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/aliases.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/memmove_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/mutex_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/norace_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/race_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/rwmutex_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/seqcount.go0
-rw-r--r--[-rwxr-xr-x]pkg/sync/sync.go0
-rwxr-xr-xpkg/sync/sync_state_autogen.go3
-rwxr-xr-xpkg/sync/sync_unsafe_state_autogen.go12
-rw-r--r--[-rwxr-xr-x]pkg/syserr/syserr_linux_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/syserr/syserr_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/syserror/syserror_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/adapters/gonet/gonet.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/adapters/gonet/gonet_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/buffer/buffer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/hash/jenkins/jenkins_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/header_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ipv6_extension_headers.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndp_neighbor_advert.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndp_neighbor_solicit.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndp_options.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndp_router_advert.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndp_router_solicit.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/header/ndpoptionidentifier_string.go0
-rw-r--r--pkg/tcpip/header/tcp.go29
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/channel/channel.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/channel/channel_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/fdbased/fdbased_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/fdbased/fdbased_unsafe_state_autogen.go0
-rw-r--r--pkg/tcpip/link/fdbased/packet_dispatchers.go2
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/loopback/loopback_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/muxed/injectable.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/muxed/muxed_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/qdisc/fifo/endpoint.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/qdisc/fifo/fifo_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/qdisc/fifo/packet_buffer_queue.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/rawfile/rawfile_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/rawfile/rawfile_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/pipe.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/pipe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/pipe_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/pipe_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/rx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/pipe/tx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/queue/queue_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/queue/rx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/queue/tx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/rx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/sharedmem.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/sharedmem_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/sharedmem_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/sharedmem_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sharedmem/tx.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/sniffer/sniffer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/tun/device.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/tun/protocol.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/tun/tun_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/tun/tun_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/tun/tun_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/waitable/waitable.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/link/waitable/waitable_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/arp/arp_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/fragmentation/fragmentation_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/fragmentation/reassembler_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/hash/hash_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/ipv4/ipv4_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/network/ipv6/ipv6_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/ports/ports_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/seqnum/seqnum_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/conntrack.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/dhcpv6configurationfromndpra_string.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/forwarder.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/iptables.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/iptables_targets.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/iptables_types.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/linkaddrentry_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/ndp.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/packet_buffer.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/packet_buffer_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/rand.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/stack/stack_state_autogen.go0
-rw-r--r--pkg/tcpip/tcpip.go65
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/tcpip_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/tcpip_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/timer.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/icmp/icmp_packet_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/icmp/icmp_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/packet/endpoint.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/packet/endpoint_state.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/packet/packet_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/packet/packet_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/raw/raw_packet_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/raw/raw_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/connect_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/dispatcher.go0
-rw-r--r--pkg/tcpip/transport/tcp/endpoint_state.go68
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/rcv_state.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/tcp_endpoint_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/tcp_segment_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/tcp_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcp/tcp_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcpconntrack/tcp_conntrack.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/tcpconntrack/tcpconntrack_state_autogen.go0
-rw-r--r--pkg/tcpip/transport/udp/endpoint.go32
-rw-r--r--pkg/tcpip/transport/udp/endpoint_state.go18
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/udp/udp_packet_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/tcpip/transport/udp/udp_state_autogen.go3
-rw-r--r--[-rwxr-xr-x]pkg/unet/unet_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/unet/unet_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/urpc/urpc_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/access_type.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/addr.go17
-rw-r--r--[-rwxr-xr-x]pkg/usermem/addr_range.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/addr_range_seq_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/bytes_io.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/bytes_io_unsafe.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_arm64.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_x86.go0
-rw-r--r--[-rwxr-xr-x]pkg/usermem/usermem_x86_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]pkg/waiter/waiter_list.go0
-rw-r--r--[-rwxr-xr-x]pkg/waiter/waiter_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/boot_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/boot_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/boot_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/compat_arm64.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/config_amd64.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/config_arm64.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/config_profile.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/filter_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/filter_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/filter_race_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/filter/filter_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/platforms/platforms_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/pprof/pprof.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/pprof/pprof_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/boot/vfs.go0
-rw-r--r--runsc/cgroup/cgroup.go50
-rw-r--r--[-rwxr-xr-x]runsc/cgroup/cgroup_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/cmd/cmd_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/cmd/statefile.go0
-rw-r--r--[-rwxr-xr-x]runsc/console/console_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/container/container_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/container/state_file.go0
-rw-r--r--[-rwxr-xr-x]runsc/flag/flag.go0
-rw-r--r--[-rwxr-xr-x]runsc/flag/flag_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/config_amd64.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/config_arm64.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/filter_amd64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/filter_arm64_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/filter_race_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/filter/filter_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_amd64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_amd64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_arm64_unsafe.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_arm64_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/fsgofer/fsgofer_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/sandbox/sandbox_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/sandbox/sandbox_unsafe_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]runsc/specutils/cri.go0
-rw-r--r--[-rwxr-xr-x]runsc/specutils/specutils_state_autogen.go0
-rw-r--r--[-rwxr-xr-x]tools/go_marshal/marshal/marshal.go0
-rw-r--r--[-rwxr-xr-x]tools/go_marshal/marshal/marshal_state_autogen.go0
686 files changed, 5599 insertions, 338 deletions
diff --git a/pkg/abi/abi_linux_state_autogen.go b/pkg/abi/abi_linux_state_autogen.go
index 327ef0e5c..327ef0e5c 100755..100644
--- a/pkg/abi/abi_linux_state_autogen.go
+++ b/pkg/abi/abi_linux_state_autogen.go
diff --git a/pkg/abi/abi_state_autogen.go b/pkg/abi/abi_state_autogen.go
index d54002c3b..d54002c3b 100755..100644
--- a/pkg/abi/abi_state_autogen.go
+++ b/pkg/abi/abi_state_autogen.go
diff --git a/pkg/abi/linux/arch_amd64.go b/pkg/abi/linux/arch_amd64.go
index 0be31e755..0be31e755 100755..100644
--- a/pkg/abi/linux/arch_amd64.go
+++ b/pkg/abi/linux/arch_amd64.go
diff --git a/pkg/abi/linux/epoll_amd64.go b/pkg/abi/linux/epoll_amd64.go
index 7e74b1143..7e74b1143 100755..100644
--- a/pkg/abi/linux/epoll_amd64.go
+++ b/pkg/abi/linux/epoll_amd64.go
diff --git a/pkg/abi/linux/epoll_arm64.go b/pkg/abi/linux/epoll_arm64.go
index a35939cc9..a35939cc9 100755..100644
--- a/pkg/abi/linux/epoll_arm64.go
+++ b/pkg/abi/linux/epoll_arm64.go
diff --git a/pkg/abi/linux/file_amd64.go b/pkg/abi/linux/file_amd64.go
index 6b72364ea..6b72364ea 100755..100644
--- a/pkg/abi/linux/file_amd64.go
+++ b/pkg/abi/linux/file_amd64.go
diff --git a/pkg/abi/linux/file_arm64.go b/pkg/abi/linux/file_arm64.go
index 6492c9038..6492c9038 100755..100644
--- a/pkg/abi/linux/file_arm64.go
+++ b/pkg/abi/linux/file_arm64.go
diff --git a/pkg/abi/linux/ioctl_tun.go b/pkg/abi/linux/ioctl_tun.go
index c59c9c136..c59c9c136 100755..100644
--- a/pkg/abi/linux/ioctl_tun.go
+++ b/pkg/abi/linux/ioctl_tun.go
diff --git a/pkg/abi/linux/linux_abi_autogen_unsafe.go b/pkg/abi/linux/linux_abi_autogen_unsafe.go
index 6d0ae0409..d351e2186 100755..100644
--- a/pkg/abi/linux/linux_abi_autogen_unsafe.go
+++ b/pkg/abi/linux/linux_abi_autogen_unsafe.go
@@ -129,7 +129,7 @@ func (s *Statx) Packed() bool {
// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
func (s *Statx) MarshalUnsafe(dst []byte) {
- if s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() {
+ if s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() {
safecopy.CopyIn(dst, unsafe.Pointer(s))
} else {
s.MarshalBytes(dst)
@@ -138,7 +138,7 @@ func (s *Statx) MarshalUnsafe(dst []byte) {
// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
func (s *Statx) UnmarshalUnsafe(src []byte) {
- if s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() {
+ if s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() {
safecopy.CopyOut(unsafe.Pointer(s), src)
} else {
s.UnmarshalBytes(src)
@@ -148,7 +148,7 @@ func (s *Statx) UnmarshalUnsafe(src []byte) {
// CopyOutN implements marshal.Marshallable.CopyOutN.
//go:nosplit
func (s *Statx) CopyOutN(task marshal.Task, addr usermem.Addr, limit int) (int, error) {
- if !s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() {
+ if !s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() {
// Type Statx doesn't have a packed layout in memory, fall back to MarshalBytes.
buf := task.CopyScratchBuffer(s.SizeBytes()) // escapes: okay.
s.MarshalBytes(buf) // escapes: fallback.
@@ -178,7 +178,7 @@ func (s *Statx) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
// CopyIn implements marshal.Marshallable.CopyIn.
//go:nosplit
func (s *Statx) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
- if !s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() {
+ if !s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() {
// Type Statx doesn't have a packed layout in memory, fall back to UnmarshalBytes.
buf := task.CopyScratchBuffer(s.SizeBytes()) // escapes: okay.
length, err := task.CopyInBytes(addr, buf) // escapes: okay.
@@ -204,7 +204,7 @@ func (s *Statx) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
// WriteTo implements io.WriterTo.WriteTo.
func (s *Statx) WriteTo(w io.Writer) (int64, error) {
- if !s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() {
+ if !s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() {
// Type Statx doesn't have a packed layout in memory, fall back to MarshalBytes.
buf := make([]byte, s.SizeBytes())
s.MarshalBytes(buf)
diff --git a/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go b/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go
index 1ab6ec3f5..ad674f6de 100755..100644
--- a/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go
+++ b/pkg/abi/linux/linux_amd64_abi_autogen_unsafe.go
@@ -293,7 +293,7 @@ func (s *Stat) Packed() bool {
// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
func (s *Stat) MarshalUnsafe(dst []byte) {
- if s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed() {
+ if s.MTime.Packed() && s.CTime.Packed() && s.ATime.Packed() {
safecopy.CopyIn(dst, unsafe.Pointer(s))
} else {
s.MarshalBytes(dst)
@@ -302,7 +302,7 @@ func (s *Stat) MarshalUnsafe(dst []byte) {
// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
func (s *Stat) UnmarshalUnsafe(src []byte) {
- if s.MTime.Packed() && s.CTime.Packed() && s.ATime.Packed() {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
safecopy.CopyOut(unsafe.Pointer(s), src)
} else {
s.UnmarshalBytes(src)
@@ -342,7 +342,7 @@ func (s *Stat) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) {
// CopyIn implements marshal.Marshallable.CopyIn.
//go:nosplit
func (s *Stat) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
- if !s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
+ if !s.MTime.Packed() && s.CTime.Packed() && s.ATime.Packed() {
// Type Stat doesn't have a packed layout in memory, fall back to UnmarshalBytes.
buf := task.CopyScratchBuffer(s.SizeBytes()) // escapes: okay.
length, err := task.CopyInBytes(addr, buf) // escapes: okay.
diff --git a/pkg/abi/linux/linux_amd64_state_autogen.go b/pkg/abi/linux/linux_amd64_state_autogen.go
index 58cabce4c..58cabce4c 100755..100644
--- a/pkg/abi/linux/linux_amd64_state_autogen.go
+++ b/pkg/abi/linux/linux_amd64_state_autogen.go
diff --git a/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go b/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go
index a5a5f78aa..69d75f6bc 100755..100644
--- a/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go
+++ b/pkg/abi/linux/linux_arm64_abi_autogen_unsafe.go
@@ -309,7 +309,7 @@ func (s *Stat) MarshalUnsafe(dst []byte) {
// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
func (s *Stat) UnmarshalUnsafe(src []byte) {
- if s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed() {
+ if s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
safecopy.CopyOut(unsafe.Pointer(s), src)
} else {
s.UnmarshalBytes(src)
@@ -375,7 +375,7 @@ func (s *Stat) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) {
// WriteTo implements io.WriterTo.WriteTo.
func (s *Stat) WriteTo(w io.Writer) (int64, error) {
- if !s.CTime.Packed() && s.ATime.Packed() && s.MTime.Packed() {
+ if !s.ATime.Packed() && s.MTime.Packed() && s.CTime.Packed() {
// Type Stat doesn't have a packed layout in memory, fall back to MarshalBytes.
buf := make([]byte, s.SizeBytes())
s.MarshalBytes(buf)
diff --git a/pkg/abi/linux/linux_arm64_state_autogen.go b/pkg/abi/linux/linux_arm64_state_autogen.go
index 301a5cb76..301a5cb76 100755..100644
--- a/pkg/abi/linux/linux_arm64_state_autogen.go
+++ b/pkg/abi/linux/linux_arm64_state_autogen.go
diff --git a/pkg/abi/linux/linux_state_autogen.go b/pkg/abi/linux/linux_state_autogen.go
index b8e488a11..b8e488a11 100755..100644
--- a/pkg/abi/linux/linux_state_autogen.go
+++ b/pkg/abi/linux/linux_state_autogen.go
diff --git a/pkg/abi/linux/ptrace_amd64.go b/pkg/abi/linux/ptrace_amd64.go
index ed3881e27..ed3881e27 100755..100644
--- a/pkg/abi/linux/ptrace_amd64.go
+++ b/pkg/abi/linux/ptrace_amd64.go
diff --git a/pkg/abi/linux/ptrace_arm64.go b/pkg/abi/linux/ptrace_arm64.go
index 6147738b3..6147738b3 100755..100644
--- a/pkg/abi/linux/ptrace_arm64.go
+++ b/pkg/abi/linux/ptrace_arm64.go
diff --git a/pkg/abi/linux/rseq.go b/pkg/abi/linux/rseq.go
index 76253ba30..76253ba30 100755..100644
--- a/pkg/abi/linux/rseq.go
+++ b/pkg/abi/linux/rseq.go
diff --git a/pkg/abi/linux/signalfd.go b/pkg/abi/linux/signalfd.go
index 85fad9956..85fad9956 100755..100644
--- a/pkg/abi/linux/signalfd.go
+++ b/pkg/abi/linux/signalfd.go
diff --git a/pkg/abi/linux/xattr.go b/pkg/abi/linux/xattr.go
index 99180b208..99180b208 100755..100644
--- a/pkg/abi/linux/xattr.go
+++ b/pkg/abi/linux/xattr.go
diff --git a/pkg/amutex/amutex_state_autogen.go b/pkg/amutex/amutex_state_autogen.go
index 5a09c71ed..5a09c71ed 100755..100644
--- a/pkg/amutex/amutex_state_autogen.go
+++ b/pkg/amutex/amutex_state_autogen.go
diff --git a/pkg/atomicbitops/atomicbitops.go b/pkg/atomicbitops/atomicbitops.go
index 1be081719..1be081719 100755..100644
--- a/pkg/atomicbitops/atomicbitops.go
+++ b/pkg/atomicbitops/atomicbitops.go
diff --git a/pkg/atomicbitops/atomicbitops_amd64.s b/pkg/atomicbitops/atomicbitops_amd64.s
index 54c887ee5..54c887ee5 100755..100644
--- a/pkg/atomicbitops/atomicbitops_amd64.s
+++ b/pkg/atomicbitops/atomicbitops_amd64.s
diff --git a/pkg/atomicbitops/atomicbitops_arm64.s b/pkg/atomicbitops/atomicbitops_arm64.s
index 5c780851b..5c780851b 100755..100644
--- a/pkg/atomicbitops/atomicbitops_arm64.s
+++ b/pkg/atomicbitops/atomicbitops_arm64.s
diff --git a/pkg/atomicbitops/atomicbitops_noasm.go b/pkg/atomicbitops/atomicbitops_noasm.go
index 3b2898256..3b2898256 100755..100644
--- a/pkg/atomicbitops/atomicbitops_noasm.go
+++ b/pkg/atomicbitops/atomicbitops_noasm.go
diff --git a/pkg/atomicbitops/atomicbitops_state_autogen.go b/pkg/atomicbitops/atomicbitops_state_autogen.go
index 06fcf712a..06fcf712a 100755..100644
--- a/pkg/atomicbitops/atomicbitops_state_autogen.go
+++ b/pkg/atomicbitops/atomicbitops_state_autogen.go
diff --git a/pkg/binary/binary_state_autogen.go b/pkg/binary/binary_state_autogen.go
index 4661a5982..4661a5982 100755..100644
--- a/pkg/binary/binary_state_autogen.go
+++ b/pkg/binary/binary_state_autogen.go
diff --git a/pkg/bits/bits32.go b/pkg/bits/bits32.go
index 28134a9e7..28134a9e7 100755..100644
--- a/pkg/bits/bits32.go
+++ b/pkg/bits/bits32.go
diff --git a/pkg/bits/bits64.go b/pkg/bits/bits64.go
index 73117b19b..73117b19b 100755..100644
--- a/pkg/bits/bits64.go
+++ b/pkg/bits/bits64.go
diff --git a/pkg/bits/bits_state_autogen.go b/pkg/bits/bits_state_autogen.go
index 22b8250c6..22b8250c6 100755..100644
--- a/pkg/bits/bits_state_autogen.go
+++ b/pkg/bits/bits_state_autogen.go
diff --git a/pkg/bits/uint64_arch.go b/pkg/bits/uint64_arch.go
index 9f23eff77..9f23eff77 100755..100644
--- a/pkg/bits/uint64_arch.go
+++ b/pkg/bits/uint64_arch.go
diff --git a/pkg/bits/uint64_arch_arm64_asm.s b/pkg/bits/uint64_arch_arm64_asm.s
index 814ba562d..814ba562d 100755..100644
--- a/pkg/bits/uint64_arch_arm64_asm.s
+++ b/pkg/bits/uint64_arch_arm64_asm.s
diff --git a/pkg/bpf/bpf_state_autogen.go b/pkg/bpf/bpf_state_autogen.go
index ae8a36d57..ae8a36d57 100755..100644
--- a/pkg/bpf/bpf_state_autogen.go
+++ b/pkg/bpf/bpf_state_autogen.go
diff --git a/pkg/buffer/buffer.go b/pkg/buffer/buffer.go
index c6d089fd9..c6d089fd9 100755..100644
--- a/pkg/buffer/buffer.go
+++ b/pkg/buffer/buffer.go
diff --git a/pkg/buffer/buffer_list.go b/pkg/buffer/buffer_list.go
index 15c7a74cc..15c7a74cc 100755..100644
--- a/pkg/buffer/buffer_list.go
+++ b/pkg/buffer/buffer_list.go
diff --git a/pkg/buffer/buffer_state_autogen.go b/pkg/buffer/buffer_state_autogen.go
index 2e6299f81..2e6299f81 100755..100644
--- a/pkg/buffer/buffer_state_autogen.go
+++ b/pkg/buffer/buffer_state_autogen.go
diff --git a/pkg/buffer/buffer_unsafe_state_autogen.go b/pkg/buffer/buffer_unsafe_state_autogen.go
index 5a5c40722..5a5c40722 100755..100644
--- a/pkg/buffer/buffer_unsafe_state_autogen.go
+++ b/pkg/buffer/buffer_unsafe_state_autogen.go
diff --git a/pkg/buffer/safemem.go b/pkg/buffer/safemem.go
index 0e5b86344..b789e56e9 100755..100644
--- a/pkg/buffer/safemem.go
+++ b/pkg/buffer/safemem.go
@@ -28,12 +28,11 @@ func (b *buffer) ReadBlock() safemem.Block {
return safemem.BlockFromSafeSlice(b.ReadSlice())
}
-// WriteFromBlocks implements safemem.Writer.WriteFromBlocks.
-//
-// This will advance the write index.
-func (v *View) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
- need := int(srcs.NumBytes())
- if need == 0 {
+// WriteFromSafememReader writes up to count bytes from r to v and advances the
+// write index by the number of bytes written. It calls r.ReadToBlocks() at
+// most once.
+func (v *View) WriteFromSafememReader(r safemem.Reader, count uint64) (uint64, error) {
+ if count == 0 {
return 0, nil
}
@@ -50,32 +49,33 @@ func (v *View) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
}
// Does the last block have sufficient capacity alone?
- if l := firstBuf.WriteSize(); l >= need {
- dst = safemem.BlockSeqOf(firstBuf.WriteBlock())
+ if l := uint64(firstBuf.WriteSize()); l >= count {
+ dst = safemem.BlockSeqOf(firstBuf.WriteBlock().TakeFirst64(count))
} else {
// Append blocks until sufficient.
- need -= l
+ count -= l
blocks = append(blocks, firstBuf.WriteBlock())
- for need > 0 {
+ for count > 0 {
emptyBuf := bufferPool.Get().(*buffer)
v.data.PushBack(emptyBuf)
- need -= emptyBuf.WriteSize()
- blocks = append(blocks, emptyBuf.WriteBlock())
+ block := emptyBuf.WriteBlock().TakeFirst64(count)
+ count -= uint64(block.Len())
+ blocks = append(blocks, block)
}
dst = safemem.BlockSeqFromSlice(blocks)
}
- // Perform the copy.
- n, err := safemem.CopySeq(dst, srcs)
+ // Perform I/O.
+ n, err := r.ReadToBlocks(dst)
v.size += int64(n)
// Update all indices.
- for left := int(n); left > 0; firstBuf = firstBuf.Next() {
- if l := firstBuf.WriteSize(); left >= l {
+ for left := n; left > 0; firstBuf = firstBuf.Next() {
+ if l := firstBuf.WriteSize(); left >= uint64(l) {
firstBuf.WriteMove(l) // Whole block.
- left -= l
+ left -= uint64(l)
} else {
- firstBuf.WriteMove(left) // Partial block.
+ firstBuf.WriteMove(int(left)) // Partial block.
left = 0
}
}
@@ -83,14 +83,16 @@ func (v *View) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
return n, err
}
-// ReadToBlocks implements safemem.Reader.ReadToBlocks.
-//
-// This will not advance the read index; the caller should follow
-// this call with a call to TrimFront in order to remove the read
-// data from the buffer. This is done to support pipe sematics.
-func (v *View) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
- need := int(dsts.NumBytes())
- if need == 0 {
+// WriteFromBlocks implements safemem.Writer.WriteFromBlocks. It advances the
+// write index by the number of bytes written.
+func (v *View) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
+ return v.WriteFromSafememReader(&safemem.BlockSeqReader{srcs}, srcs.NumBytes())
+}
+
+// ReadToSafememWriter reads up to count bytes from v to w. It does not advance
+// the read index. It calls w.WriteFromBlocks() at most once.
+func (v *View) ReadToSafememWriter(w safemem.Writer, count uint64) (uint64, error) {
+ if count == 0 {
return 0, nil
}
@@ -105,25 +107,27 @@ func (v *View) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
}
// Is all the data in a single block?
- if l := firstBuf.ReadSize(); l >= need {
- src = safemem.BlockSeqOf(firstBuf.ReadBlock())
+ if l := uint64(firstBuf.ReadSize()); l >= count {
+ src = safemem.BlockSeqOf(firstBuf.ReadBlock().TakeFirst64(count))
} else {
// Build a list of all the buffers.
- need -= l
+ count -= l
blocks = append(blocks, firstBuf.ReadBlock())
- for buf := firstBuf.Next(); buf != nil && need > 0; buf = buf.Next() {
- need -= buf.ReadSize()
- blocks = append(blocks, buf.ReadBlock())
+ for buf := firstBuf.Next(); buf != nil && count > 0; buf = buf.Next() {
+ block := buf.ReadBlock().TakeFirst64(count)
+ count -= uint64(block.Len())
+ blocks = append(blocks, block)
}
src = safemem.BlockSeqFromSlice(blocks)
}
- // Perform the copy.
- n, err := safemem.CopySeq(dsts, src)
-
- // See above: we would normally advance the read index here, but we
- // don't do that in order to support pipe semantics. We rely on a
- // separate call to TrimFront() in this case.
+ // Perform I/O. As documented, we don't advance the read index.
+ return w.WriteFromBlocks(src)
+}
- return n, err
+// ReadToBlocks implements safemem.Reader.ReadToBlocks. It does not advance the
+// read index by the number of bytes read, such that it's only safe to call if
+// the caller guarantees that ReadToBlocks will only be called once.
+func (v *View) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
+ return v.ReadToSafememWriter(&safemem.BlockSeqWriter{dsts}, dsts.NumBytes())
}
diff --git a/pkg/buffer/view.go b/pkg/buffer/view.go
index e6901eadb..e6901eadb 100755..100644
--- a/pkg/buffer/view.go
+++ b/pkg/buffer/view.go
diff --git a/pkg/buffer/view_unsafe.go b/pkg/buffer/view_unsafe.go
index d1ef39b26..d1ef39b26 100755..100644
--- a/pkg/buffer/view_unsafe.go
+++ b/pkg/buffer/view_unsafe.go
diff --git a/pkg/compressio/compressio_state_autogen.go b/pkg/compressio/compressio_state_autogen.go
index c47e0dd17..c47e0dd17 100755..100644
--- a/pkg/compressio/compressio_state_autogen.go
+++ b/pkg/compressio/compressio_state_autogen.go
diff --git a/pkg/context/context.go b/pkg/context/context.go
index 5319b6d8d..5319b6d8d 100755..100644
--- a/pkg/context/context.go
+++ b/pkg/context/context.go
diff --git a/pkg/context/context_state_autogen.go b/pkg/context/context_state_autogen.go
index fdc3c9fbb..fdc3c9fbb 100755..100644
--- a/pkg/context/context_state_autogen.go
+++ b/pkg/context/context_state_autogen.go
diff --git a/pkg/control/client/client_state_autogen.go b/pkg/control/client/client_state_autogen.go
index 9872f1107..9872f1107 100755..100644
--- a/pkg/control/client/client_state_autogen.go
+++ b/pkg/control/client/client_state_autogen.go
diff --git a/pkg/control/server/server_state_autogen.go b/pkg/control/server/server_state_autogen.go
index c236b8da5..c236b8da5 100755..100644
--- a/pkg/control/server/server_state_autogen.go
+++ b/pkg/control/server/server_state_autogen.go
diff --git a/pkg/cpuid/cpuid_arm64.go b/pkg/cpuid/cpuid_arm64.go
index 08381c1c0..08381c1c0 100755..100644
--- a/pkg/cpuid/cpuid_arm64.go
+++ b/pkg/cpuid/cpuid_arm64.go
diff --git a/pkg/cpuid/cpuid_arm64_state_autogen.go b/pkg/cpuid/cpuid_arm64_state_autogen.go
index 0e671d441..0e671d441 100755..100644
--- a/pkg/cpuid/cpuid_arm64_state_autogen.go
+++ b/pkg/cpuid/cpuid_arm64_state_autogen.go
diff --git a/pkg/cpuid/cpuid_state_autogen.go b/pkg/cpuid/cpuid_state_autogen.go
index 86206a6bf..86206a6bf 100755..100644
--- a/pkg/cpuid/cpuid_state_autogen.go
+++ b/pkg/cpuid/cpuid_state_autogen.go
diff --git a/pkg/cpuid/cpuid_x86.go b/pkg/cpuid/cpuid_x86.go
index 562f8f405..562f8f405 100755..100644
--- a/pkg/cpuid/cpuid_x86.go
+++ b/pkg/cpuid/cpuid_x86.go
diff --git a/pkg/cpuid/cpuid_x86_state_autogen.go b/pkg/cpuid/cpuid_x86_state_autogen.go
index 591868c88..591868c88 100755..100644
--- a/pkg/cpuid/cpuid_x86_state_autogen.go
+++ b/pkg/cpuid/cpuid_x86_state_autogen.go
diff --git a/pkg/eventchannel/eventchannel_go_proto/event.pb.go b/pkg/eventchannel/eventchannel_go_proto/event.pb.go
index bb71ed3e6..bb71ed3e6 100755..100644
--- a/pkg/eventchannel/eventchannel_go_proto/event.pb.go
+++ b/pkg/eventchannel/eventchannel_go_proto/event.pb.go
diff --git a/pkg/eventchannel/eventchannel_state_autogen.go b/pkg/eventchannel/eventchannel_state_autogen.go
index 50b9c54b3..50b9c54b3 100755..100644
--- a/pkg/eventchannel/eventchannel_state_autogen.go
+++ b/pkg/eventchannel/eventchannel_state_autogen.go
diff --git a/pkg/fd/fd_state_autogen.go b/pkg/fd/fd_state_autogen.go
index 5ad412976..5ad412976 100755..100644
--- a/pkg/fd/fd_state_autogen.go
+++ b/pkg/fd/fd_state_autogen.go
diff --git a/pkg/fdchannel/fdchannel_unsafe.go b/pkg/fdchannel/fdchannel_unsafe.go
index 367235be5..367235be5 100755..100644
--- a/pkg/fdchannel/fdchannel_unsafe.go
+++ b/pkg/fdchannel/fdchannel_unsafe.go
diff --git a/pkg/fdchannel/fdchannel_unsafe_state_autogen.go b/pkg/fdchannel/fdchannel_unsafe_state_autogen.go
index 61447d773..61447d773 100755..100644
--- a/pkg/fdchannel/fdchannel_unsafe_state_autogen.go
+++ b/pkg/fdchannel/fdchannel_unsafe_state_autogen.go
diff --git a/pkg/fdnotifier/fdnotifier_state_autogen.go b/pkg/fdnotifier/fdnotifier_state_autogen.go
index 527d44091..527d44091 100755..100644
--- a/pkg/fdnotifier/fdnotifier_state_autogen.go
+++ b/pkg/fdnotifier/fdnotifier_state_autogen.go
diff --git a/pkg/fdnotifier/fdnotifier_unsafe_state_autogen.go b/pkg/fdnotifier/fdnotifier_unsafe_state_autogen.go
index 527d44091..527d44091 100755..100644
--- a/pkg/fdnotifier/fdnotifier_unsafe_state_autogen.go
+++ b/pkg/fdnotifier/fdnotifier_unsafe_state_autogen.go
diff --git a/pkg/flipcall/ctrl_futex.go b/pkg/flipcall/ctrl_futex.go
index e7c3a3a0b..e7c3a3a0b 100755..100644
--- a/pkg/flipcall/ctrl_futex.go
+++ b/pkg/flipcall/ctrl_futex.go
diff --git a/pkg/flipcall/flipcall.go b/pkg/flipcall/flipcall.go
index 3cdb576e1..3cdb576e1 100755..100644
--- a/pkg/flipcall/flipcall.go
+++ b/pkg/flipcall/flipcall.go
diff --git a/pkg/flipcall/flipcall_linux_state_autogen.go b/pkg/flipcall/flipcall_linux_state_autogen.go
index ce37ac4e1..ce37ac4e1 100755..100644
--- a/pkg/flipcall/flipcall_linux_state_autogen.go
+++ b/pkg/flipcall/flipcall_linux_state_autogen.go
diff --git a/pkg/flipcall/flipcall_state_autogen.go b/pkg/flipcall/flipcall_state_autogen.go
index 0e03c2a65..0e03c2a65 100755..100644
--- a/pkg/flipcall/flipcall_state_autogen.go
+++ b/pkg/flipcall/flipcall_state_autogen.go
diff --git a/pkg/flipcall/flipcall_unsafe.go b/pkg/flipcall/flipcall_unsafe.go
index ac974b232..ac974b232 100755..100644
--- a/pkg/flipcall/flipcall_unsafe.go
+++ b/pkg/flipcall/flipcall_unsafe.go
diff --git a/pkg/flipcall/flipcall_unsafe_state_autogen.go b/pkg/flipcall/flipcall_unsafe_state_autogen.go
index 0e03c2a65..0e03c2a65 100755..100644
--- a/pkg/flipcall/flipcall_unsafe_state_autogen.go
+++ b/pkg/flipcall/flipcall_unsafe_state_autogen.go
diff --git a/pkg/flipcall/futex_linux.go b/pkg/flipcall/futex_linux.go
index 168c1ccff..168c1ccff 100755..100644
--- a/pkg/flipcall/futex_linux.go
+++ b/pkg/flipcall/futex_linux.go
diff --git a/pkg/flipcall/io.go b/pkg/flipcall/io.go
index 85e40b932..85e40b932 100755..100644
--- a/pkg/flipcall/io.go
+++ b/pkg/flipcall/io.go
diff --git a/pkg/flipcall/packet_window_allocator.go b/pkg/flipcall/packet_window_allocator.go
index af9cc3d21..af9cc3d21 100755..100644
--- a/pkg/flipcall/packet_window_allocator.go
+++ b/pkg/flipcall/packet_window_allocator.go
diff --git a/pkg/fspath/builder.go b/pkg/fspath/builder.go
index 6318d3874..6318d3874 100755..100644
--- a/pkg/fspath/builder.go
+++ b/pkg/fspath/builder.go
diff --git a/pkg/fspath/fspath.go b/pkg/fspath/fspath.go
index 4c983d5fd..4c983d5fd 100755..100644
--- a/pkg/fspath/fspath.go
+++ b/pkg/fspath/fspath.go
diff --git a/pkg/fspath/fspath_state_autogen.go b/pkg/fspath/fspath_state_autogen.go
index 6ceea8003..6ceea8003 100755..100644
--- a/pkg/fspath/fspath_state_autogen.go
+++ b/pkg/fspath/fspath_state_autogen.go
diff --git a/pkg/gate/gate_state_autogen.go b/pkg/gate/gate_state_autogen.go
index 221af659e..221af659e 100755..100644
--- a/pkg/gate/gate_state_autogen.go
+++ b/pkg/gate/gate_state_autogen.go
diff --git a/pkg/gohacks/gohacks_unsafe.go b/pkg/gohacks/gohacks_unsafe.go
index aad675172..aad675172 100755..100644
--- a/pkg/gohacks/gohacks_unsafe.go
+++ b/pkg/gohacks/gohacks_unsafe.go
diff --git a/pkg/gohacks/gohacks_unsafe_state_autogen.go b/pkg/gohacks/gohacks_unsafe_state_autogen.go
index c651ff01e..c651ff01e 100755..100644
--- a/pkg/gohacks/gohacks_unsafe_state_autogen.go
+++ b/pkg/gohacks/gohacks_unsafe_state_autogen.go
diff --git a/pkg/ilist/ilist_state_autogen.go b/pkg/ilist/ilist_state_autogen.go
index 4294bcb90..4294bcb90 100755..100644
--- a/pkg/ilist/ilist_state_autogen.go
+++ b/pkg/ilist/ilist_state_autogen.go
diff --git a/pkg/ilist/interface_list.go b/pkg/ilist/interface_list.go
index cabf46e3f..cabf46e3f 100755..100644
--- a/pkg/ilist/interface_list.go
+++ b/pkg/ilist/interface_list.go
diff --git a/pkg/linewriter/linewriter_state_autogen.go b/pkg/linewriter/linewriter_state_autogen.go
deleted file mode 100755
index 1cd1df9b8..000000000
--- a/pkg/linewriter/linewriter_state_autogen.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// automatically generated by stateify.
-
-package linewriter
diff --git a/pkg/memutil/memutil_unsafe_state_autogen.go b/pkg/memutil/memutil_unsafe_state_autogen.go
index 173297149..173297149 100755..100644
--- a/pkg/memutil/memutil_unsafe_state_autogen.go
+++ b/pkg/memutil/memutil_unsafe_state_autogen.go
diff --git a/pkg/metric/metric_go_proto/metric.pb.go b/pkg/metric/metric_go_proto/metric.pb.go
index 13f41a80d..13f41a80d 100755..100644
--- a/pkg/metric/metric_go_proto/metric.pb.go
+++ b/pkg/metric/metric_go_proto/metric.pb.go
diff --git a/pkg/metric/metric_state_autogen.go b/pkg/metric/metric_state_autogen.go
index 36e5ed81b..36e5ed81b 100755..100644
--- a/pkg/metric/metric_state_autogen.go
+++ b/pkg/metric/metric_state_autogen.go
diff --git a/pkg/p9/p9_state_autogen.go b/pkg/p9/p9_state_autogen.go
index bc9b1bd57..bc9b1bd57 100755..100644
--- a/pkg/p9/p9_state_autogen.go
+++ b/pkg/p9/p9_state_autogen.go
diff --git a/pkg/p9/transport_flipcall.go b/pkg/p9/transport_flipcall.go
index 38038abdf..38038abdf 100755..100644
--- a/pkg/p9/transport_flipcall.go
+++ b/pkg/p9/transport_flipcall.go
diff --git a/pkg/pool/pool.go b/pkg/pool/pool.go
index a1b2e0cfe..a1b2e0cfe 100755..100644
--- a/pkg/pool/pool.go
+++ b/pkg/pool/pool.go
diff --git a/pkg/pool/pool_state_autogen.go b/pkg/pool/pool_state_autogen.go
index 1f4164c00..1f4164c00 100755..100644
--- a/pkg/pool/pool_state_autogen.go
+++ b/pkg/pool/pool_state_autogen.go
diff --git a/pkg/procid/procid_state_autogen.go b/pkg/procid/procid_state_autogen.go
index 662988d79..662988d79 100755..100644
--- a/pkg/procid/procid_state_autogen.go
+++ b/pkg/procid/procid_state_autogen.go
diff --git a/pkg/rand/rand_linux_state_autogen.go b/pkg/rand/rand_linux_state_autogen.go
index f727c9314..f727c9314 100755..100644
--- a/pkg/rand/rand_linux_state_autogen.go
+++ b/pkg/rand/rand_linux_state_autogen.go
diff --git a/pkg/rand/rand_state_autogen.go b/pkg/rand/rand_state_autogen.go
index e0a5cd184..e0a5cd184 100755..100644
--- a/pkg/rand/rand_state_autogen.go
+++ b/pkg/rand/rand_state_autogen.go
diff --git a/pkg/refs/refs_state_autogen.go b/pkg/refs/refs_state_autogen.go
index 4c5591d30..4c5591d30 100755..100644
--- a/pkg/refs/refs_state_autogen.go
+++ b/pkg/refs/refs_state_autogen.go
diff --git a/pkg/refs/weak_ref_list.go b/pkg/refs/weak_ref_list.go
index 90433fb28..90433fb28 100755..100644
--- a/pkg/refs/weak_ref_list.go
+++ b/pkg/refs/weak_ref_list.go
diff --git a/pkg/safecopy/atomic_amd64.s b/pkg/safecopy/atomic_amd64.s
index a0cd78f33..a0cd78f33 100755..100644
--- a/pkg/safecopy/atomic_amd64.s
+++ b/pkg/safecopy/atomic_amd64.s
diff --git a/pkg/safecopy/atomic_arm64.s b/pkg/safecopy/atomic_arm64.s
index d58ed71f7..d58ed71f7 100755..100644
--- a/pkg/safecopy/atomic_arm64.s
+++ b/pkg/safecopy/atomic_arm64.s
diff --git a/pkg/safecopy/memclr_amd64.s b/pkg/safecopy/memclr_amd64.s
index 64cf32f05..64cf32f05 100755..100644
--- a/pkg/safecopy/memclr_amd64.s
+++ b/pkg/safecopy/memclr_amd64.s
diff --git a/pkg/safecopy/memclr_arm64.s b/pkg/safecopy/memclr_arm64.s
index 7361b9067..7361b9067 100755..100644
--- a/pkg/safecopy/memclr_arm64.s
+++ b/pkg/safecopy/memclr_arm64.s
diff --git a/pkg/safecopy/memcpy_amd64.s b/pkg/safecopy/memcpy_amd64.s
index 00b46c18f..00b46c18f 100755..100644
--- a/pkg/safecopy/memcpy_amd64.s
+++ b/pkg/safecopy/memcpy_amd64.s
diff --git a/pkg/safecopy/memcpy_arm64.s b/pkg/safecopy/memcpy_arm64.s
index e7e541565..e7e541565 100755..100644
--- a/pkg/safecopy/memcpy_arm64.s
+++ b/pkg/safecopy/memcpy_arm64.s
diff --git a/pkg/safecopy/safecopy.go b/pkg/safecopy/safecopy.go
index 2fb7e5809..2fb7e5809 100755..100644
--- a/pkg/safecopy/safecopy.go
+++ b/pkg/safecopy/safecopy.go
diff --git a/pkg/safecopy/safecopy_state_autogen.go b/pkg/safecopy/safecopy_state_autogen.go
index 791eef959..791eef959 100755..100644
--- a/pkg/safecopy/safecopy_state_autogen.go
+++ b/pkg/safecopy/safecopy_state_autogen.go
diff --git a/pkg/safecopy/safecopy_unsafe.go b/pkg/safecopy/safecopy_unsafe.go
index 41dd567f3..41dd567f3 100755..100644
--- a/pkg/safecopy/safecopy_unsafe.go
+++ b/pkg/safecopy/safecopy_unsafe.go
diff --git a/pkg/safecopy/safecopy_unsafe_state_autogen.go b/pkg/safecopy/safecopy_unsafe_state_autogen.go
index 791eef959..791eef959 100755..100644
--- a/pkg/safecopy/safecopy_unsafe_state_autogen.go
+++ b/pkg/safecopy/safecopy_unsafe_state_autogen.go
diff --git a/pkg/safecopy/sighandler_amd64.s b/pkg/safecopy/sighandler_amd64.s
index 475ae48e9..475ae48e9 100755..100644
--- a/pkg/safecopy/sighandler_amd64.s
+++ b/pkg/safecopy/sighandler_amd64.s
diff --git a/pkg/safecopy/sighandler_arm64.s b/pkg/safecopy/sighandler_arm64.s
index 53e4ac2c1..53e4ac2c1 100755..100644
--- a/pkg/safecopy/sighandler_arm64.s
+++ b/pkg/safecopy/sighandler_arm64.s
diff --git a/pkg/safemem/block_unsafe.go b/pkg/safemem/block_unsafe.go
index e7fd30743..e7fd30743 100755..100644
--- a/pkg/safemem/block_unsafe.go
+++ b/pkg/safemem/block_unsafe.go
diff --git a/pkg/safemem/io.go b/pkg/safemem/io.go
index f039a5c34..f039a5c34 100755..100644
--- a/pkg/safemem/io.go
+++ b/pkg/safemem/io.go
diff --git a/pkg/safemem/safemem.go b/pkg/safemem/safemem.go
index 3e70d33a2..3e70d33a2 100755..100644
--- a/pkg/safemem/safemem.go
+++ b/pkg/safemem/safemem.go
diff --git a/pkg/safemem/safemem_state_autogen.go b/pkg/safemem/safemem_state_autogen.go
index 66d53f22d..66d53f22d 100755..100644
--- a/pkg/safemem/safemem_state_autogen.go
+++ b/pkg/safemem/safemem_state_autogen.go
diff --git a/pkg/safemem/safemem_unsafe_state_autogen.go b/pkg/safemem/safemem_unsafe_state_autogen.go
index 66d53f22d..66d53f22d 100755..100644
--- a/pkg/safemem/safemem_unsafe_state_autogen.go
+++ b/pkg/safemem/safemem_unsafe_state_autogen.go
diff --git a/pkg/safemem/seq_unsafe.go b/pkg/safemem/seq_unsafe.go
index f5f0574f8..f5f0574f8 100755..100644
--- a/pkg/safemem/seq_unsafe.go
+++ b/pkg/safemem/seq_unsafe.go
diff --git a/pkg/seccomp/seccomp_amd64_state_autogen.go b/pkg/seccomp/seccomp_amd64_state_autogen.go
index 27a96018b..27a96018b 100755..100644
--- a/pkg/seccomp/seccomp_amd64_state_autogen.go
+++ b/pkg/seccomp/seccomp_amd64_state_autogen.go
diff --git a/pkg/seccomp/seccomp_arm64_state_autogen.go b/pkg/seccomp/seccomp_arm64_state_autogen.go
index 96c64c23d..96c64c23d 100755..100644
--- a/pkg/seccomp/seccomp_arm64_state_autogen.go
+++ b/pkg/seccomp/seccomp_arm64_state_autogen.go
diff --git a/pkg/seccomp/seccomp_state_autogen.go b/pkg/seccomp/seccomp_state_autogen.go
index e16b5d7c2..e16b5d7c2 100755..100644
--- a/pkg/seccomp/seccomp_state_autogen.go
+++ b/pkg/seccomp/seccomp_state_autogen.go
diff --git a/pkg/seccomp/seccomp_unsafe_state_autogen.go b/pkg/seccomp/seccomp_unsafe_state_autogen.go
index e16b5d7c2..e16b5d7c2 100755..100644
--- a/pkg/seccomp/seccomp_unsafe_state_autogen.go
+++ b/pkg/seccomp/seccomp_unsafe_state_autogen.go
diff --git a/pkg/secio/secio_state_autogen.go b/pkg/secio/secio_state_autogen.go
index 372ac4b92..372ac4b92 100755..100644
--- a/pkg/secio/secio_state_autogen.go
+++ b/pkg/secio/secio_state_autogen.go
diff --git a/pkg/sentry/arch/arch_aarch64.go b/pkg/sentry/arch/arch_aarch64.go
index 343f81f59..343f81f59 100755..100644
--- a/pkg/sentry/arch/arch_aarch64.go
+++ b/pkg/sentry/arch/arch_aarch64.go
diff --git a/pkg/sentry/arch/arch_aarch64_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_aarch64_abi_autogen_unsafe.go
index f7a3597d4..f7a3597d4 100755..100644
--- a/pkg/sentry/arch/arch_aarch64_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_aarch64_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_aarch64_state_autogen.go b/pkg/sentry/arch/arch_aarch64_state_autogen.go
index 49f2e3d67..49f2e3d67 100755..100644
--- a/pkg/sentry/arch/arch_aarch64_state_autogen.go
+++ b/pkg/sentry/arch/arch_aarch64_state_autogen.go
diff --git a/pkg/sentry/arch/arch_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_abi_autogen_unsafe.go
index 98cc11f75..98cc11f75 100755..100644
--- a/pkg/sentry/arch/arch_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_amd64_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_amd64_abi_autogen_unsafe.go
index 8eadb6e22..8eadb6e22 100755..100644
--- a/pkg/sentry/arch/arch_amd64_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_amd64_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_amd64_state_autogen.go b/pkg/sentry/arch/arch_amd64_state_autogen.go
index 73c523c90..73c523c90 100755..100644
--- a/pkg/sentry/arch/arch_amd64_state_autogen.go
+++ b/pkg/sentry/arch/arch_amd64_state_autogen.go
diff --git a/pkg/sentry/arch/arch_arm64.go b/pkg/sentry/arch/arch_arm64.go
index ada7ac7b8..ada7ac7b8 100755..100644
--- a/pkg/sentry/arch/arch_arm64.go
+++ b/pkg/sentry/arch/arch_arm64.go
diff --git a/pkg/sentry/arch/arch_arm64_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_arm64_abi_autogen_unsafe.go
index c8e4c7c24..c8e4c7c24 100755..100644
--- a/pkg/sentry/arch/arch_arm64_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_arm64_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_arm64_state_autogen.go b/pkg/sentry/arch/arch_arm64_state_autogen.go
index 9c6dfdf2e..9c6dfdf2e 100755..100644
--- a/pkg/sentry/arch/arch_arm64_state_autogen.go
+++ b/pkg/sentry/arch/arch_arm64_state_autogen.go
diff --git a/pkg/sentry/arch/arch_state_autogen.go b/pkg/sentry/arch/arch_state_autogen.go
index 82f4d9d73..82f4d9d73 100755..100644
--- a/pkg/sentry/arch/arch_state_autogen.go
+++ b/pkg/sentry/arch/arch_state_autogen.go
diff --git a/pkg/sentry/arch/arch_x86_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_x86_abi_autogen_unsafe.go
index 521dcbb06..521dcbb06 100755..100644
--- a/pkg/sentry/arch/arch_x86_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_x86_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_x86_impl.go b/pkg/sentry/arch/arch_x86_impl.go
index 0c73fcbfb..0c73fcbfb 100755..100644
--- a/pkg/sentry/arch/arch_x86_impl.go
+++ b/pkg/sentry/arch/arch_x86_impl.go
diff --git a/pkg/sentry/arch/arch_x86_impl_abi_autogen_unsafe.go b/pkg/sentry/arch/arch_x86_impl_abi_autogen_unsafe.go
index 4357dc093..4357dc093 100755..100644
--- a/pkg/sentry/arch/arch_x86_impl_abi_autogen_unsafe.go
+++ b/pkg/sentry/arch/arch_x86_impl_abi_autogen_unsafe.go
diff --git a/pkg/sentry/arch/arch_x86_impl_state_autogen.go b/pkg/sentry/arch/arch_x86_impl_state_autogen.go
index 7303bb17f..7303bb17f 100755..100644
--- a/pkg/sentry/arch/arch_x86_impl_state_autogen.go
+++ b/pkg/sentry/arch/arch_x86_impl_state_autogen.go
diff --git a/pkg/sentry/arch/arch_x86_state_autogen.go b/pkg/sentry/arch/arch_x86_state_autogen.go
index 20eaa99a6..20eaa99a6 100755..100644
--- a/pkg/sentry/arch/arch_x86_state_autogen.go
+++ b/pkg/sentry/arch/arch_x86_state_autogen.go
diff --git a/pkg/sentry/arch/registers_go_proto/registers.pb.go b/pkg/sentry/arch/registers_go_proto/registers.pb.go
index c4e9584b5..c4e9584b5 100755..100644
--- a/pkg/sentry/arch/registers_go_proto/registers.pb.go
+++ b/pkg/sentry/arch/registers_go_proto/registers.pb.go
diff --git a/pkg/sentry/arch/signal.go b/pkg/sentry/arch/signal.go
index c9fb55d00..c9fb55d00 100755..100644
--- a/pkg/sentry/arch/signal.go
+++ b/pkg/sentry/arch/signal.go
diff --git a/pkg/sentry/arch/signal_arm64.go b/pkg/sentry/arch/signal_arm64.go
index 642c79dda..642c79dda 100755..100644
--- a/pkg/sentry/arch/signal_arm64.go
+++ b/pkg/sentry/arch/signal_arm64.go
diff --git a/pkg/sentry/arch/syscalls_arm64.go b/pkg/sentry/arch/syscalls_arm64.go
index 95dfd1e90..95dfd1e90 100755..100644
--- a/pkg/sentry/arch/syscalls_arm64.go
+++ b/pkg/sentry/arch/syscalls_arm64.go
diff --git a/pkg/sentry/control/control_state_autogen.go b/pkg/sentry/control/control_state_autogen.go
index bd5797221..bd5797221 100755..100644
--- a/pkg/sentry/control/control_state_autogen.go
+++ b/pkg/sentry/control/control_state_autogen.go
diff --git a/pkg/sentry/device/device_state_autogen.go b/pkg/sentry/device/device_state_autogen.go
index dd41a5659..dd41a5659 100755..100644
--- a/pkg/sentry/device/device_state_autogen.go
+++ b/pkg/sentry/device/device_state_autogen.go
diff --git a/pkg/sentry/devices/memdev/full.go b/pkg/sentry/devices/memdev/full.go
index c7e197691..c7e197691 100755..100644
--- a/pkg/sentry/devices/memdev/full.go
+++ b/pkg/sentry/devices/memdev/full.go
diff --git a/pkg/sentry/devices/memdev/memdev.go b/pkg/sentry/devices/memdev/memdev.go
index 5759900c4..5759900c4 100755..100644
--- a/pkg/sentry/devices/memdev/memdev.go
+++ b/pkg/sentry/devices/memdev/memdev.go
diff --git a/pkg/sentry/devices/memdev/memdev_state_autogen.go b/pkg/sentry/devices/memdev/memdev_state_autogen.go
index 2676fbbe5..2676fbbe5 100755..100644
--- a/pkg/sentry/devices/memdev/memdev_state_autogen.go
+++ b/pkg/sentry/devices/memdev/memdev_state_autogen.go
diff --git a/pkg/sentry/devices/memdev/null.go b/pkg/sentry/devices/memdev/null.go
index 33d060d02..33d060d02 100755..100644
--- a/pkg/sentry/devices/memdev/null.go
+++ b/pkg/sentry/devices/memdev/null.go
diff --git a/pkg/sentry/devices/memdev/random.go b/pkg/sentry/devices/memdev/random.go
index acfa23149..acfa23149 100755..100644
--- a/pkg/sentry/devices/memdev/random.go
+++ b/pkg/sentry/devices/memdev/random.go
diff --git a/pkg/sentry/devices/memdev/zero.go b/pkg/sentry/devices/memdev/zero.go
index 3b1372b9e..3b1372b9e 100755..100644
--- a/pkg/sentry/devices/memdev/zero.go
+++ b/pkg/sentry/devices/memdev/zero.go
diff --git a/pkg/sentry/fdimport/fdimport.go b/pkg/sentry/fdimport/fdimport.go
index a4199f9e9..a4199f9e9 100755..100644
--- a/pkg/sentry/fdimport/fdimport.go
+++ b/pkg/sentry/fdimport/fdimport.go
diff --git a/pkg/sentry/fdimport/fdimport_state_autogen.go b/pkg/sentry/fdimport/fdimport_state_autogen.go
index fbb89b276..fbb89b276 100755..100644
--- a/pkg/sentry/fdimport/fdimport_state_autogen.go
+++ b/pkg/sentry/fdimport/fdimport_state_autogen.go
diff --git a/pkg/sentry/fs/anon/anon_state_autogen.go b/pkg/sentry/fs/anon/anon_state_autogen.go
index b2b1a466e..b2b1a466e 100755..100644
--- a/pkg/sentry/fs/anon/anon_state_autogen.go
+++ b/pkg/sentry/fs/anon/anon_state_autogen.go
diff --git a/pkg/sentry/fs/dev/dev_state_autogen.go b/pkg/sentry/fs/dev/dev_state_autogen.go
index 272f02672..272f02672 100755..100644
--- a/pkg/sentry/fs/dev/dev_state_autogen.go
+++ b/pkg/sentry/fs/dev/dev_state_autogen.go
diff --git a/pkg/sentry/fs/dev/net_tun.go b/pkg/sentry/fs/dev/net_tun.go
index dc7ad075a..dc7ad075a 100755..100644
--- a/pkg/sentry/fs/dev/net_tun.go
+++ b/pkg/sentry/fs/dev/net_tun.go
diff --git a/pkg/sentry/fs/dirent_list.go b/pkg/sentry/fs/dirent_list.go
index ecbbd7883..ecbbd7883 100755..100644
--- a/pkg/sentry/fs/dirent_list.go
+++ b/pkg/sentry/fs/dirent_list.go
diff --git a/pkg/sentry/fs/event_list.go b/pkg/sentry/fs/event_list.go
index 167fdf906..167fdf906 100755..100644
--- a/pkg/sentry/fs/event_list.go
+++ b/pkg/sentry/fs/event_list.go
diff --git a/pkg/sentry/fs/fdpipe/fdpipe_state_autogen.go b/pkg/sentry/fs/fdpipe/fdpipe_state_autogen.go
index 9ed7a3d41..9ed7a3d41 100755..100644
--- a/pkg/sentry/fs/fdpipe/fdpipe_state_autogen.go
+++ b/pkg/sentry/fs/fdpipe/fdpipe_state_autogen.go
diff --git a/pkg/sentry/fs/fs_state_autogen.go b/pkg/sentry/fs/fs_state_autogen.go
index 502a90d71..502a90d71 100755..100644
--- a/pkg/sentry/fs/fs_state_autogen.go
+++ b/pkg/sentry/fs/fs_state_autogen.go
diff --git a/pkg/sentry/fs/fsutil/dirty_set_impl.go b/pkg/sentry/fs/fsutil/dirty_set_impl.go
index 2510b81b3..8d462c412 100755..100644
--- a/pkg/sentry/fs/fsutil/dirty_set_impl.go
+++ b/pkg/sentry/fs/fsutil/dirty_set_impl.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const DirtytrackGaps = 0
+
+var _ = uint8(DirtytrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type DirtydynamicGap [DirtytrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *DirtydynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *DirtydynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *DirtySet) Insert(gap DirtyGapIterator, r __generics_imported0.MappableR
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (dirtySetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := DirtytrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (dirtySetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *DirtySet) Insert(gap DirtyGapIterator, r __generics_imported0.MappableR
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (dirtySetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := DirtytrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *DirtySet) InsertWithoutMerging(gap DirtyGapIterator, r __generics_impor
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *DirtySet) InsertWithoutMergingUnchecked(gap DirtyGapIterator, r __generics_imported0.MappableRange, val DirtyInfo) DirtyIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := DirtytrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return DirtyIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *DirtySet) Remove(seg DirtyIterator) DirtyGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if DirtytrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
dirtySetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if DirtytrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(DirtyGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *DirtySet) MergeUnchecked(first, second DirtyIterator) DirtyIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type Dirtynode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap DirtydynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [DirtymaxDegree - 1]__generics_imported0.MappableRange
@@ -607,12 +663,12 @@ func (n *Dirtynode) nextSibling() *Dirtynode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *Dirtynode) rebalanceBeforeInsert(gap DirtyGapIterator) DirtyGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < DirtymaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &Dirtynode{
@@ -648,6 +704,11 @@ func (n *Dirtynode) rebalanceBeforeInsert(gap DirtyGapIterator) DirtyGapIterator
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if DirtytrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *Dirtynode) rebalanceBeforeInsert(gap DirtyGapIterator) DirtyGapIterator
}
n.nrSegments = DirtyminDegree - 1
+ if DirtytrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *Dirtynode) rebalanceAfterRemove(gap DirtyGapIterator) DirtyGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if DirtytrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return DirtyGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *Dirtynode) rebalanceAfterRemove(gap DirtyGapIterator) DirtyGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if DirtytrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return DirtyGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *Dirtynode) rebalanceAfterRemove(gap DirtyGapIterator) DirtyGapIterator
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return DirtyGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *Dirtynode) rebalanceAfterRemove(gap DirtyGapIterator) DirtyGapIterator
p.children[p.nrSegments] = nil
p.nrSegments--
+ if DirtytrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *Dirtynode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *Dirtynode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *Dirtynode) calculateMaxGapLeaf() uint64 {
+ max := DirtyGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (DirtyGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *Dirtynode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Dirtynode) searchFirstLargeEnoughGap(minSize uint64) DirtyGapIterator {
+ if n.maxGap.Get() < minSize {
+ return DirtyGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := DirtyGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Dirtynode) searchLastLargeEnoughGap(minSize uint64) DirtyGapIterator {
+ if n.maxGap.Get() < minSize {
+ return DirtyGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := DirtyGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap DirtyGapIterator) NextGap() DirtyGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap DirtyGapIterator) NextLargeEnoughGap(minSize uint64) DirtyGapIterator {
+ if DirtytrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap DirtyGapIterator) nextLargeEnoughGapHelper(minSize uint64) DirtyGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return DirtyGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap DirtyGapIterator) PrevLargeEnoughGap(minSize uint64) DirtyGapIterator {
+ if DirtytrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap DirtyGapIterator) prevLargeEnoughGapHelper(minSize uint64) DirtyGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return DirtyGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *Dirtynode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if DirtytrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *DirtySet) ImportSortedSlices(sds *DirtySegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *DirtySet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.MappableRange, DirtyInfo) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *DirtySet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *DirtySet) saveRoot() *DirtySegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/fs/fsutil/file_range_set_impl.go b/pkg/sentry/fs/fsutil/file_range_set_impl.go
index 01e7a2401..e5b6d1041 100755..100644
--- a/pkg/sentry/fs/fsutil/file_range_set_impl.go
+++ b/pkg/sentry/fs/fsutil/file_range_set_impl.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const FileRangetrackGaps = 0
+
+var _ = uint8(FileRangetrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type FileRangedynamicGap [FileRangetrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *FileRangedynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *FileRangedynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *FileRangeSet) Insert(gap FileRangeGapIterator, r __generics_imported0.M
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (FileRangeSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := FileRangetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (FileRangeSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *FileRangeSet) Insert(gap FileRangeGapIterator, r __generics_imported0.M
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (FileRangeSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := FileRangetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *FileRangeSet) InsertWithoutMerging(gap FileRangeGapIterator, r __generi
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *FileRangeSet) InsertWithoutMergingUnchecked(gap FileRangeGapIterator, r __generics_imported0.MappableRange, val uint64) FileRangeIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := FileRangetrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return FileRangeIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *FileRangeSet) Remove(seg FileRangeIterator) FileRangeGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if FileRangetrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
FileRangeSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if FileRangetrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(FileRangeGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *FileRangeSet) MergeUnchecked(first, second FileRangeIterator) FileRange
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type FileRangenode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap FileRangedynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [FileRangemaxDegree - 1]__generics_imported0.MappableRange
@@ -607,12 +663,12 @@ func (n *FileRangenode) nextSibling() *FileRangenode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *FileRangenode) rebalanceBeforeInsert(gap FileRangeGapIterator) FileRangeGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < FileRangemaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &FileRangenode{
@@ -648,6 +704,11 @@ func (n *FileRangenode) rebalanceBeforeInsert(gap FileRangeGapIterator) FileRang
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if FileRangetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *FileRangenode) rebalanceBeforeInsert(gap FileRangeGapIterator) FileRang
}
n.nrSegments = FileRangeminDegree - 1
+ if FileRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *FileRangenode) rebalanceAfterRemove(gap FileRangeGapIterator) FileRange
}
n.nrSegments++
sibling.nrSegments--
+
+ if FileRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return FileRangeGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *FileRangenode) rebalanceAfterRemove(gap FileRangeGapIterator) FileRange
}
n.nrSegments++
sibling.nrSegments--
+
+ if FileRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return FileRangeGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *FileRangenode) rebalanceAfterRemove(gap FileRangeGapIterator) FileRange
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return FileRangeGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *FileRangenode) rebalanceAfterRemove(gap FileRangeGapIterator) FileRange
p.children[p.nrSegments] = nil
p.nrSegments--
+ if FileRangetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *FileRangenode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *FileRangenode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *FileRangenode) calculateMaxGapLeaf() uint64 {
+ max := FileRangeGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (FileRangeGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *FileRangenode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *FileRangenode) searchFirstLargeEnoughGap(minSize uint64) FileRangeGapIterator {
+ if n.maxGap.Get() < minSize {
+ return FileRangeGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := FileRangeGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *FileRangenode) searchLastLargeEnoughGap(minSize uint64) FileRangeGapIterator {
+ if n.maxGap.Get() < minSize {
+ return FileRangeGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := FileRangeGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap FileRangeGapIterator) NextGap() FileRangeGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap FileRangeGapIterator) NextLargeEnoughGap(minSize uint64) FileRangeGapIterator {
+ if FileRangetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap FileRangeGapIterator) nextLargeEnoughGapHelper(minSize uint64) FileRangeGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return FileRangeGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap FileRangeGapIterator) PrevLargeEnoughGap(minSize uint64) FileRangeGapIterator {
+ if FileRangetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap FileRangeGapIterator) prevLargeEnoughGapHelper(minSize uint64) FileRangeGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return FileRangeGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *FileRangenode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if FileRangetrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *FileRangeSet) ImportSortedSlices(sds *FileRangeSegmentDataSlices) error
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *FileRangeSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.MappableRange, uint64) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *FileRangeSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *FileRangeSet) saveRoot() *FileRangeSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/fs/fsutil/frame_ref_set.go b/pkg/sentry/fs/fsutil/frame_ref_set.go
index 6564fd0c6..dd6f5aba6 100644
--- a/pkg/sentry/fs/fsutil/frame_ref_set.go
+++ b/pkg/sentry/fs/fsutil/frame_ref_set.go
@@ -18,6 +18,7 @@ import (
"math"
"gvisor.dev/gvisor/pkg/sentry/platform"
+ "gvisor.dev/gvisor/pkg/sentry/usage"
)
// FrameRefSetFunctions implements segment.Functions for FrameRefSet.
@@ -49,3 +50,42 @@ func (FrameRefSetFunctions) Merge(_ platform.FileRange, val1 uint64, _ platform.
func (FrameRefSetFunctions) Split(_ platform.FileRange, val uint64, _ uint64) (uint64, uint64) {
return val, val
}
+
+// IncRefAndAccount adds a reference on the range fr. All newly inserted segments
+// are accounted as host page cache memory mappings.
+func (refs *FrameRefSet) IncRefAndAccount(fr platform.FileRange) {
+ seg, gap := refs.Find(fr.Start)
+ for {
+ switch {
+ case seg.Ok() && seg.Start() < fr.End:
+ seg = refs.Isolate(seg, fr)
+ seg.SetValue(seg.Value() + 1)
+ seg, gap = seg.NextNonEmpty()
+ case gap.Ok() && gap.Start() < fr.End:
+ newRange := gap.Range().Intersect(fr)
+ usage.MemoryAccounting.Inc(newRange.Length(), usage.Mapped)
+ seg, gap = refs.InsertWithoutMerging(gap, newRange, 1).NextNonEmpty()
+ default:
+ refs.MergeAdjacent(fr)
+ return
+ }
+ }
+}
+
+// DecRefAndAccount removes a reference on the range fr and untracks segments
+// that are removed from memory accounting.
+func (refs *FrameRefSet) DecRefAndAccount(fr platform.FileRange) {
+ seg := refs.FindSegment(fr.Start)
+
+ for seg.Ok() && seg.Start() < fr.End {
+ seg = refs.Isolate(seg, fr)
+ if old := seg.Value(); old == 1 {
+ usage.MemoryAccounting.Dec(seg.Range().Length(), usage.Mapped)
+ seg = refs.Remove(seg).NextSegment()
+ } else {
+ seg.SetValue(old - 1)
+ seg = seg.NextSegment()
+ }
+ }
+ refs.MergeAdjacent(fr)
+}
diff --git a/pkg/sentry/fs/fsutil/frame_ref_set_impl.go b/pkg/sentry/fs/fsutil/frame_ref_set_impl.go
index 88695dbd1..413b037d1 100755..100644
--- a/pkg/sentry/fs/fsutil/frame_ref_set_impl.go
+++ b/pkg/sentry/fs/fsutil/frame_ref_set_impl.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const FrameReftrackGaps = 0
+
+var _ = uint8(FrameReftrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type FrameRefdynamicGap [FrameReftrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *FrameRefdynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *FrameRefdynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *FrameRefSet) Insert(gap FrameRefGapIterator, r __generics_imported0.Fil
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (FrameRefSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := FrameReftrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (FrameRefSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *FrameRefSet) Insert(gap FrameRefGapIterator, r __generics_imported0.Fil
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (FrameRefSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := FrameReftrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *FrameRefSet) InsertWithoutMerging(gap FrameRefGapIterator, r __generics
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *FrameRefSet) InsertWithoutMergingUnchecked(gap FrameRefGapIterator, r __generics_imported0.FileRange, val uint64) FrameRefIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := FrameReftrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return FrameRefIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *FrameRefSet) Remove(seg FrameRefIterator) FrameRefGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if FrameReftrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
FrameRefSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if FrameReftrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(FrameRefGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *FrameRefSet) MergeUnchecked(first, second FrameRefIterator) FrameRefIte
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type FrameRefnode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap FrameRefdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [FrameRefmaxDegree - 1]__generics_imported0.FileRange
@@ -607,12 +663,12 @@ func (n *FrameRefnode) nextSibling() *FrameRefnode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *FrameRefnode) rebalanceBeforeInsert(gap FrameRefGapIterator) FrameRefGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < FrameRefmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &FrameRefnode{
@@ -648,6 +704,11 @@ func (n *FrameRefnode) rebalanceBeforeInsert(gap FrameRefGapIterator) FrameRefGa
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if FrameReftrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *FrameRefnode) rebalanceBeforeInsert(gap FrameRefGapIterator) FrameRefGa
}
n.nrSegments = FrameRefminDegree - 1
+ if FrameReftrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *FrameRefnode) rebalanceAfterRemove(gap FrameRefGapIterator) FrameRefGap
}
n.nrSegments++
sibling.nrSegments--
+
+ if FrameReftrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return FrameRefGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *FrameRefnode) rebalanceAfterRemove(gap FrameRefGapIterator) FrameRefGap
}
n.nrSegments++
sibling.nrSegments--
+
+ if FrameReftrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return FrameRefGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *FrameRefnode) rebalanceAfterRemove(gap FrameRefGapIterator) FrameRefGap
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return FrameRefGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *FrameRefnode) rebalanceAfterRemove(gap FrameRefGapIterator) FrameRefGap
p.children[p.nrSegments] = nil
p.nrSegments--
+ if FrameReftrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *FrameRefnode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *FrameRefnode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *FrameRefnode) calculateMaxGapLeaf() uint64 {
+ max := FrameRefGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (FrameRefGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *FrameRefnode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *FrameRefnode) searchFirstLargeEnoughGap(minSize uint64) FrameRefGapIterator {
+ if n.maxGap.Get() < minSize {
+ return FrameRefGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := FrameRefGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *FrameRefnode) searchLastLargeEnoughGap(minSize uint64) FrameRefGapIterator {
+ if n.maxGap.Get() < minSize {
+ return FrameRefGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := FrameRefGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap FrameRefGapIterator) NextGap() FrameRefGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap FrameRefGapIterator) NextLargeEnoughGap(minSize uint64) FrameRefGapIterator {
+ if FrameReftrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap FrameRefGapIterator) nextLargeEnoughGapHelper(minSize uint64) FrameRefGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return FrameRefGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap FrameRefGapIterator) PrevLargeEnoughGap(minSize uint64) FrameRefGapIterator {
+ if FrameReftrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap FrameRefGapIterator) prevLargeEnoughGapHelper(minSize uint64) FrameRefGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return FrameRefGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *FrameRefnode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if FrameReftrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *FrameRefSet) ImportSortedSlices(sds *FrameRefSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *FrameRefSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.FileRange, uint64) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *FrameRefSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *FrameRefSet) saveRoot() *FrameRefSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/fs/fsutil/fsutil_impl_state_autogen.go b/pkg/sentry/fs/fsutil/fsutil_impl_state_autogen.go
index a0baca0c5..79d4610f0 100755..100644
--- a/pkg/sentry/fs/fsutil/fsutil_impl_state_autogen.go
+++ b/pkg/sentry/fs/fsutil/fsutil_impl_state_autogen.go
@@ -25,6 +25,7 @@ func (x *Dirtynode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -36,6 +37,7 @@ func (x *Dirtynode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
@@ -75,6 +77,7 @@ func (x *FileRangenode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -86,6 +89,7 @@ func (x *FileRangenode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
@@ -125,6 +129,7 @@ func (x *FrameRefnode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -136,6 +141,7 @@ func (x *FrameRefnode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/fs/fsutil/fsutil_state_autogen.go b/pkg/sentry/fs/fsutil/fsutil_state_autogen.go
index 80b93ad25..80b93ad25 100755..100644
--- a/pkg/sentry/fs/fsutil/fsutil_state_autogen.go
+++ b/pkg/sentry/fs/fsutil/fsutil_state_autogen.go
diff --git a/pkg/sentry/fs/fsutil/fsutil_unsafe_state_autogen.go b/pkg/sentry/fs/fsutil/fsutil_unsafe_state_autogen.go
index 00b0994f6..00b0994f6 100755..100644
--- a/pkg/sentry/fs/fsutil/fsutil_unsafe_state_autogen.go
+++ b/pkg/sentry/fs/fsutil/fsutil_unsafe_state_autogen.go
diff --git a/pkg/sentry/fs/gofer/fifo.go b/pkg/sentry/fs/gofer/fifo.go
index 456557058..456557058 100755..100644
--- a/pkg/sentry/fs/gofer/fifo.go
+++ b/pkg/sentry/fs/gofer/fifo.go
diff --git a/pkg/sentry/fs/gofer/gofer_state_autogen.go b/pkg/sentry/fs/gofer/gofer_state_autogen.go
index 7db9211b4..7db9211b4 100755..100644
--- a/pkg/sentry/fs/gofer/gofer_state_autogen.go
+++ b/pkg/sentry/fs/gofer/gofer_state_autogen.go
diff --git a/pkg/sentry/fs/host/host.go b/pkg/sentry/fs/host/host.go
index 081ba1dd8..081ba1dd8 100755..100644
--- a/pkg/sentry/fs/host/host.go
+++ b/pkg/sentry/fs/host/host.go
diff --git a/pkg/sentry/fs/host/host_amd64_unsafe_state_autogen.go b/pkg/sentry/fs/host/host_amd64_unsafe_state_autogen.go
index 488cbdfcf..488cbdfcf 100755..100644
--- a/pkg/sentry/fs/host/host_amd64_unsafe_state_autogen.go
+++ b/pkg/sentry/fs/host/host_amd64_unsafe_state_autogen.go
diff --git a/pkg/sentry/fs/host/host_arm64_unsafe_state_autogen.go b/pkg/sentry/fs/host/host_arm64_unsafe_state_autogen.go
index 7371b44db..7371b44db 100755..100644
--- a/pkg/sentry/fs/host/host_arm64_unsafe_state_autogen.go
+++ b/pkg/sentry/fs/host/host_arm64_unsafe_state_autogen.go
diff --git a/pkg/sentry/fs/host/host_state_autogen.go b/pkg/sentry/fs/host/host_state_autogen.go
index a6b97a154..a6b97a154 100755..100644
--- a/pkg/sentry/fs/host/host_state_autogen.go
+++ b/pkg/sentry/fs/host/host_state_autogen.go
diff --git a/pkg/sentry/fs/host/host_unsafe_state_autogen.go b/pkg/sentry/fs/host/host_unsafe_state_autogen.go
index b2d8c661f..b2d8c661f 100755..100644
--- a/pkg/sentry/fs/host/host_unsafe_state_autogen.go
+++ b/pkg/sentry/fs/host/host_unsafe_state_autogen.go
diff --git a/pkg/sentry/fs/host/util_amd64_unsafe.go b/pkg/sentry/fs/host/util_amd64_unsafe.go
index 66da6e9f5..66da6e9f5 100755..100644
--- a/pkg/sentry/fs/host/util_amd64_unsafe.go
+++ b/pkg/sentry/fs/host/util_amd64_unsafe.go
diff --git a/pkg/sentry/fs/host/util_arm64_unsafe.go b/pkg/sentry/fs/host/util_arm64_unsafe.go
index e8cb94aeb..e8cb94aeb 100755..100644
--- a/pkg/sentry/fs/host/util_arm64_unsafe.go
+++ b/pkg/sentry/fs/host/util_arm64_unsafe.go
diff --git a/pkg/sentry/fs/lock/lock_range.go b/pkg/sentry/fs/lock/lock_range.go
index 7a6f77640..7a6f77640 100755..100644
--- a/pkg/sentry/fs/lock/lock_range.go
+++ b/pkg/sentry/fs/lock/lock_range.go
diff --git a/pkg/sentry/fs/lock/lock_set.go b/pkg/sentry/fs/lock/lock_set.go
index 2343ca0b4..5356f5791 100755..100644
--- a/pkg/sentry/fs/lock/lock_set.go
+++ b/pkg/sentry/fs/lock/lock_set.go
@@ -5,6 +5,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const LocktrackGaps = 0
+
+var _ = uint8(LocktrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type LockdynamicGap [LocktrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *LockdynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *LockdynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -263,8 +291,12 @@ func (s *LockSet) Insert(gap LockGapIterator, r LockRange, val Lock) LockIterato
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (lockSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := LocktrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (lockSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -278,11 +310,16 @@ func (s *LockSet) Insert(gap LockGapIterator, r LockRange, val Lock) LockIterato
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (lockSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := LocktrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -309,11 +346,15 @@ func (s *LockSet) InsertWithoutMerging(gap LockGapIterator, r LockRange, val Loc
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *LockSet) InsertWithoutMergingUnchecked(gap LockGapIterator, r LockRange, val Lock) LockIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := LocktrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return LockIterator{gap.node, gap.index}
}
@@ -328,12 +369,20 @@ func (s *LockSet) Remove(seg LockIterator) LockGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if LocktrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
lockSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if LocktrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(LockGapIterator{seg.node, seg.index})
}
@@ -383,6 +432,7 @@ func (s *LockSet) MergeUnchecked(first, second LockIterator) LockIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -558,6 +608,12 @@ type Locknode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap LockdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [LockmaxDegree - 1]LockRange
@@ -603,12 +659,12 @@ func (n *Locknode) nextSibling() *Locknode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *Locknode) rebalanceBeforeInsert(gap LockGapIterator) LockGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < LockmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &Locknode{
@@ -644,6 +700,11 @@ func (n *Locknode) rebalanceBeforeInsert(gap LockGapIterator) LockGapIterator {
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if LocktrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -681,6 +742,11 @@ func (n *Locknode) rebalanceBeforeInsert(gap LockGapIterator) LockGapIterator {
}
n.nrSegments = LockminDegree - 1
+ if LocktrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -726,6 +792,11 @@ func (n *Locknode) rebalanceAfterRemove(gap LockGapIterator) LockGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if LocktrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return LockGapIterator{n, 0}
}
@@ -754,6 +825,11 @@ func (n *Locknode) rebalanceAfterRemove(gap LockGapIterator) LockGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if LocktrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return LockGapIterator{n, n.nrSegments}
@@ -786,6 +862,7 @@ func (n *Locknode) rebalanceAfterRemove(gap LockGapIterator) LockGapIterator {
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return LockGapIterator{p, gap.index}
}
@@ -832,10 +909,146 @@ func (n *Locknode) rebalanceAfterRemove(gap LockGapIterator) LockGapIterator {
p.children[p.nrSegments] = nil
p.nrSegments--
+ if LocktrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *Locknode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *Locknode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *Locknode) calculateMaxGapLeaf() uint64 {
+ max := LockGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (LockGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *Locknode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Locknode) searchFirstLargeEnoughGap(minSize uint64) LockGapIterator {
+ if n.maxGap.Get() < minSize {
+ return LockGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := LockGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Locknode) searchLastLargeEnoughGap(minSize uint64) LockGapIterator {
+ if n.maxGap.Get() < minSize {
+ return LockGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := LockGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1141,6 +1354,114 @@ func (gap LockGapIterator) NextGap() LockGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap LockGapIterator) NextLargeEnoughGap(minSize uint64) LockGapIterator {
+ if LocktrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap LockGapIterator) nextLargeEnoughGapHelper(minSize uint64) LockGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return LockGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap LockGapIterator) PrevLargeEnoughGap(minSize uint64) LockGapIterator {
+ if LocktrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap LockGapIterator) prevLargeEnoughGapHelper(minSize uint64) LockGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return LockGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1207,7 +1528,15 @@ func (n *Locknode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if LocktrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1259,6 +1588,46 @@ func (s *LockSet) ImportSortedSlices(sds *LockSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *LockSet) segmentTestCheck(expectedSegments int, segFunc func(int, LockRange, Lock) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *LockSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *LockSet) saveRoot() *LockSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/fs/lock/lock_state_autogen.go b/pkg/sentry/fs/lock/lock_state_autogen.go
index a5db62814..d5ea98366 100755..100644
--- a/pkg/sentry/fs/lock/lock_state_autogen.go
+++ b/pkg/sentry/fs/lock/lock_state_autogen.go
@@ -67,6 +67,7 @@ func (x *Locknode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -78,6 +79,7 @@ func (x *Locknode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/fs/proc/device/device_state_autogen.go b/pkg/sentry/fs/proc/device/device_state_autogen.go
index 4a5e3cc88..4a5e3cc88 100755..100644
--- a/pkg/sentry/fs/proc/device/device_state_autogen.go
+++ b/pkg/sentry/fs/proc/device/device_state_autogen.go
diff --git a/pkg/sentry/fs/proc/proc_state_autogen.go b/pkg/sentry/fs/proc/proc_state_autogen.go
index baf7cd42b..baf7cd42b 100755..100644
--- a/pkg/sentry/fs/proc/proc_state_autogen.go
+++ b/pkg/sentry/fs/proc/proc_state_autogen.go
diff --git a/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go b/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go
index cfd3a40b4..cfd3a40b4 100755..100644
--- a/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go
+++ b/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go
diff --git a/pkg/sentry/fs/ramfs/ramfs_state_autogen.go b/pkg/sentry/fs/ramfs/ramfs_state_autogen.go
index 0a001e0b6..0a001e0b6 100755..100644
--- a/pkg/sentry/fs/ramfs/ramfs_state_autogen.go
+++ b/pkg/sentry/fs/ramfs/ramfs_state_autogen.go
diff --git a/pkg/sentry/fs/sys/sys_state_autogen.go b/pkg/sentry/fs/sys/sys_state_autogen.go
index 733c504b1..733c504b1 100755..100644
--- a/pkg/sentry/fs/sys/sys_state_autogen.go
+++ b/pkg/sentry/fs/sys/sys_state_autogen.go
diff --git a/pkg/sentry/fs/timerfd/timerfd_state_autogen.go b/pkg/sentry/fs/timerfd/timerfd_state_autogen.go
index 955cf1d38..955cf1d38 100755..100644
--- a/pkg/sentry/fs/timerfd/timerfd_state_autogen.go
+++ b/pkg/sentry/fs/timerfd/timerfd_state_autogen.go
diff --git a/pkg/sentry/fs/tmpfs/tmpfs_state_autogen.go b/pkg/sentry/fs/tmpfs/tmpfs_state_autogen.go
index e4d2584fd..e4d2584fd 100755..100644
--- a/pkg/sentry/fs/tmpfs/tmpfs_state_autogen.go
+++ b/pkg/sentry/fs/tmpfs/tmpfs_state_autogen.go
diff --git a/pkg/sentry/fs/tty/tty_state_autogen.go b/pkg/sentry/fs/tty/tty_state_autogen.go
index 25d601072..25d601072 100755..100644
--- a/pkg/sentry/fs/tty/tty_state_autogen.go
+++ b/pkg/sentry/fs/tty/tty_state_autogen.go
diff --git a/pkg/sentry/fs/user/user.go b/pkg/sentry/fs/user/user.go
index fe7f67c00..fe7f67c00 100755..100644
--- a/pkg/sentry/fs/user/user.go
+++ b/pkg/sentry/fs/user/user.go
diff --git a/pkg/sentry/fs/user/user_state_autogen.go b/pkg/sentry/fs/user/user_state_autogen.go
index 8083e036c..8083e036c 100755..100644
--- a/pkg/sentry/fs/user/user_state_autogen.go
+++ b/pkg/sentry/fs/user/user_state_autogen.go
diff --git a/pkg/sentry/fsbridge/bridge.go b/pkg/sentry/fsbridge/bridge.go
index 8e7590721..8e7590721 100755..100644
--- a/pkg/sentry/fsbridge/bridge.go
+++ b/pkg/sentry/fsbridge/bridge.go
diff --git a/pkg/sentry/fsbridge/fs.go b/pkg/sentry/fsbridge/fs.go
index 093ce1fb3..093ce1fb3 100755..100644
--- a/pkg/sentry/fsbridge/fs.go
+++ b/pkg/sentry/fsbridge/fs.go
diff --git a/pkg/sentry/fsbridge/fsbridge_state_autogen.go b/pkg/sentry/fsbridge/fsbridge_state_autogen.go
index d370b2d47..d370b2d47 100755..100644
--- a/pkg/sentry/fsbridge/fsbridge_state_autogen.go
+++ b/pkg/sentry/fsbridge/fsbridge_state_autogen.go
diff --git a/pkg/sentry/fsbridge/vfs.go b/pkg/sentry/fsbridge/vfs.go
index 89168220a..89168220a 100755..100644
--- a/pkg/sentry/fsbridge/vfs.go
+++ b/pkg/sentry/fsbridge/vfs.go
diff --git a/pkg/sentry/fsimpl/devpts/devpts.go b/pkg/sentry/fsimpl/devpts/devpts.go
index c03c65445..c03c65445 100755..100644
--- a/pkg/sentry/fsimpl/devpts/devpts.go
+++ b/pkg/sentry/fsimpl/devpts/devpts.go
diff --git a/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go b/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go
index 90cd7937c..90cd7937c 100755..100644
--- a/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go
+++ b/pkg/sentry/fsimpl/devpts/devpts_state_autogen.go
diff --git a/pkg/sentry/fsimpl/devpts/line_discipline.go b/pkg/sentry/fsimpl/devpts/line_discipline.go
index f7bc325d1..f7bc325d1 100755..100644
--- a/pkg/sentry/fsimpl/devpts/line_discipline.go
+++ b/pkg/sentry/fsimpl/devpts/line_discipline.go
diff --git a/pkg/sentry/fsimpl/devpts/master.go b/pkg/sentry/fsimpl/devpts/master.go
index 7a7ce5d81..7a7ce5d81 100755..100644
--- a/pkg/sentry/fsimpl/devpts/master.go
+++ b/pkg/sentry/fsimpl/devpts/master.go
diff --git a/pkg/sentry/fsimpl/devpts/queue.go b/pkg/sentry/fsimpl/devpts/queue.go
index dffb4232c..dffb4232c 100755..100644
--- a/pkg/sentry/fsimpl/devpts/queue.go
+++ b/pkg/sentry/fsimpl/devpts/queue.go
diff --git a/pkg/sentry/fsimpl/devpts/slave.go b/pkg/sentry/fsimpl/devpts/slave.go
index 526cd406c..526cd406c 100755..100644
--- a/pkg/sentry/fsimpl/devpts/slave.go
+++ b/pkg/sentry/fsimpl/devpts/slave.go
diff --git a/pkg/sentry/fsimpl/devpts/terminal.go b/pkg/sentry/fsimpl/devpts/terminal.go
index 7d2781c54..7d2781c54 100755..100644
--- a/pkg/sentry/fsimpl/devpts/terminal.go
+++ b/pkg/sentry/fsimpl/devpts/terminal.go
diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go
index 142ee53b0..142ee53b0 100755..100644
--- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go
+++ b/pkg/sentry/fsimpl/devtmpfs/devtmpfs.go
diff --git a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go b/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go
index ac054eb77..ac054eb77 100755..100644
--- a/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go
+++ b/pkg/sentry/fsimpl/devtmpfs/devtmpfs_state_autogen.go
diff --git a/pkg/sentry/fsimpl/eventfd/eventfd.go b/pkg/sentry/fsimpl/eventfd/eventfd.go
index c573d7935..c573d7935 100755..100644
--- a/pkg/sentry/fsimpl/eventfd/eventfd.go
+++ b/pkg/sentry/fsimpl/eventfd/eventfd.go
diff --git a/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go b/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go
index e83f6aed8..e83f6aed8 100755..100644
--- a/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go
+++ b/pkg/sentry/fsimpl/eventfd/eventfd_state_autogen.go
diff --git a/pkg/sentry/fsimpl/gofer/dentry_list.go b/pkg/sentry/fsimpl/gofer/dentry_list.go
index fa03e2501..fa03e2501 100755..100644
--- a/pkg/sentry/fsimpl/gofer/dentry_list.go
+++ b/pkg/sentry/fsimpl/gofer/dentry_list.go
diff --git a/pkg/sentry/fsimpl/gofer/directory.go b/pkg/sentry/fsimpl/gofer/directory.go
index b98218753..b98218753 100755..100644
--- a/pkg/sentry/fsimpl/gofer/directory.go
+++ b/pkg/sentry/fsimpl/gofer/directory.go
diff --git a/pkg/sentry/fsimpl/gofer/filesystem.go b/pkg/sentry/fsimpl/gofer/filesystem.go
index 7f2181216..7f2181216 100755..100644
--- a/pkg/sentry/fsimpl/gofer/filesystem.go
+++ b/pkg/sentry/fsimpl/gofer/filesystem.go
diff --git a/pkg/sentry/fsimpl/gofer/fstree.go b/pkg/sentry/fsimpl/gofer/fstree.go
index 9ef0dd8c8..9ef0dd8c8 100755..100644
--- a/pkg/sentry/fsimpl/gofer/fstree.go
+++ b/pkg/sentry/fsimpl/gofer/fstree.go
diff --git a/pkg/sentry/fsimpl/gofer/gofer.go b/pkg/sentry/fsimpl/gofer/gofer.go
index ebf063a58..131da332f 100755..100644
--- a/pkg/sentry/fsimpl/gofer/gofer.go
+++ b/pkg/sentry/fsimpl/gofer/gofer.go
@@ -84,12 +84,6 @@ type filesystem struct {
// devMinor is the filesystem's minor device number. devMinor is immutable.
devMinor uint32
- // uid and gid are the effective KUID and KGID of the filesystem's creator,
- // and are used as the owner and group for files that don't specify one.
- // uid and gid are immutable.
- uid auth.KUID
- gid auth.KGID
-
// renameMu serves two purposes:
//
// - It synchronizes path resolution with renaming initiated by this
@@ -122,6 +116,8 @@ type filesystemOptions struct {
fd int
aname string
interop InteropMode // derived from the "cache" mount option
+ dfltuid auth.KUID
+ dfltgid auth.KGID
msize uint32
version string
@@ -230,6 +226,15 @@ type InternalFilesystemOptions struct {
OpenSocketsByConnecting bool
}
+// _V9FS_DEFUID and _V9FS_DEFGID (from Linux's fs/9p/v9fs.h) are the default
+// UIDs and GIDs used for files that do not provide a specific owner or group
+// respectively.
+const (
+ // uint32(-2) doesn't work in Go.
+ _V9FS_DEFUID = auth.KUID(4294967294)
+ _V9FS_DEFGID = auth.KGID(4294967294)
+)
+
// Name implements vfs.FilesystemType.Name.
func (FilesystemType) Name() string {
return Name
@@ -315,6 +320,31 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
}
}
+ // Parse the default UID and GID.
+ fsopts.dfltuid = _V9FS_DEFUID
+ if dfltuidstr, ok := mopts["dfltuid"]; ok {
+ delete(mopts, "dfltuid")
+ dfltuid, err := strconv.ParseUint(dfltuidstr, 10, 32)
+ if err != nil {
+ ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: dfltuid=%s", dfltuidstr)
+ return nil, nil, syserror.EINVAL
+ }
+ // In Linux, dfltuid is interpreted as a UID and is converted to a KUID
+ // in the caller's user namespace, but goferfs isn't
+ // application-mountable.
+ fsopts.dfltuid = auth.KUID(dfltuid)
+ }
+ fsopts.dfltgid = _V9FS_DEFGID
+ if dfltgidstr, ok := mopts["dfltgid"]; ok {
+ delete(mopts, "dfltgid")
+ dfltgid, err := strconv.ParseUint(dfltgidstr, 10, 32)
+ if err != nil {
+ ctx.Warningf("gofer.FilesystemType.GetFilesystem: invalid default UID: dfltgid=%s", dfltgidstr)
+ return nil, nil, syserror.EINVAL
+ }
+ fsopts.dfltgid = auth.KGID(dfltgid)
+ }
+
// Parse the 9P message size.
fsopts.msize = 1024 * 1024 // 1M, tested to give good enough performance up to 64M
if msizestr, ok := mopts["msize"]; ok {
@@ -422,8 +452,6 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
client: client,
clock: ktime.RealtimeClockFromContext(ctx),
devMinor: devMinor,
- uid: creds.EffectiveKUID,
- gid: creds.EffectiveKGID,
syncableDentries: make(map[*dentry]struct{}),
specialFileFDs: make(map[*specialFileFD]struct{}),
}
@@ -672,8 +700,8 @@ func (fs *filesystem) newDentry(ctx context.Context, file p9file, qid p9.QID, ma
file: file,
ino: qid.Path,
mode: uint32(attr.Mode),
- uid: uint32(fs.uid),
- gid: uint32(fs.gid),
+ uid: uint32(fs.opts.dfltuid),
+ gid: uint32(fs.opts.dfltgid),
blockSize: usermem.PageSize,
handle: handle{
fd: -1,
@@ -928,8 +956,8 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, stat *lin
// so we can't race with Write or another truncate.)
d.dataMu.Unlock()
if d.size < oldSize {
- oldpgend := pageRoundUp(oldSize)
- newpgend := pageRoundUp(d.size)
+ oldpgend, _ := usermem.PageRoundUp(oldSize)
+ newpgend, _ := usermem.PageRoundUp(d.size)
if oldpgend != newpgend {
d.mapsMu.Lock()
d.mappings.Invalidate(memmap.MappableRange{newpgend, oldpgend}, memmap.InvalidateOpts{
diff --git a/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go b/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go
index 546d432c9..546d432c9 100755..100644
--- a/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go
+++ b/pkg/sentry/fsimpl/gofer/gofer_state_autogen.go
diff --git a/pkg/sentry/fsimpl/gofer/handle.go b/pkg/sentry/fsimpl/gofer/handle.go
index 724a3f1f7..724a3f1f7 100755..100644
--- a/pkg/sentry/fsimpl/gofer/handle.go
+++ b/pkg/sentry/fsimpl/gofer/handle.go
diff --git a/pkg/sentry/fsimpl/gofer/p9file.go b/pkg/sentry/fsimpl/gofer/p9file.go
index 87f0b877f..87f0b877f 100755..100644
--- a/pkg/sentry/fsimpl/gofer/p9file.go
+++ b/pkg/sentry/fsimpl/gofer/p9file.go
diff --git a/pkg/sentry/fsimpl/gofer/regular_file.go b/pkg/sentry/fsimpl/gofer/regular_file.go
index 857f7c74e..0d10cf7ac 100755..100644
--- a/pkg/sentry/fsimpl/gofer/regular_file.go
+++ b/pkg/sentry/fsimpl/gofer/regular_file.go
@@ -148,9 +148,9 @@ func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, off
return 0, err
}
// Remove touched pages from the cache.
- pgstart := pageRoundDown(uint64(offset))
- pgend := pageRoundUp(uint64(offset + src.NumBytes()))
- if pgend < pgstart {
+ pgstart := usermem.PageRoundDown(uint64(offset))
+ pgend, ok := usermem.PageRoundUp(uint64(offset + src.NumBytes()))
+ if !ok {
return 0, syserror.EINVAL
}
mr := memmap.MappableRange{pgstart, pgend}
@@ -306,9 +306,10 @@ func (rw *dentryReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error)
if fillCache {
// Read into the cache, then re-enter the loop to read from the
// cache.
+ gapEnd, _ := usermem.PageRoundUp(gapMR.End)
reqMR := memmap.MappableRange{
- Start: pageRoundDown(gapMR.Start),
- End: pageRoundUp(gapMR.End),
+ Start: usermem.PageRoundDown(gapMR.Start),
+ End: gapEnd,
}
optMR := gap.Range()
err := rw.d.cache.Fill(rw.ctx, reqMR, maxFillRange(reqMR, optMR), mf, usage.PageCache, rw.d.handle.readToBlocksAt)
@@ -671,7 +672,7 @@ func (d *dentry) Translate(ctx context.Context, required, optional memmap.Mappab
// Constrain translations to d.size (rounded up) to prevent translation to
// pages that may be concurrently truncated.
- pgend := pageRoundUp(d.size)
+ pgend, _ := usermem.PageRoundUp(d.size)
var beyondEOF bool
if required.End > pgend {
if required.Start >= pgend {
@@ -818,43 +819,15 @@ type dentryPlatformFile struct {
// IncRef implements platform.File.IncRef.
func (d *dentryPlatformFile) IncRef(fr platform.FileRange) {
d.dataMu.Lock()
- seg, gap := d.fdRefs.Find(fr.Start)
- for {
- switch {
- case seg.Ok() && seg.Start() < fr.End:
- seg = d.fdRefs.Isolate(seg, fr)
- seg.SetValue(seg.Value() + 1)
- seg, gap = seg.NextNonEmpty()
- case gap.Ok() && gap.Start() < fr.End:
- newRange := gap.Range().Intersect(fr)
- usage.MemoryAccounting.Inc(newRange.Length(), usage.Mapped)
- seg, gap = d.fdRefs.InsertWithoutMerging(gap, newRange, 1).NextNonEmpty()
- default:
- d.fdRefs.MergeAdjacent(fr)
- d.dataMu.Unlock()
- return
- }
- }
+ d.fdRefs.IncRefAndAccount(fr)
+ d.dataMu.Unlock()
}
// DecRef implements platform.File.DecRef.
func (d *dentryPlatformFile) DecRef(fr platform.FileRange) {
d.dataMu.Lock()
- seg := d.fdRefs.FindSegment(fr.Start)
-
- for seg.Ok() && seg.Start() < fr.End {
- seg = d.fdRefs.Isolate(seg, fr)
- if old := seg.Value(); old == 1 {
- usage.MemoryAccounting.Dec(seg.Range().Length(), usage.Mapped)
- seg = d.fdRefs.Remove(seg).NextSegment()
- } else {
- seg.SetValue(old - 1)
- seg = seg.NextSegment()
- }
- }
- d.fdRefs.MergeAdjacent(fr)
+ d.fdRefs.DecRefAndAccount(fr)
d.dataMu.Unlock()
-
}
// MapInternal implements platform.File.MapInternal.
diff --git a/pkg/sentry/fsimpl/gofer/socket.go b/pkg/sentry/fsimpl/gofer/socket.go
index d6dbe9092..d6dbe9092 100755..100644
--- a/pkg/sentry/fsimpl/gofer/socket.go
+++ b/pkg/sentry/fsimpl/gofer/socket.go
diff --git a/pkg/sentry/fsimpl/gofer/special_file.go b/pkg/sentry/fsimpl/gofer/special_file.go
index a464e6a94..a464e6a94 100755..100644
--- a/pkg/sentry/fsimpl/gofer/special_file.go
+++ b/pkg/sentry/fsimpl/gofer/special_file.go
diff --git a/pkg/sentry/fsimpl/gofer/symlink.go b/pkg/sentry/fsimpl/gofer/symlink.go
index 2ec819f86..2ec819f86 100755..100644
--- a/pkg/sentry/fsimpl/gofer/symlink.go
+++ b/pkg/sentry/fsimpl/gofer/symlink.go
diff --git a/pkg/sentry/fsimpl/gofer/time.go b/pkg/sentry/fsimpl/gofer/time.go
index 2608e7e1d..2608e7e1d 100755..100644
--- a/pkg/sentry/fsimpl/gofer/time.go
+++ b/pkg/sentry/fsimpl/gofer/time.go
diff --git a/pkg/sentry/fsimpl/host/control.go b/pkg/sentry/fsimpl/host/control.go
index b9082a20f..b9082a20f 100755..100644
--- a/pkg/sentry/fsimpl/host/control.go
+++ b/pkg/sentry/fsimpl/host/control.go
diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go
index 8caf55a1b..18b127521 100755..100644
--- a/pkg/sentry/fsimpl/host/host.go
+++ b/pkg/sentry/fsimpl/host/host.go
@@ -86,15 +86,13 @@ func NewFD(ctx context.Context, mnt *vfs.Mount, hostFD int, opts *NewFDOptions)
i := &inode{
hostFD: hostFD,
- seekable: seekable,
+ ino: fs.NextIno(),
isTTY: opts.IsTTY,
- canMap: canMap(uint32(fileType)),
wouldBlock: wouldBlock(uint32(fileType)),
- ino: fs.NextIno(),
- // For simplicity, set offset to 0. Technically, we should use the existing
- // offset on the host if the file is seekable.
- offset: 0,
+ seekable: seekable,
+ canMap: canMap(uint32(fileType)),
}
+ i.pf.inode = i
// Non-seekable files can't be memory mapped, assert this.
if !i.seekable && i.canMap {
@@ -117,6 +115,10 @@ func NewFD(ctx context.Context, mnt *vfs.Mount, hostFD int, opts *NewFDOptions)
// i.open will take a reference on d.
defer d.DecRef()
+
+ // For simplicity, fileDescription.offset is set to 0. Technically, we
+ // should only set to 0 on files that are not seekable (sockets, pipes,
+ // etc.), and use the offset from the host fd otherwise when importing.
return i.open(ctx, d.VFSDentry(), mnt, flags)
}
@@ -189,11 +191,15 @@ type inode struct {
// This field is initialized at creation time and is immutable.
hostFD int
- // wouldBlock is true if the host FD would return EWOULDBLOCK for
- // operations that would block.
+ // ino is an inode number unique within this filesystem.
//
// This field is initialized at creation time and is immutable.
- wouldBlock bool
+ ino uint64
+
+ // isTTY is true if this file represents a TTY.
+ //
+ // This field is initialized at creation time and is immutable.
+ isTTY bool
// seekable is false if the host fd points to a file representing a stream,
// e.g. a socket or a pipe. Such files are not seekable and can return
@@ -202,29 +208,29 @@ type inode struct {
// This field is initialized at creation time and is immutable.
seekable bool
- // isTTY is true if this file represents a TTY.
+ // wouldBlock is true if the host FD would return EWOULDBLOCK for
+ // operations that would block.
//
// This field is initialized at creation time and is immutable.
- isTTY bool
+ wouldBlock bool
+
+ // Event queue for blocking operations.
+ queue waiter.Queue
// canMap specifies whether we allow the file to be memory mapped.
//
// This field is initialized at creation time and is immutable.
canMap bool
- // ino is an inode number unique within this filesystem.
- //
- // This field is initialized at creation time and is immutable.
- ino uint64
+ // mapsMu protects mappings.
+ mapsMu sync.Mutex
- // offsetMu protects offset.
- offsetMu sync.Mutex
-
- // offset specifies the current file offset.
- offset int64
+ // If canMap is true, mappings tracks mappings of hostFD into
+ // memmap.MappingSpaces.
+ mappings memmap.MappingSet
- // Event queue for blocking operations.
- queue waiter.Queue
+ // pf implements platform.File for mappings of hostFD.
+ pf inodePlatformFile
}
// CheckPermissions implements kernfs.Inode.
@@ -388,6 +394,21 @@ func (i *inode) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Cre
if err := syscall.Ftruncate(i.hostFD, int64(s.Size)); err != nil {
return err
}
+ oldSize := uint64(hostStat.Size)
+ if s.Size < oldSize {
+ oldpgend, _ := usermem.PageRoundUp(oldSize)
+ newpgend, _ := usermem.PageRoundUp(s.Size)
+ if oldpgend != newpgend {
+ i.mapsMu.Lock()
+ i.mappings.Invalidate(memmap.MappableRange{newpgend, oldpgend}, memmap.InvalidateOpts{
+ // Compare Linux's mm/truncate.c:truncate_setsize() =>
+ // truncate_pagecache() =>
+ // mm/memory.c:unmap_mapping_range(evencows=1).
+ InvalidatePrivate: true,
+ })
+ i.mapsMu.Unlock()
+ }
+ }
}
if m&(linux.STATX_ATIME|linux.STATX_MTIME) != 0 {
ts := [2]syscall.Timespec{
@@ -464,9 +485,6 @@ func (i *inode) open(ctx context.Context, d *vfs.Dentry, mnt *vfs.Mount, flags u
return vfsfd, nil
}
- // For simplicity, set offset to 0. Technically, we should
- // only set to 0 on files that are not seekable (sockets, pipes, etc.),
- // and use the offset from the host fd otherwise.
fd := &fileDescription{inode: i}
vfsfd := &fd.vfsfd
if err := vfsfd.Init(fd, flags, mnt, d, &vfs.FileDescriptionOptions{}); err != nil {
@@ -487,6 +505,13 @@ type fileDescription struct {
//
// inode is immutable after fileDescription creation.
inode *inode
+
+ // offsetMu protects offset.
+ offsetMu sync.Mutex
+
+ // offset specifies the current file offset. It is only meaningful when
+ // inode.seekable is true.
+ offset int64
}
// SetStat implements vfs.FileDescriptionImpl.
@@ -532,10 +557,10 @@ func (f *fileDescription) Read(ctx context.Context, dst usermem.IOSequence, opts
return n, err
}
// TODO(gvisor.dev/issue/1672): Cache pages, when forced to do so.
- i.offsetMu.Lock()
- n, err := readFromHostFD(ctx, i.hostFD, dst, i.offset, opts.Flags)
- i.offset += n
- i.offsetMu.Unlock()
+ f.offsetMu.Lock()
+ n, err := readFromHostFD(ctx, i.hostFD, dst, f.offset, opts.Flags)
+ f.offset += n
+ f.offsetMu.Unlock()
return n, err
}
@@ -572,10 +597,10 @@ func (f *fileDescription) Write(ctx context.Context, src usermem.IOSequence, opt
}
// TODO(gvisor.dev/issue/1672): Cache pages, when forced to do so.
// TODO(gvisor.dev/issue/1672): Write to end of file and update offset if O_APPEND is set on this file.
- i.offsetMu.Lock()
- n, err := writeToHostFD(ctx, i.hostFD, src, i.offset, opts.Flags)
- i.offset += n
- i.offsetMu.Unlock()
+ f.offsetMu.Lock()
+ n, err := writeToHostFD(ctx, i.hostFD, src, f.offset, opts.Flags)
+ f.offset += n
+ f.offsetMu.Unlock()
return n, err
}
@@ -600,41 +625,41 @@ func (f *fileDescription) Seek(_ context.Context, offset int64, whence int32) (i
return 0, syserror.ESPIPE
}
- i.offsetMu.Lock()
- defer i.offsetMu.Unlock()
+ f.offsetMu.Lock()
+ defer f.offsetMu.Unlock()
switch whence {
case linux.SEEK_SET:
if offset < 0 {
- return i.offset, syserror.EINVAL
+ return f.offset, syserror.EINVAL
}
- i.offset = offset
+ f.offset = offset
case linux.SEEK_CUR:
- // Check for overflow. Note that underflow cannot occur, since i.offset >= 0.
- if offset > math.MaxInt64-i.offset {
- return i.offset, syserror.EOVERFLOW
+ // Check for overflow. Note that underflow cannot occur, since f.offset >= 0.
+ if offset > math.MaxInt64-f.offset {
+ return f.offset, syserror.EOVERFLOW
}
- if i.offset+offset < 0 {
- return i.offset, syserror.EINVAL
+ if f.offset+offset < 0 {
+ return f.offset, syserror.EINVAL
}
- i.offset += offset
+ f.offset += offset
case linux.SEEK_END:
var s syscall.Stat_t
if err := syscall.Fstat(i.hostFD, &s); err != nil {
- return i.offset, err
+ return f.offset, err
}
size := s.Size
// Check for overflow. Note that underflow cannot occur, since size >= 0.
if offset > math.MaxInt64-size {
- return i.offset, syserror.EOVERFLOW
+ return f.offset, syserror.EOVERFLOW
}
if size+offset < 0 {
- return i.offset, syserror.EINVAL
+ return f.offset, syserror.EINVAL
}
- i.offset = size + offset
+ f.offset = size + offset
case linux.SEEK_DATA, linux.SEEK_HOLE:
// Modifying the offset in the host file table should not matter, since
@@ -643,16 +668,16 @@ func (f *fileDescription) Seek(_ context.Context, offset int64, whence int32) (i
// For reading and writing, we always rely on our internal offset.
n, err := unix.Seek(i.hostFD, offset, int(whence))
if err != nil {
- return i.offset, err
+ return f.offset, err
}
- i.offset = n
+ f.offset = n
default:
// Invalid whence.
- return i.offset, syserror.EINVAL
+ return f.offset, syserror.EINVAL
}
- return i.offset, nil
+ return f.offset, nil
}
// Sync implements FileDescriptionImpl.
@@ -666,8 +691,9 @@ func (f *fileDescription) ConfigureMMap(_ context.Context, opts *memmap.MMapOpts
if !f.inode.canMap {
return syserror.ENODEV
}
- // TODO(gvisor.dev/issue/1672): Implement ConfigureMMap and Mappable interface.
- return syserror.ENODEV
+ i := f.inode
+ i.pf.fileMapperInitOnce.Do(i.pf.fileMapper.Init)
+ return vfs.GenericConfigureMMap(&f.vfsfd, i, opts)
}
// EventRegister implements waiter.Waitable.EventRegister.
diff --git a/pkg/sentry/fsimpl/host/host_state_autogen.go b/pkg/sentry/fsimpl/host/host_state_autogen.go
index 28bc79d04..28bc79d04 100755..100644
--- a/pkg/sentry/fsimpl/host/host_state_autogen.go
+++ b/pkg/sentry/fsimpl/host/host_state_autogen.go
diff --git a/pkg/sentry/fsimpl/host/host_unsafe_state_autogen.go b/pkg/sentry/fsimpl/host/host_unsafe_state_autogen.go
index b2d8c661f..b2d8c661f 100755..100644
--- a/pkg/sentry/fsimpl/host/host_unsafe_state_autogen.go
+++ b/pkg/sentry/fsimpl/host/host_unsafe_state_autogen.go
diff --git a/pkg/sentry/fsimpl/host/ioctl_unsafe.go b/pkg/sentry/fsimpl/host/ioctl_unsafe.go
index 0983bf7d8..0983bf7d8 100755..100644
--- a/pkg/sentry/fsimpl/host/ioctl_unsafe.go
+++ b/pkg/sentry/fsimpl/host/ioctl_unsafe.go
diff --git a/pkg/sentry/fsimpl/host/mmap.go b/pkg/sentry/fsimpl/host/mmap.go
new file mode 100644
index 000000000..8545a82f0
--- /dev/null
+++ b/pkg/sentry/fsimpl/host/mmap.go
@@ -0,0 +1,132 @@
+// Copyright 2020 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 host
+
+import (
+ "gvisor.dev/gvisor/pkg/context"
+ "gvisor.dev/gvisor/pkg/safemem"
+ "gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
+ "gvisor.dev/gvisor/pkg/sentry/memmap"
+ "gvisor.dev/gvisor/pkg/sentry/platform"
+ "gvisor.dev/gvisor/pkg/sync"
+ "gvisor.dev/gvisor/pkg/usermem"
+)
+
+// inodePlatformFile implements platform.File. It exists solely because inode
+// cannot implement both kernfs.Inode.IncRef and platform.File.IncRef.
+//
+// inodePlatformFile should only be used if inode.canMap is true.
+type inodePlatformFile struct {
+ *inode
+
+ // fdRefsMu protects fdRefs.
+ fdRefsMu sync.Mutex
+
+ // fdRefs counts references on platform.File offsets. It is used solely for
+ // memory accounting.
+ fdRefs fsutil.FrameRefSet
+
+ // fileMapper caches mappings of the host file represented by this inode.
+ fileMapper fsutil.HostFileMapper
+
+ // fileMapperInitOnce is used to lazily initialize fileMapper.
+ fileMapperInitOnce sync.Once
+}
+
+// IncRef implements platform.File.IncRef.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inodePlatformFile) IncRef(fr platform.FileRange) {
+ i.fdRefsMu.Lock()
+ i.fdRefs.IncRefAndAccount(fr)
+ i.fdRefsMu.Unlock()
+}
+
+// DecRef implements platform.File.DecRef.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inodePlatformFile) DecRef(fr platform.FileRange) {
+ i.fdRefsMu.Lock()
+ i.fdRefs.DecRefAndAccount(fr)
+ i.fdRefsMu.Unlock()
+}
+
+// MapInternal implements platform.File.MapInternal.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inodePlatformFile) MapInternal(fr platform.FileRange, at usermem.AccessType) (safemem.BlockSeq, error) {
+ return i.fileMapper.MapInternal(fr, i.hostFD, at.Write)
+}
+
+// FD implements platform.File.FD.
+func (i *inodePlatformFile) FD() int {
+ return i.hostFD
+}
+
+// AddMapping implements memmap.Mappable.AddMapping.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inode) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) error {
+ i.mapsMu.Lock()
+ mapped := i.mappings.AddMapping(ms, ar, offset, writable)
+ for _, r := range mapped {
+ i.pf.fileMapper.IncRefOn(r)
+ }
+ i.mapsMu.Unlock()
+ return nil
+}
+
+// RemoveMapping implements memmap.Mappable.RemoveMapping.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inode) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) {
+ i.mapsMu.Lock()
+ unmapped := i.mappings.RemoveMapping(ms, ar, offset, writable)
+ for _, r := range unmapped {
+ i.pf.fileMapper.DecRefOn(r)
+ }
+ i.mapsMu.Unlock()
+}
+
+// CopyMapping implements memmap.Mappable.CopyMapping.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inode) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR usermem.AddrRange, offset uint64, writable bool) error {
+ return i.AddMapping(ctx, ms, dstAR, offset, writable)
+}
+
+// Translate implements memmap.Mappable.Translate.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inode) Translate(ctx context.Context, required, optional memmap.MappableRange, at usermem.AccessType) ([]memmap.Translation, error) {
+ mr := optional
+ return []memmap.Translation{
+ {
+ Source: mr,
+ File: &i.pf,
+ Offset: mr.Start,
+ Perms: usermem.AnyAccess,
+ },
+ }, nil
+}
+
+// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
+//
+// Precondition: i.inode.canMap must be true.
+func (i *inode) InvalidateUnsavable(ctx context.Context) error {
+ // We expect the same host fd across save/restore, so all translations
+ // should be valid.
+ return nil
+}
diff --git a/pkg/sentry/fsimpl/host/socket.go b/pkg/sentry/fsimpl/host/socket.go
index 38f1fbfba..38f1fbfba 100755..100644
--- a/pkg/sentry/fsimpl/host/socket.go
+++ b/pkg/sentry/fsimpl/host/socket.go
diff --git a/pkg/sentry/fsimpl/host/socket_iovec.go b/pkg/sentry/fsimpl/host/socket_iovec.go
index 584c247d2..584c247d2 100755..100644
--- a/pkg/sentry/fsimpl/host/socket_iovec.go
+++ b/pkg/sentry/fsimpl/host/socket_iovec.go
diff --git a/pkg/sentry/fsimpl/host/socket_unsafe.go b/pkg/sentry/fsimpl/host/socket_unsafe.go
index 35ded24bc..35ded24bc 100755..100644
--- a/pkg/sentry/fsimpl/host/socket_unsafe.go
+++ b/pkg/sentry/fsimpl/host/socket_unsafe.go
diff --git a/pkg/sentry/fsimpl/host/tty.go b/pkg/sentry/fsimpl/host/tty.go
index 68af6e5af..68af6e5af 100755..100644
--- a/pkg/sentry/fsimpl/host/tty.go
+++ b/pkg/sentry/fsimpl/host/tty.go
diff --git a/pkg/sentry/fsimpl/host/util.go b/pkg/sentry/fsimpl/host/util.go
index 2bc757b1a..2bc757b1a 100755..100644
--- a/pkg/sentry/fsimpl/host/util.go
+++ b/pkg/sentry/fsimpl/host/util.go
diff --git a/pkg/sentry/fsimpl/host/util_unsafe.go b/pkg/sentry/fsimpl/host/util_unsafe.go
index 5136ac844..5136ac844 100755..100644
--- a/pkg/sentry/fsimpl/host/util_unsafe.go
+++ b/pkg/sentry/fsimpl/host/util_unsafe.go
diff --git a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go
index 1568a9d49..1568a9d49 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go
+++ b/pkg/sentry/fsimpl/kernfs/dynamic_bytes_file.go
diff --git a/pkg/sentry/fsimpl/kernfs/fd_impl_util.go b/pkg/sentry/fsimpl/kernfs/fd_impl_util.go
index 8284e76a7..8284e76a7 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/fd_impl_util.go
+++ b/pkg/sentry/fsimpl/kernfs/fd_impl_util.go
diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go
index 4a12ae245..4a12ae245 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/filesystem.go
+++ b/pkg/sentry/fsimpl/kernfs/filesystem.go
diff --git a/pkg/sentry/fsimpl/kernfs/fstree.go b/pkg/sentry/fsimpl/kernfs/fstree.go
index 4c4033462..4c4033462 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/fstree.go
+++ b/pkg/sentry/fsimpl/kernfs/fstree.go
diff --git a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
index 982daa2e6..982daa2e6 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
+++ b/pkg/sentry/fsimpl/kernfs/inode_impl_util.go
diff --git a/pkg/sentry/fsimpl/kernfs/kernfs.go b/pkg/sentry/fsimpl/kernfs/kernfs.go
index a83151ad3..a83151ad3 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/kernfs.go
+++ b/pkg/sentry/fsimpl/kernfs/kernfs.go
diff --git a/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go b/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go
index 299ad87fa..299ad87fa 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go
+++ b/pkg/sentry/fsimpl/kernfs/kernfs_state_autogen.go
diff --git a/pkg/sentry/fsimpl/kernfs/slot_list.go b/pkg/sentry/fsimpl/kernfs/slot_list.go
index 09c30bca7..09c30bca7 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/slot_list.go
+++ b/pkg/sentry/fsimpl/kernfs/slot_list.go
diff --git a/pkg/sentry/fsimpl/kernfs/symlink.go b/pkg/sentry/fsimpl/kernfs/symlink.go
index 2ab3f53fd..2ab3f53fd 100755..100644
--- a/pkg/sentry/fsimpl/kernfs/symlink.go
+++ b/pkg/sentry/fsimpl/kernfs/symlink.go
diff --git a/pkg/sentry/fsimpl/pipefs/pipefs.go b/pkg/sentry/fsimpl/pipefs/pipefs.go
index cab771211..cab771211 100755..100644
--- a/pkg/sentry/fsimpl/pipefs/pipefs.go
+++ b/pkg/sentry/fsimpl/pipefs/pipefs.go
diff --git a/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go b/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go
index e3e3887cd..e3e3887cd 100755..100644
--- a/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go
+++ b/pkg/sentry/fsimpl/pipefs/pipefs_state_autogen.go
diff --git a/pkg/sentry/fsimpl/proc/filesystem.go b/pkg/sentry/fsimpl/proc/filesystem.go
index 609210253..609210253 100755..100644
--- a/pkg/sentry/fsimpl/proc/filesystem.go
+++ b/pkg/sentry/fsimpl/proc/filesystem.go
diff --git a/pkg/sentry/fsimpl/proc/proc_state_autogen.go b/pkg/sentry/fsimpl/proc/proc_state_autogen.go
index 168e61390..168e61390 100755..100644
--- a/pkg/sentry/fsimpl/proc/proc_state_autogen.go
+++ b/pkg/sentry/fsimpl/proc/proc_state_autogen.go
diff --git a/pkg/sentry/fsimpl/proc/subtasks.go b/pkg/sentry/fsimpl/proc/subtasks.go
index 36a911db4..36a911db4 100755..100644
--- a/pkg/sentry/fsimpl/proc/subtasks.go
+++ b/pkg/sentry/fsimpl/proc/subtasks.go
diff --git a/pkg/sentry/fsimpl/proc/task.go b/pkg/sentry/fsimpl/proc/task.go
index 482055db1..482055db1 100755..100644
--- a/pkg/sentry/fsimpl/proc/task.go
+++ b/pkg/sentry/fsimpl/proc/task.go
diff --git a/pkg/sentry/fsimpl/proc/task_fds.go b/pkg/sentry/fsimpl/proc/task_fds.go
index 44ccc9e4a..44ccc9e4a 100755..100644
--- a/pkg/sentry/fsimpl/proc/task_fds.go
+++ b/pkg/sentry/fsimpl/proc/task_fds.go
diff --git a/pkg/sentry/fsimpl/proc/task_files.go b/pkg/sentry/fsimpl/proc/task_files.go
index 2f297e48a..2f297e48a 100755..100644
--- a/pkg/sentry/fsimpl/proc/task_files.go
+++ b/pkg/sentry/fsimpl/proc/task_files.go
diff --git a/pkg/sentry/fsimpl/proc/task_net.go b/pkg/sentry/fsimpl/proc/task_net.go
index 6bde27376..6bde27376 100755..100644
--- a/pkg/sentry/fsimpl/proc/task_net.go
+++ b/pkg/sentry/fsimpl/proc/task_net.go
diff --git a/pkg/sentry/fsimpl/proc/tasks.go b/pkg/sentry/fsimpl/proc/tasks.go
index b51d43954..b51d43954 100755..100644
--- a/pkg/sentry/fsimpl/proc/tasks.go
+++ b/pkg/sentry/fsimpl/proc/tasks.go
diff --git a/pkg/sentry/fsimpl/proc/tasks_files.go b/pkg/sentry/fsimpl/proc/tasks_files.go
index 7d8983aa5..7d8983aa5 100755..100644
--- a/pkg/sentry/fsimpl/proc/tasks_files.go
+++ b/pkg/sentry/fsimpl/proc/tasks_files.go
diff --git a/pkg/sentry/fsimpl/proc/tasks_sys.go b/pkg/sentry/fsimpl/proc/tasks_sys.go
index 6dac2afa4..6dac2afa4 100755..100644
--- a/pkg/sentry/fsimpl/proc/tasks_sys.go
+++ b/pkg/sentry/fsimpl/proc/tasks_sys.go
diff --git a/pkg/sentry/fsimpl/signalfd/signalfd.go b/pkg/sentry/fsimpl/signalfd/signalfd.go
index d29ef3f83..d29ef3f83 100755..100644
--- a/pkg/sentry/fsimpl/signalfd/signalfd.go
+++ b/pkg/sentry/fsimpl/signalfd/signalfd.go
diff --git a/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go b/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go
index c3d9b2ffb..c3d9b2ffb 100755..100644
--- a/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go
+++ b/pkg/sentry/fsimpl/signalfd/signalfd_state_autogen.go
diff --git a/pkg/sentry/fsimpl/sockfs/sockfs.go b/pkg/sentry/fsimpl/sockfs/sockfs.go
index ee0828a15..ee0828a15 100755..100644
--- a/pkg/sentry/fsimpl/sockfs/sockfs.go
+++ b/pkg/sentry/fsimpl/sockfs/sockfs.go
diff --git a/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go b/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go
index 8d5b85e2c..8d5b85e2c 100755..100644
--- a/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go
+++ b/pkg/sentry/fsimpl/sockfs/sockfs_state_autogen.go
diff --git a/pkg/sentry/fsimpl/sys/sys.go b/pkg/sentry/fsimpl/sys/sys.go
index 0af373604..0af373604 100755..100644
--- a/pkg/sentry/fsimpl/sys/sys.go
+++ b/pkg/sentry/fsimpl/sys/sys.go
diff --git a/pkg/sentry/fsimpl/sys/sys_state_autogen.go b/pkg/sentry/fsimpl/sys/sys_state_autogen.go
index 8866ddff9..8866ddff9 100755..100644
--- a/pkg/sentry/fsimpl/sys/sys_state_autogen.go
+++ b/pkg/sentry/fsimpl/sys/sys_state_autogen.go
diff --git a/pkg/sentry/fsimpl/timerfd/timerfd.go b/pkg/sentry/fsimpl/timerfd/timerfd.go
index 60c92d626..60c92d626 100755..100644
--- a/pkg/sentry/fsimpl/timerfd/timerfd.go
+++ b/pkg/sentry/fsimpl/timerfd/timerfd.go
diff --git a/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go b/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go
index 4e5976369..4e5976369 100755..100644
--- a/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go
+++ b/pkg/sentry/fsimpl/timerfd/timerfd_state_autogen.go
diff --git a/pkg/sentry/fsimpl/tmpfs/dentry_list.go b/pkg/sentry/fsimpl/tmpfs/dentry_list.go
index 9af621dd3..9af621dd3 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/dentry_list.go
+++ b/pkg/sentry/fsimpl/tmpfs/dentry_list.go
diff --git a/pkg/sentry/fsimpl/tmpfs/device_file.go b/pkg/sentry/fsimpl/tmpfs/device_file.go
index 83bf885ee..83bf885ee 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/device_file.go
+++ b/pkg/sentry/fsimpl/tmpfs/device_file.go
diff --git a/pkg/sentry/fsimpl/tmpfs/directory.go b/pkg/sentry/fsimpl/tmpfs/directory.go
index f2399981b..f2399981b 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/directory.go
+++ b/pkg/sentry/fsimpl/tmpfs/directory.go
diff --git a/pkg/sentry/fsimpl/tmpfs/filesystem.go b/pkg/sentry/fsimpl/tmpfs/filesystem.go
index 80fa7b29d..80fa7b29d 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/filesystem.go
+++ b/pkg/sentry/fsimpl/tmpfs/filesystem.go
diff --git a/pkg/sentry/fsimpl/tmpfs/fstree.go b/pkg/sentry/fsimpl/tmpfs/fstree.go
index fab366345..fab366345 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/fstree.go
+++ b/pkg/sentry/fsimpl/tmpfs/fstree.go
diff --git a/pkg/sentry/fsimpl/tmpfs/named_pipe.go b/pkg/sentry/fsimpl/tmpfs/named_pipe.go
index 8d77b3fa8..8d77b3fa8 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/named_pipe.go
+++ b/pkg/sentry/fsimpl/tmpfs/named_pipe.go
diff --git a/pkg/sentry/fsimpl/tmpfs/regular_file.go b/pkg/sentry/fsimpl/tmpfs/regular_file.go
index 3f433d666..fee174375 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/regular_file.go
+++ b/pkg/sentry/fsimpl/tmpfs/regular_file.go
@@ -312,7 +312,7 @@ func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, off
f := fd.inode().impl.(*regularFile)
if end := offset + srclen; end < offset {
// Overflow.
- return 0, syserror.EFBIG
+ return 0, syserror.EINVAL
}
var err error
diff --git a/pkg/sentry/fsimpl/tmpfs/socket_file.go b/pkg/sentry/fsimpl/tmpfs/socket_file.go
index 25c2321af..25c2321af 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/socket_file.go
+++ b/pkg/sentry/fsimpl/tmpfs/socket_file.go
diff --git a/pkg/sentry/fsimpl/tmpfs/symlink.go b/pkg/sentry/fsimpl/tmpfs/symlink.go
index 47e075ed4..47e075ed4 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/symlink.go
+++ b/pkg/sentry/fsimpl/tmpfs/symlink.go
diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs.go b/pkg/sentry/fsimpl/tmpfs/tmpfs.go
index 1e781aecd..1e781aecd 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/tmpfs.go
+++ b/pkg/sentry/fsimpl/tmpfs/tmpfs.go
diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go b/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go
index 10d8b49a6..10d8b49a6 100755..100644
--- a/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go
+++ b/pkg/sentry/fsimpl/tmpfs/tmpfs_state_autogen.go
diff --git a/pkg/sentry/hostcpu/getcpu_arm64.s b/pkg/sentry/hostcpu/getcpu_arm64.s
index caf9abb89..caf9abb89 100755..100644
--- a/pkg/sentry/hostcpu/getcpu_arm64.s
+++ b/pkg/sentry/hostcpu/getcpu_arm64.s
diff --git a/pkg/sentry/hostcpu/hostcpu_state_autogen.go b/pkg/sentry/hostcpu/hostcpu_state_autogen.go
index 97d33d8bf..97d33d8bf 100755..100644
--- a/pkg/sentry/hostcpu/hostcpu_state_autogen.go
+++ b/pkg/sentry/hostcpu/hostcpu_state_autogen.go
diff --git a/pkg/sentry/hostfd/hostfd.go b/pkg/sentry/hostfd/hostfd.go
index 70dd9cafb..70dd9cafb 100755..100644
--- a/pkg/sentry/hostfd/hostfd.go
+++ b/pkg/sentry/hostfd/hostfd.go
diff --git a/pkg/sentry/hostfd/hostfd_state_autogen.go b/pkg/sentry/hostfd/hostfd_state_autogen.go
index 9033424d5..9033424d5 100755..100644
--- a/pkg/sentry/hostfd/hostfd_state_autogen.go
+++ b/pkg/sentry/hostfd/hostfd_state_autogen.go
diff --git a/pkg/sentry/hostfd/hostfd_unsafe.go b/pkg/sentry/hostfd/hostfd_unsafe.go
index cd4dc67fb..cd4dc67fb 100755..100644
--- a/pkg/sentry/hostfd/hostfd_unsafe.go
+++ b/pkg/sentry/hostfd/hostfd_unsafe.go
diff --git a/pkg/sentry/hostfd/hostfd_unsafe_state_autogen.go b/pkg/sentry/hostfd/hostfd_unsafe_state_autogen.go
index 9033424d5..9033424d5 100755..100644
--- a/pkg/sentry/hostfd/hostfd_unsafe_state_autogen.go
+++ b/pkg/sentry/hostfd/hostfd_unsafe_state_autogen.go
diff --git a/pkg/sentry/hostmm/hostmm_state_autogen.go b/pkg/sentry/hostmm/hostmm_state_autogen.go
index 925c56e14..925c56e14 100755..100644
--- a/pkg/sentry/hostmm/hostmm_state_autogen.go
+++ b/pkg/sentry/hostmm/hostmm_state_autogen.go
diff --git a/pkg/sentry/inet/inet_state_autogen.go b/pkg/sentry/inet/inet_state_autogen.go
index d2985113b..d2985113b 100755..100644
--- a/pkg/sentry/inet/inet_state_autogen.go
+++ b/pkg/sentry/inet/inet_state_autogen.go
diff --git a/pkg/sentry/inet/namespace.go b/pkg/sentry/inet/namespace.go
index 029af3025..029af3025 100755..100644
--- a/pkg/sentry/inet/namespace.go
+++ b/pkg/sentry/inet/namespace.go
diff --git a/pkg/sentry/kernel/auth/atomicptr_credentials_unsafe.go b/pkg/sentry/kernel/auth/atomicptr_credentials_unsafe.go
index 4535c958f..4535c958f 100755..100644
--- a/pkg/sentry/kernel/auth/atomicptr_credentials_unsafe.go
+++ b/pkg/sentry/kernel/auth/atomicptr_credentials_unsafe.go
diff --git a/pkg/sentry/kernel/auth/auth_state_autogen.go b/pkg/sentry/kernel/auth/auth_state_autogen.go
index 5b97d58a6..36e3576e8 100755..100644
--- a/pkg/sentry/kernel/auth/auth_state_autogen.go
+++ b/pkg/sentry/kernel/auth/auth_state_autogen.go
@@ -88,6 +88,7 @@ func (x *idMapnode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -99,6 +100,7 @@ func (x *idMapnode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/kernel/auth/auth_unsafe_state_autogen.go b/pkg/sentry/kernel/auth/auth_unsafe_state_autogen.go
index 6589b612c..6589b612c 100755..100644
--- a/pkg/sentry/kernel/auth/auth_unsafe_state_autogen.go
+++ b/pkg/sentry/kernel/auth/auth_unsafe_state_autogen.go
diff --git a/pkg/sentry/kernel/auth/id_map_range.go b/pkg/sentry/kernel/auth/id_map_range.go
index 833fa3518..833fa3518 100755..100644
--- a/pkg/sentry/kernel/auth/id_map_range.go
+++ b/pkg/sentry/kernel/auth/id_map_range.go
diff --git a/pkg/sentry/kernel/auth/id_map_set.go b/pkg/sentry/kernel/auth/id_map_set.go
index 73a17f281..983a036c5 100755..100644
--- a/pkg/sentry/kernel/auth/id_map_set.go
+++ b/pkg/sentry/kernel/auth/id_map_set.go
@@ -5,6 +5,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const idMaptrackGaps = 0
+
+var _ = uint8(idMaptrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type idMapdynamicGap [idMaptrackGaps]uint32
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *idMapdynamicGap) Get() uint32 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *idMapdynamicGap) Set(v uint32) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -263,8 +291,12 @@ func (s *idMapSet) Insert(gap idMapGapIterator, r idMapRange, val uint32) idMapI
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (idMapFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := idMaptrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (idMapFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -278,11 +310,16 @@ func (s *idMapSet) Insert(gap idMapGapIterator, r idMapRange, val uint32) idMapI
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (idMapFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := idMaptrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -309,11 +346,15 @@ func (s *idMapSet) InsertWithoutMerging(gap idMapGapIterator, r idMapRange, val
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *idMapSet) InsertWithoutMergingUnchecked(gap idMapGapIterator, r idMapRange, val uint32) idMapIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := idMaptrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return idMapIterator{gap.node, gap.index}
}
@@ -328,12 +369,20 @@ func (s *idMapSet) Remove(seg idMapIterator) idMapGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if idMaptrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
idMapFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if idMaptrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(idMapGapIterator{seg.node, seg.index})
}
@@ -383,6 +432,7 @@ func (s *idMapSet) MergeUnchecked(first, second idMapIterator) idMapIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -558,6 +608,12 @@ type idMapnode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap idMapdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [idMapmaxDegree - 1]idMapRange
@@ -603,12 +659,12 @@ func (n *idMapnode) nextSibling() *idMapnode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *idMapnode) rebalanceBeforeInsert(gap idMapGapIterator) idMapGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < idMapmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &idMapnode{
@@ -644,6 +700,11 @@ func (n *idMapnode) rebalanceBeforeInsert(gap idMapGapIterator) idMapGapIterator
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if idMaptrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -681,6 +742,11 @@ func (n *idMapnode) rebalanceBeforeInsert(gap idMapGapIterator) idMapGapIterator
}
n.nrSegments = idMapminDegree - 1
+ if idMaptrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -726,6 +792,11 @@ func (n *idMapnode) rebalanceAfterRemove(gap idMapGapIterator) idMapGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if idMaptrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return idMapGapIterator{n, 0}
}
@@ -754,6 +825,11 @@ func (n *idMapnode) rebalanceAfterRemove(gap idMapGapIterator) idMapGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if idMaptrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return idMapGapIterator{n, n.nrSegments}
@@ -786,6 +862,7 @@ func (n *idMapnode) rebalanceAfterRemove(gap idMapGapIterator) idMapGapIterator
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return idMapGapIterator{p, gap.index}
}
@@ -832,10 +909,146 @@ func (n *idMapnode) rebalanceAfterRemove(gap idMapGapIterator) idMapGapIterator
p.children[p.nrSegments] = nil
p.nrSegments--
+ if idMaptrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *idMapnode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *idMapnode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *idMapnode) calculateMaxGapLeaf() uint32 {
+ max := idMapGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (idMapGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *idMapnode) calculateMaxGapInternal() uint32 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *idMapnode) searchFirstLargeEnoughGap(minSize uint32) idMapGapIterator {
+ if n.maxGap.Get() < minSize {
+ return idMapGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := idMapGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *idMapnode) searchLastLargeEnoughGap(minSize uint32) idMapGapIterator {
+ if n.maxGap.Get() < minSize {
+ return idMapGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := idMapGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1141,6 +1354,114 @@ func (gap idMapGapIterator) NextGap() idMapGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap idMapGapIterator) NextLargeEnoughGap(minSize uint32) idMapGapIterator {
+ if idMaptrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap idMapGapIterator) nextLargeEnoughGapHelper(minSize uint32) idMapGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return idMapGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap idMapGapIterator) PrevLargeEnoughGap(minSize uint32) idMapGapIterator {
+ if idMaptrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap idMapGapIterator) prevLargeEnoughGapHelper(minSize uint32) idMapGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return idMapGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1207,7 +1528,15 @@ func (n *idMapnode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if idMaptrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1259,6 +1588,46 @@ func (s *idMapSet) ImportSortedSlices(sds *idMapSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *idMapSet) segmentTestCheck(expectedSegments int, segFunc func(int, idMapRange, uint32) error) error {
+ havePrev := false
+ prev := uint32(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *idMapSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *idMapSet) saveRoot() *idMapSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/kernel/epoll/epoll_list.go b/pkg/sentry/kernel/epoll/epoll_list.go
index a018f7b5c..a018f7b5c 100755..100644
--- a/pkg/sentry/kernel/epoll/epoll_list.go
+++ b/pkg/sentry/kernel/epoll/epoll_list.go
diff --git a/pkg/sentry/kernel/epoll/epoll_state_autogen.go b/pkg/sentry/kernel/epoll/epoll_state_autogen.go
index da3150465..da3150465 100755..100644
--- a/pkg/sentry/kernel/epoll/epoll_state_autogen.go
+++ b/pkg/sentry/kernel/epoll/epoll_state_autogen.go
diff --git a/pkg/sentry/kernel/eventfd/eventfd_state_autogen.go b/pkg/sentry/kernel/eventfd/eventfd_state_autogen.go
index 636d80ea9..636d80ea9 100755..100644
--- a/pkg/sentry/kernel/eventfd/eventfd_state_autogen.go
+++ b/pkg/sentry/kernel/eventfd/eventfd_state_autogen.go
diff --git a/pkg/sentry/kernel/fasync/fasync_state_autogen.go b/pkg/sentry/kernel/fasync/fasync_state_autogen.go
index fdcd48f64..fdcd48f64 100755..100644
--- a/pkg/sentry/kernel/fasync/fasync_state_autogen.go
+++ b/pkg/sentry/kernel/fasync/fasync_state_autogen.go
diff --git a/pkg/sentry/kernel/futex/atomicptr_bucket_unsafe.go b/pkg/sentry/kernel/futex/atomicptr_bucket_unsafe.go
index d3fdf09b0..d3fdf09b0 100755..100644
--- a/pkg/sentry/kernel/futex/atomicptr_bucket_unsafe.go
+++ b/pkg/sentry/kernel/futex/atomicptr_bucket_unsafe.go
diff --git a/pkg/sentry/kernel/futex/futex_state_autogen.go b/pkg/sentry/kernel/futex/futex_state_autogen.go
index 12a0788ff..12a0788ff 100755..100644
--- a/pkg/sentry/kernel/futex/futex_state_autogen.go
+++ b/pkg/sentry/kernel/futex/futex_state_autogen.go
diff --git a/pkg/sentry/kernel/futex/futex_unsafe_state_autogen.go b/pkg/sentry/kernel/futex/futex_unsafe_state_autogen.go
index 7fc038fce..7fc038fce 100755..100644
--- a/pkg/sentry/kernel/futex/futex_unsafe_state_autogen.go
+++ b/pkg/sentry/kernel/futex/futex_unsafe_state_autogen.go
diff --git a/pkg/sentry/kernel/futex/waiter_list.go b/pkg/sentry/kernel/futex/waiter_list.go
index 1b7a92b62..1b7a92b62 100755..100644
--- a/pkg/sentry/kernel/futex/waiter_list.go
+++ b/pkg/sentry/kernel/futex/waiter_list.go
diff --git a/pkg/sentry/kernel/kernel_amd64_state_autogen.go b/pkg/sentry/kernel/kernel_amd64_state_autogen.go
index 12de47ad0..12de47ad0 100755..100644
--- a/pkg/sentry/kernel/kernel_amd64_state_autogen.go
+++ b/pkg/sentry/kernel/kernel_amd64_state_autogen.go
diff --git a/pkg/sentry/kernel/kernel_arm64_state_autogen.go b/pkg/sentry/kernel/kernel_arm64_state_autogen.go
index 3c040d283..3c040d283 100755..100644
--- a/pkg/sentry/kernel/kernel_arm64_state_autogen.go
+++ b/pkg/sentry/kernel/kernel_arm64_state_autogen.go
diff --git a/pkg/sentry/kernel/kernel_opts.go b/pkg/sentry/kernel/kernel_opts.go
index 2e66ec587..2e66ec587 100755..100644
--- a/pkg/sentry/kernel/kernel_opts.go
+++ b/pkg/sentry/kernel/kernel_opts.go
diff --git a/pkg/sentry/kernel/kernel_opts_state_autogen.go b/pkg/sentry/kernel/kernel_opts_state_autogen.go
index 9ed7e27c9..9ed7e27c9 100755..100644
--- a/pkg/sentry/kernel/kernel_opts_state_autogen.go
+++ b/pkg/sentry/kernel/kernel_opts_state_autogen.go
diff --git a/pkg/sentry/kernel/kernel_state_autogen.go b/pkg/sentry/kernel/kernel_state_autogen.go
index 89ac06522..89ac06522 100755..100644
--- a/pkg/sentry/kernel/kernel_state_autogen.go
+++ b/pkg/sentry/kernel/kernel_state_autogen.go
diff --git a/pkg/sentry/kernel/kernel_unsafe_state_autogen.go b/pkg/sentry/kernel/kernel_unsafe_state_autogen.go
index 12130bf74..12130bf74 100755..100644
--- a/pkg/sentry/kernel/kernel_unsafe_state_autogen.go
+++ b/pkg/sentry/kernel/kernel_unsafe_state_autogen.go
diff --git a/pkg/sentry/kernel/memevent/memevent_state_autogen.go b/pkg/sentry/kernel/memevent/memevent_state_autogen.go
index 4a1679fa9..4a1679fa9 100755..100644
--- a/pkg/sentry/kernel/memevent/memevent_state_autogen.go
+++ b/pkg/sentry/kernel/memevent/memevent_state_autogen.go
diff --git a/pkg/sentry/kernel/memevent/memory_events.go b/pkg/sentry/kernel/memevent/memory_events.go
index 200565bb8..200565bb8 100755..100644
--- a/pkg/sentry/kernel/memevent/memory_events.go
+++ b/pkg/sentry/kernel/memevent/memory_events.go
diff --git a/pkg/sentry/kernel/memevent/memory_events_go_proto/memory_events.pb.go b/pkg/sentry/kernel/memevent/memory_events_go_proto/memory_events.pb.go
index f8b857fa9..f8b857fa9 100755..100644
--- a/pkg/sentry/kernel/memevent/memory_events_go_proto/memory_events.pb.go
+++ b/pkg/sentry/kernel/memevent/memory_events_go_proto/memory_events.pb.go
diff --git a/pkg/sentry/kernel/pending_signals_list.go b/pkg/sentry/kernel/pending_signals_list.go
index 2685c631a..2685c631a 100755..100644
--- a/pkg/sentry/kernel/pending_signals_list.go
+++ b/pkg/sentry/kernel/pending_signals_list.go
diff --git a/pkg/sentry/kernel/pipe/pipe.go b/pkg/sentry/kernel/pipe/pipe.go
index 62c8691f1..79645d7d2 100644
--- a/pkg/sentry/kernel/pipe/pipe.go
+++ b/pkg/sentry/kernel/pipe/pipe.go
@@ -207,7 +207,10 @@ func (p *Pipe) read(ctx context.Context, ops readOps) (int64, error) {
p.mu.Lock()
defer p.mu.Unlock()
+ return p.readLocked(ctx, ops)
+}
+func (p *Pipe) readLocked(ctx context.Context, ops readOps) (int64, error) {
// Is the pipe empty?
if p.view.Size() == 0 {
if !p.HasWriters() {
@@ -246,7 +249,10 @@ type writeOps struct {
func (p *Pipe) write(ctx context.Context, ops writeOps) (int64, error) {
p.mu.Lock()
defer p.mu.Unlock()
+ return p.writeLocked(ctx, ops)
+}
+func (p *Pipe) writeLocked(ctx context.Context, ops writeOps) (int64, error) {
// Can't write to a pipe with no readers.
if !p.HasReaders() {
return 0, syscall.EPIPE
diff --git a/pkg/sentry/kernel/pipe/pipe_state_autogen.go b/pkg/sentry/kernel/pipe/pipe_state_autogen.go
index b49ab46f9..b49ab46f9 100755..100644
--- a/pkg/sentry/kernel/pipe/pipe_state_autogen.go
+++ b/pkg/sentry/kernel/pipe/pipe_state_autogen.go
diff --git a/pkg/sentry/fsimpl/gofer/pagemath.go b/pkg/sentry/kernel/pipe/pipe_unsafe.go
index 847cb0784..dd60cba24 100755..100644
--- a/pkg/sentry/fsimpl/gofer/pagemath.go
+++ b/pkg/sentry/kernel/pipe/pipe_unsafe.go
@@ -12,20 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package gofer
+package pipe
import (
- "gvisor.dev/gvisor/pkg/usermem"
+ "unsafe"
)
-// This are equivalent to usermem.Addr.RoundDown/Up, but without the
-// potentially truncating conversion to usermem.Addr. This is necessary because
-// there is no way to define generic "PageRoundDown/Up" functions in Go.
-
-func pageRoundDown(x uint64) uint64 {
- return x &^ (usermem.PageSize - 1)
-}
-
-func pageRoundUp(x uint64) uint64 {
- return pageRoundDown(x + usermem.PageSize - 1)
+// lockTwoPipes locks both x.mu and y.mu in an order that is guaranteed to be
+// consistent for both lockTwoPipes(x, y) and lockTwoPipes(y, x), such that
+// concurrent calls cannot deadlock.
+//
+// Preconditions: x != y.
+func lockTwoPipes(x, y *Pipe) {
+ // Lock the two pipes in order of increasing address.
+ if uintptr(unsafe.Pointer(x)) < uintptr(unsafe.Pointer(y)) {
+ x.mu.Lock()
+ y.mu.Lock()
+ } else {
+ y.mu.Lock()
+ x.mu.Lock()
+ }
}
diff --git a/pkg/log/log_state_autogen.go b/pkg/sentry/kernel/pipe/pipe_unsafe_state_autogen.go
index 4e243c216..d3b40feb4 100755..100644
--- a/pkg/log/log_state_autogen.go
+++ b/pkg/sentry/kernel/pipe/pipe_unsafe_state_autogen.go
@@ -1,3 +1,3 @@
// automatically generated by stateify.
-package log
+package pipe
diff --git a/pkg/sentry/kernel/pipe/pipe_util.go b/pkg/sentry/kernel/pipe/pipe_util.go
index aacf28da2..aacf28da2 100755..100644
--- a/pkg/sentry/kernel/pipe/pipe_util.go
+++ b/pkg/sentry/kernel/pipe/pipe_util.go
diff --git a/pkg/sentry/kernel/pipe/vfs.go b/pkg/sentry/kernel/pipe/vfs.go
index b54f08a30..2602bed72 100755..100644
--- a/pkg/sentry/kernel/pipe/vfs.go
+++ b/pkg/sentry/kernel/pipe/vfs.go
@@ -16,7 +16,9 @@ package pipe
import (
"gvisor.dev/gvisor/pkg/abi/linux"
+ "gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/context"
+ "gvisor.dev/gvisor/pkg/safemem"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/sync"
@@ -150,7 +152,9 @@ func (vp *VFSPipe) newFD(mnt *vfs.Mount, vfsd *vfs.Dentry, statusFlags uint32) *
return &fd.vfsfd
}
-// VFSPipeFD implements vfs.FileDescriptionImpl for pipes.
+// VFSPipeFD implements vfs.FileDescriptionImpl for pipes. It also implements
+// non-atomic usermem.IO methods, allowing it to be passed as usermem.IO to
+// other FileDescriptions for splice(2) and tee(2).
type VFSPipeFD struct {
vfsfd vfs.FileDescription
vfs.FileDescriptionDefaultImpl
@@ -229,3 +233,216 @@ func (fd *VFSPipeFD) PipeSize() int64 {
func (fd *VFSPipeFD) SetPipeSize(size int64) (int64, error) {
return fd.pipe.SetFifoSize(size)
}
+
+// IOSequence returns a useremm.IOSequence that reads up to count bytes from,
+// or writes up to count bytes to, fd.
+func (fd *VFSPipeFD) IOSequence(count int64) usermem.IOSequence {
+ return usermem.IOSequence{
+ IO: fd,
+ Addrs: usermem.AddrRangeSeqOf(usermem.AddrRange{0, usermem.Addr(count)}),
+ }
+}
+
+// CopyIn implements usermem.IO.CopyIn.
+func (fd *VFSPipeFD) CopyIn(ctx context.Context, addr usermem.Addr, dst []byte, opts usermem.IOOpts) (int, error) {
+ origCount := int64(len(dst))
+ n, err := fd.pipe.read(ctx, readOps{
+ left: func() int64 {
+ return int64(len(dst))
+ },
+ limit: func(l int64) {
+ dst = dst[:l]
+ },
+ read: func(view *buffer.View) (int64, error) {
+ n, err := view.ReadAt(dst, 0)
+ view.TrimFront(int64(n))
+ return int64(n), err
+ },
+ })
+ if n > 0 {
+ fd.pipe.Notify(waiter.EventOut)
+ }
+ if err == nil && n != origCount {
+ return int(n), syserror.ErrWouldBlock
+ }
+ return int(n), err
+}
+
+// CopyOut implements usermem.IO.CopyOut.
+func (fd *VFSPipeFD) CopyOut(ctx context.Context, addr usermem.Addr, src []byte, opts usermem.IOOpts) (int, error) {
+ origCount := int64(len(src))
+ n, err := fd.pipe.write(ctx, writeOps{
+ left: func() int64 {
+ return int64(len(src))
+ },
+ limit: func(l int64) {
+ src = src[:l]
+ },
+ write: func(view *buffer.View) (int64, error) {
+ view.Append(src)
+ return int64(len(src)), nil
+ },
+ })
+ if n > 0 {
+ fd.pipe.Notify(waiter.EventIn)
+ }
+ if err == nil && n != origCount {
+ return int(n), syserror.ErrWouldBlock
+ }
+ return int(n), err
+}
+
+// ZeroOut implements usermem.IO.ZeroOut.
+func (fd *VFSPipeFD) ZeroOut(ctx context.Context, addr usermem.Addr, toZero int64, opts usermem.IOOpts) (int64, error) {
+ origCount := toZero
+ n, err := fd.pipe.write(ctx, writeOps{
+ left: func() int64 {
+ return toZero
+ },
+ limit: func(l int64) {
+ toZero = l
+ },
+ write: func(view *buffer.View) (int64, error) {
+ view.Grow(view.Size()+toZero, true /* zero */)
+ return toZero, nil
+ },
+ })
+ if n > 0 {
+ fd.pipe.Notify(waiter.EventIn)
+ }
+ if err == nil && n != origCount {
+ return n, syserror.ErrWouldBlock
+ }
+ return n, err
+}
+
+// CopyInTo implements usermem.IO.CopyInTo.
+func (fd *VFSPipeFD) CopyInTo(ctx context.Context, ars usermem.AddrRangeSeq, dst safemem.Writer, opts usermem.IOOpts) (int64, error) {
+ count := ars.NumBytes()
+ if count == 0 {
+ return 0, nil
+ }
+ origCount := count
+ n, err := fd.pipe.read(ctx, readOps{
+ left: func() int64 {
+ return count
+ },
+ limit: func(l int64) {
+ count = l
+ },
+ read: func(view *buffer.View) (int64, error) {
+ n, err := view.ReadToSafememWriter(dst, uint64(count))
+ view.TrimFront(int64(n))
+ return int64(n), err
+ },
+ })
+ if n > 0 {
+ fd.pipe.Notify(waiter.EventOut)
+ }
+ if err == nil && n != origCount {
+ return n, syserror.ErrWouldBlock
+ }
+ return n, err
+}
+
+// CopyOutFrom implements usermem.IO.CopyOutFrom.
+func (fd *VFSPipeFD) CopyOutFrom(ctx context.Context, ars usermem.AddrRangeSeq, src safemem.Reader, opts usermem.IOOpts) (int64, error) {
+ count := ars.NumBytes()
+ if count == 0 {
+ return 0, nil
+ }
+ origCount := count
+ n, err := fd.pipe.write(ctx, writeOps{
+ left: func() int64 {
+ return count
+ },
+ limit: func(l int64) {
+ count = l
+ },
+ write: func(view *buffer.View) (int64, error) {
+ n, err := view.WriteFromSafememReader(src, uint64(count))
+ return int64(n), err
+ },
+ })
+ if n > 0 {
+ fd.pipe.Notify(waiter.EventIn)
+ }
+ if err == nil && n != origCount {
+ return n, syserror.ErrWouldBlock
+ }
+ return n, err
+}
+
+// SwapUint32 implements usermem.IO.SwapUint32.
+func (fd *VFSPipeFD) SwapUint32(ctx context.Context, addr usermem.Addr, new uint32, opts usermem.IOOpts) (uint32, error) {
+ // How did a pipe get passed as the virtual address space to futex(2)?
+ panic("VFSPipeFD.SwapUint32 called unexpectedly")
+}
+
+// CompareAndSwapUint32 implements usermem.IO.CompareAndSwapUint32.
+func (fd *VFSPipeFD) CompareAndSwapUint32(ctx context.Context, addr usermem.Addr, old, new uint32, opts usermem.IOOpts) (uint32, error) {
+ panic("VFSPipeFD.CompareAndSwapUint32 called unexpectedly")
+}
+
+// LoadUint32 implements usermem.IO.LoadUint32.
+func (fd *VFSPipeFD) LoadUint32(ctx context.Context, addr usermem.Addr, opts usermem.IOOpts) (uint32, error) {
+ panic("VFSPipeFD.LoadUint32 called unexpectedly")
+}
+
+// Splice reads up to count bytes from src and writes them to dst. It returns
+// the number of bytes moved.
+//
+// Preconditions: count > 0.
+func Splice(ctx context.Context, dst, src *VFSPipeFD, count int64) (int64, error) {
+ return spliceOrTee(ctx, dst, src, count, true /* removeFromSrc */)
+}
+
+// Tee reads up to count bytes from src and writes them to dst, without
+// removing the read bytes from src. It returns the number of bytes copied.
+//
+// Preconditions: count > 0.
+func Tee(ctx context.Context, dst, src *VFSPipeFD, count int64) (int64, error) {
+ return spliceOrTee(ctx, dst, src, count, false /* removeFromSrc */)
+}
+
+// Preconditions: count > 0.
+func spliceOrTee(ctx context.Context, dst, src *VFSPipeFD, count int64, removeFromSrc bool) (int64, error) {
+ if dst.pipe == src.pipe {
+ return 0, syserror.EINVAL
+ }
+
+ lockTwoPipes(dst.pipe, src.pipe)
+ defer dst.pipe.mu.Unlock()
+ defer src.pipe.mu.Unlock()
+
+ n, err := dst.pipe.writeLocked(ctx, writeOps{
+ left: func() int64 {
+ return count
+ },
+ limit: func(l int64) {
+ count = l
+ },
+ write: func(dstView *buffer.View) (int64, error) {
+ return src.pipe.readLocked(ctx, readOps{
+ left: func() int64 {
+ return count
+ },
+ limit: func(l int64) {
+ count = l
+ },
+ read: func(srcView *buffer.View) (int64, error) {
+ n, err := srcView.ReadToSafememWriter(dstView, uint64(count))
+ if n > 0 && removeFromSrc {
+ srcView.TrimFront(int64(n))
+ }
+ return int64(n), err
+ },
+ })
+ },
+ })
+ if n > 0 {
+ dst.pipe.Notify(waiter.EventIn)
+ src.pipe.Notify(waiter.EventOut)
+ }
+ return n, err
+}
diff --git a/pkg/sentry/kernel/process_group_list.go b/pkg/sentry/kernel/process_group_list.go
index 3c5ea8aa7..3c5ea8aa7 100755..100644
--- a/pkg/sentry/kernel/process_group_list.go
+++ b/pkg/sentry/kernel/process_group_list.go
diff --git a/pkg/sentry/kernel/sched/sched_state_autogen.go b/pkg/sentry/kernel/sched/sched_state_autogen.go
index 9705ca79d..9705ca79d 100755..100644
--- a/pkg/sentry/kernel/sched/sched_state_autogen.go
+++ b/pkg/sentry/kernel/sched/sched_state_autogen.go
diff --git a/pkg/sentry/kernel/semaphore/semaphore_state_autogen.go b/pkg/sentry/kernel/semaphore/semaphore_state_autogen.go
index ba1d073d9..ba1d073d9 100755..100644
--- a/pkg/sentry/kernel/semaphore/semaphore_state_autogen.go
+++ b/pkg/sentry/kernel/semaphore/semaphore_state_autogen.go
diff --git a/pkg/sentry/kernel/semaphore/waiter_list.go b/pkg/sentry/kernel/semaphore/waiter_list.go
index 4bfe5ff95..4bfe5ff95 100755..100644
--- a/pkg/sentry/kernel/semaphore/waiter_list.go
+++ b/pkg/sentry/kernel/semaphore/waiter_list.go
diff --git a/pkg/sentry/kernel/seqatomic_taskgoroutineschedinfo_unsafe.go b/pkg/sentry/kernel/seqatomic_taskgoroutineschedinfo_unsafe.go
index b133423cc..950645965 100755..100644
--- a/pkg/sentry/kernel/seqatomic_taskgoroutineschedinfo_unsafe.go
+++ b/pkg/sentry/kernel/seqatomic_taskgoroutineschedinfo_unsafe.go
@@ -1,11 +1,11 @@
package kernel
import (
+ "fmt"
"reflect"
"strings"
"unsafe"
- "fmt"
"gvisor.dev/gvisor/pkg/sync"
)
diff --git a/pkg/sentry/kernel/session_list.go b/pkg/sentry/kernel/session_list.go
index 768482ab6..768482ab6 100755..100644
--- a/pkg/sentry/kernel/session_list.go
+++ b/pkg/sentry/kernel/session_list.go
diff --git a/pkg/sentry/kernel/shm/shm_state_autogen.go b/pkg/sentry/kernel/shm/shm_state_autogen.go
index fa8f896f7..fa8f896f7 100755..100644
--- a/pkg/sentry/kernel/shm/shm_state_autogen.go
+++ b/pkg/sentry/kernel/shm/shm_state_autogen.go
diff --git a/pkg/sentry/kernel/signalfd/signalfd.go b/pkg/sentry/kernel/signalfd/signalfd.go
index 8243bb93e..8243bb93e 100755..100644
--- a/pkg/sentry/kernel/signalfd/signalfd.go
+++ b/pkg/sentry/kernel/signalfd/signalfd.go
diff --git a/pkg/sentry/kernel/signalfd/signalfd_state_autogen.go b/pkg/sentry/kernel/signalfd/signalfd_state_autogen.go
index 2ab5b4702..2ab5b4702 100755..100644
--- a/pkg/sentry/kernel/signalfd/signalfd_state_autogen.go
+++ b/pkg/sentry/kernel/signalfd/signalfd_state_autogen.go
diff --git a/pkg/sentry/kernel/socket_list.go b/pkg/sentry/kernel/socket_list.go
index 294aa99fe..294aa99fe 100755..100644
--- a/pkg/sentry/kernel/socket_list.go
+++ b/pkg/sentry/kernel/socket_list.go
diff --git a/pkg/sentry/kernel/task_list.go b/pkg/sentry/kernel/task_list.go
index e7a3a3d20..e7a3a3d20 100755..100644
--- a/pkg/sentry/kernel/task_list.go
+++ b/pkg/sentry/kernel/task_list.go
diff --git a/pkg/sentry/kernel/time/time_state_autogen.go b/pkg/sentry/kernel/time/time_state_autogen.go
index ab6c6633d..ab6c6633d 100755..100644
--- a/pkg/sentry/kernel/time/time_state_autogen.go
+++ b/pkg/sentry/kernel/time/time_state_autogen.go
diff --git a/pkg/sentry/kernel/tty.go b/pkg/sentry/kernel/tty.go
index d0e0810e8..d0e0810e8 100755..100644
--- a/pkg/sentry/kernel/tty.go
+++ b/pkg/sentry/kernel/tty.go
diff --git a/pkg/sentry/kernel/uncaught_signal_go_proto/uncaught_signal.pb.go b/pkg/sentry/kernel/uncaught_signal_go_proto/uncaught_signal.pb.go
index 822e549ab..822e549ab 100755..100644
--- a/pkg/sentry/kernel/uncaught_signal_go_proto/uncaught_signal.pb.go
+++ b/pkg/sentry/kernel/uncaught_signal_go_proto/uncaught_signal.pb.go
diff --git a/pkg/sentry/limits/limits_state_autogen.go b/pkg/sentry/limits/limits_state_autogen.go
index aa42533a9..aa42533a9 100755..100644
--- a/pkg/sentry/limits/limits_state_autogen.go
+++ b/pkg/sentry/limits/limits_state_autogen.go
diff --git a/pkg/sentry/loader/loader_state_autogen.go b/pkg/sentry/loader/loader_state_autogen.go
index e28667944..e28667944 100755..100644
--- a/pkg/sentry/loader/loader_state_autogen.go
+++ b/pkg/sentry/loader/loader_state_autogen.go
diff --git a/pkg/sentry/loader/vdso_bin.go b/pkg/sentry/loader/vdso_bin.go
index 95a8cd8cc..595e2a1af 100755..100644
--- a/pkg/sentry/loader/vdso_bin.go
+++ b/pkg/sentry/loader/vdso_bin.go
@@ -2,4 +2,4 @@
package loader
-var vdsoBin = []byte("ELF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x008\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00p\xff\xff\xff\xff\xff\x93\x00\x00\x00\x00\x00\x00\x93\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\xa0p\xff\xff\xff\xff\xff\xa0p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xe5td\x00\x00\x00p\x00\x00\x00\x00\x00\x00pp\xff\xff\xff\xff\xffpp\xff\xff\xff\xff\xffD\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\n\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\xb0p\xff\xff\xff\xff\xff_\x00\x00\x00\x00\x00\x00\x00/\x00\x00\x00\x00 \x00pp\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x00 \x00@p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x00 \x00\x80p\xff\xff\xff\xff\xff&\x00\x00\x00\x00\x00\x00\x00h\x00\x00\x00\"\x00 \x00\xb0p\xff\xff\xff\xff\xff_\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x00 \x00p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\"\x00 \x00@p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\"\x00 \x00\x80p\xff\xff\xff\xff\xff&\x00\x00\x00\x00\x00\x00\x00\x96\x00\x00\x00\"\x00 \x00p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00linux-vdso.so.1\x00LINUX_2.6\x00__vdso_gettimeofday\x00__kernel_rt_sigreturn\x00__vdso_getcpu\x00__vdso_clock_gettime\x00gettimeofday\x00__vdso_time\x00getcpu\x00clock_gettime\x00time\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xbf\xee \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6u\xae\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;D\x00\x00\x00\x00\x00\x00\x00 \x00\x00`\x00\x00\x00 \x00\x00x\x00\x00\x00@ \x00\x00\x90\x00\x00\x00\xa0 \x00\x00\xb8\x00\x00\x00\xd0 \x00\x00\xd8\x00\x00\x00\xe0 \x00\x00\xf0\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00zR\x00x \x90\x00\x00\x00\x00\x00\x00\x00\x00\x98 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x90 \x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00L\x00\x00\x00\xa8 \x00\x00_\x00\x00\x00\x00BAD0\x83\x8eTAB\x00\x00\x00t\x00\x00\x00\xe0 \x00\x00\"\x00\x00\x00\x00AD \x83[A\x00\x00\x00\x00\x94\x00\x00\x00\xf0 \x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\xe8 \x00\x00\xa0\x00\x00\x00\x00A\x83\x90AM\x00\x00\x00\xcc\x00\x00\x00h \x00\x00\xa3\x00\x00\x00\x00A\x83\x90AP\x00\x00\x00\x00\x00\x00\x00`p\xff\xff\xff\xff\xff \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00hp\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\x9b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\xffo\x00\x00\x00\x00p\xff\xff\xff\xff\xff\xfc\xff\xffo\x00\x00\x00\x00p\xff\xff\xff\xff\xff\xfd\xff\xffo\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\xc3\x84\x00\x00\x00\x00\x00\x83\xfft\x83\xfft \x85\xffuH\x89\xf7\xe9\xba\x00\x00\x00H\x89\xf7\xe9R\x00\x00\xb8\xe4\x00\x00\x00\xc3f.\x84\x00\x00\x00\x00\x00AVSH\x83\xecI\x89\xf6H\x85\xfft:H\x89\xfbH\x8d|$\xe8\x84\x00\x00\x00\x85\xc0u7H\x8bD$H\x89H\xb8\xcf\xf7S㥛\xc4 H\xf7l$H\x89\xd0H\xc1\xe8?H\xc1\xfaH\xc2H\x89S1\xc0M\x85\xf6tI\xc7\x00\x00\x00\x00H\x83\xc4[A^ÐSH\x83\xecH\x89\xfbH\x89\xe7\xe80\x00\x00\x00H\x8b$H\x85\xdbtH\x89H\x83\xc4[\xc3f.\x84\x00\x00\x00\x00\x00@\x00\xb85\x00\x00H\x98Ð\x90\x90\x90\x90\x90SI\x89\xf8H\x8d \xa5\xde\xff\xffH\x8b1f\x90Hc\xdeH\x83\xe3\xfeH\x8by(L\x8bY0L\x8bI8L\x8bQ@\xae\xe81H\x8b1H9\xdeu\xdcH\x85\xfftYH\xc1\xe2 \x89\xc0H \xd01\xc9L)\xd8HM\xc8H\xb8\x00\x00\x00\x00\x00ʚ;1\xd2I\xf7\xf2H\xf7\xe1H\xa4\xc2 I\xd1L\x89\xc8H\xc1\xe8 H\xb9SZ\x9b\xa0/\xb8D\x00H\xf7\xe1H\xc1\xea Hi\xc2\x00ʚ;I)\xc1I\x89M\x89H1\xc0[\xc31\xffL\x89Ƹ\xe4\x00\x00\x00[\xc3SI\x89\xf8H\x8d \xde\xff\xffH\x8b1f\x90Hc\xdeH\x83\xe3\xfeH\x8byL\x8bYL\x8bIL\x8bQ \xae\xe81H\x8b1H9\xdeu\xdcH\x85\xfftYH\xc1\xe2 \x89\xc0H \xd01\xc9L)\xd8HM\xc8H\xb8\x00\x00\x00\x00\x00ʚ;1\xd2I\xf7\xf2H\xf7\xe1H\xa4\xc2 I\xd1L\x89\xc8H\xc1\xe8 H\xb9SZ\x9b\xa0/\xb8D\x00H\xf7\xe1H\xc1\xea Hi\xc2\x00ʚ;I)\xc1I\x89M\x89H1\xc0[ÿ\x00\x00\x00L\x89Ƹ\xe4\x00\x00\x00[\xc3\x00clang version 10.0.0 (https://github.com/llvm/llvm-project 407ac2eb5f136af5ddd213b8bcca176481ec5198)\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00GNU\x00gold 1.11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00Pp\xff\xff\xff\xff\xff\xa0\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x00 \x00\xf0p\xff\xff\xff\xff\xff\xa3\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x00\xa0p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x00\x00\xf1\xff\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x00\x00\xf1\xff\x00\xf0o\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00{\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x00 \x00\xb0p\xff\xff\xff\xff\xff_\x00\x00\x00\x00\x00\x00\x00\x99\x00\x00\x00\x00 \x00pp\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x00 \x00@p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\xbd\x00\x00\x00\x00 \x00\x80p\xff\xff\xff\xff\xff&\x00\x00\x00\x00\x00\x00\x00\xd2\x00\x00\x00\"\x00 \x00\xb0p\xff\xff\xff\xff\xff_\x00\x00\x00\x00\x00\x00\x00\xdf\x00\x00\x00\x00 \x00p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\xeb\x00\x00\x00\"\x00 \x00@p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\xf2\x00\x00\x00\"\x00 \x00\x80p\xff\xff\xff\xff\xff&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\x00 \x00p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\x00vdso.cc\x00vdso_time.cc\x00_ZN4vdso13ClockRealtimeEP8timespec\x00_ZN4vdso14ClockMonotonicEP8timespec\x00_DYNAMIC\x00VDSO_PRELINK\x00_params\x00LINUX_2.6\x00__vdso_gettimeofday\x00__kernel_rt_sigreturn\x00__vdso_getcpu\x00__vdso_clock_gettime\x00gettimeofday\x00__vdso_time\x00getcpu\x00clock_gettime\x00time\x00\x00.text\x00.comment\x00.dynstr\x00.eh_frame_hdr\x00.gnu.version\x00.dynsym\x00.hash\x00.note\x00.eh_frame\x00.gnu.version_d\x00.dynamic\x00.shstrtab\x00.strtab\x00.symtab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 p\xff\xff\xff\xff\xff \x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`p\xff\xff\xff\xff\xff`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00hp\xff\xff\xff\xff\xffh\x00\x00\x00\x00\x00\x00\x9b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\xff\xff\xffo\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q\x00\x00\x00\xfd\xff\xffo\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pp\xff\xff\xff\xff\xffp\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8p\xff\xff\xff\xff\xff\xb8\x00\x00\x00\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0p\xff\xff\xff\xff\xff\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pp\xff\xff\xff\xff\xffp\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcd\x00\x00\x00\x00\x00\x00\x83\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
+var vdsoBin = []byte("ELF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x008\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00p\xff\xff\xff\xff\xff\x96\x00\x00\x00\x00\x00\x00\x96\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\xc0p\xff\xff\xff\xff\xff\xc0p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00Tp\xff\xff\xff\xff\xffTp\xff\xff\xff\xff\xff@\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xe5td\x00\x00\x00\x94\x00\x00\x00\x00\x00\x00\x94p\xff\xff\xff\xff\xff\x94p\xff\xff\xff\xff\xffD\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\n\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"\x00 \x00p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\"\x00\x00\x00\x00 \x00p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\"\x00 \x00\xe0p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x00 \x00\xe0p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\"\x00 \x00\x80p\xff\xff\xff\xff\xff^\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x00 \x00\x80p\xff\xff\xff\xff\xff^\x00\x00\x00\x00\x00\x00\x00b\x00\x00\x00\"\x00 \x00@p\xff\xff\xff\xff\xff8\x00\x00\x00\x00\x00\x00\x00p\x00\x00\x00\x00 \x00@p\xff\xff\xff\xff\xff8\x00\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\x00 \x000p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00linux-vdso.so.1\x00LINUX_2.6\x00getcpu\x00__vdso_getcpu\x00time\x00__vdso_time\x00gettimeofday\x00__vdso_gettimeofday\x00clock_gettime\x00__vdso_clock_gettime\x00__kernel_rt_sigreturn\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xbf\xee \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6u\xae\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00GNU\x00gold 1.16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00GNU\x00\xaej\x80D\x93\xfb\xe3\x88\xf5<\xf5၅Sk\xe0\xc3;@\x00\x00\x00\x00\x00\x00\x9c \x00\x00\\\x00\x00\x00\xac \x00\x00t\x00\x00\x00\xec \x00\x00\x8c\x00\x00\x00L \x00\x00\xb4\x00\x00\x00| \x00\x00\xd4\x00\x00\x00\x8c \x00\x00\xec\x00\x00\x00L\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00zR\x00x \x90\x00\x00\x00\x00\x00\x00\x00\x008 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x000 \x00\x008\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00L\x00\x00\x00X \x00\x00^\x00\x00\x00\x00A\x86D\x83D0RAA\x00\x00\x00t\x00\x00\x00\x90 \x00\x00\"\x00\x00\x00\x00A\x83G XA\x00\x00\x00\x00\x94\x00\x00\x00\xa0 \x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x98 \x00\x00\xb3\x00\x00\x00\x00A\x83~\ni J\x00\x00\x00\xcc\x00\x00\x008 \x00\x00\xb6\x00\x00\x00\x00A\x83~\ni M\x00\x00\x00\x00\x00\x00\x00`p\xff\xff\xff\xff\xff \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00hp\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\x9b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xff\xffo\x00\x00\x00\x00p\xff\xff\xff\xff\xff\xfc\xff\xffo\x00\x00\x00\x00p\xff\xff\xff\xff\xff\xfd\xff\xffo\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\xc3\x84\x00\x00\x00\x00\x00\x83\xfft\x83\xfft\x85\xfft\"\xb8\xe4\x00\x00\x00\xc3f.\x84\x00\x00\x00\x00\x00H\x89\xf7\xe9x\x00\x00\x84\x00\x00\x00\x00\x00H\x89\xf7\xe9\xa8\x00\x00\x00\x84\x00\x00\x00\x00\x00UH\x89\xf5SH\x83\xecH\x85\xfft:H\x89\xfbH\x89\xe7\xe8\x87\x00\x00\x00\x85\xc0u:H\x8b$H\x8bL$H\xba\xcf\xf7S㥛\xc4 H\x89H\x89\xc8H\xc1\xf9?H\xf7\xeaH\xc1\xfaH)\xcaH\x89S1\xc0H\x85\xedtH\xc7E\x00\x00\x00\x00\x00H\x83\xc4[]\xc3f\x90SH\x89\xfbH\x83\xecH\x89\xe7\xe80\x00\x00\x00H\x8b$H\x85\xdbtH\x89H\x83\xc4[\xc3ff.\x84\x00\x00\x00\x00\x00\x00\xb85\x00\x00H\x98Ð\x90\x90\x90\x90\x90SH\x89\xfeH\x8d \xd5\xde\xff\xffH\x8b9\x83\xe7\xfeL\x8bQ(L\x8bA8H\x8bY0L\x8bY@Lc\xcf\xae\xe81H\x8b9L9\xcfu\xddM\x85\xd2tr\x89\xc0H\xc1\xe2 H \xc21\xc0H9\xd3+H\xb8\x00\x00\x00\x00\x00ʚ;H\x89\xd11\xd2I\xf7\xf3H)\xd9H\x89\xcfH\xc1\xff?H\xaf\xf8H\xf7\xe1H\xfaH\xac\xd0 H\xb9SZ\x9b\xa0/\xb8D\x00I\xc0[L\x89\xc2H\xc1\xea H\x89\xd0H\xf7\xe11\xc0H\xc1\xea H\x89Hi\xd2\x00ʚ;I)\xd0L\x89F\xc3@\x00\xb8\xe4\x00\x00\x001\xff[\xc3ff.\x84\x00\x00\x00\x00\x00f\x90SH\x89\xfeH\x8d \xde\xff\xffH\x8b9\x83\xe7\xfeL\x8bQL\x8bAH\x8bYL\x8bY Lc\xcf\xae\xe81H\x8b9L9\xcfu\xddM\x85\xd2tr\x89\xc0H\xc1\xe2 H \xc21\xc0H9\xd3+H\xb8\x00\x00\x00\x00\x00ʚ;H\x89\xd11\xd2I\xf7\xf3H)\xd9H\x89\xcfH\xc1\xff?H\xaf\xf8H\xf7\xe1H\xfaH\xac\xd0 H\xb9SZ\x9b\xa0/\xb8D\x00I\xc0[L\x89\xc2H\xc1\xea H\x89\xd0H\xf7\xe11\xc0H\xc1\xea H\x89Hi\xd2\x00ʚ;I)\xd0L\x89F\xc3@\x00\xb8\xe4\x00\x00\x00\xbf\x00\x00\x00[\xc3\x00GCC: (GNU) 9.3.1 20200317 (Red Hat 9.3.1-1)\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00 p\xff\xff\xff\xff\xff\xb3\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x00 \x00\xe0p\xff\xff\xff\xff\xff\xb6\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00 \x00\xc0p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x00\x00\xf1\xff\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x00\x00\xf1\xff\x00\xf0o\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00{\x00\x00\x00\x00\xf1\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x00\x00\x00\"\x00 \x00p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x00 \x00p\xff\xff\xff\xff\xff\n\x00\x00\x00\x00\x00\x00\x00\x9a\x00\x00\x00\"\x00 \x00\xe0p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x00 \x00\xe0p\xff\xff\xff\xff\xff\"\x00\x00\x00\x00\x00\x00\x00\xab\x00\x00\x00\"\x00 \x00\x80p\xff\xff\xff\xff\xff^\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\x00 \x00\x80p\xff\xff\xff\xff\xff^\x00\x00\x00\x00\x00\x00\x00\xcc\x00\x00\x00\"\x00 \x00@p\xff\xff\xff\xff\xff8\x00\x00\x00\x00\x00\x00\x00\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00 \x00@p\xff\xff\xff\xff\xff8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x000p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00vdso.cc\x00vdso_time.cc\x00_ZN4vdso13ClockRealtimeEP8timespec\x00_ZN4vdso14ClockMonotonicEP8timespec\x00_DYNAMIC\x00VDSO_PRELINK\x00_params\x00LINUX_2.6\x00getcpu\x00__vdso_getcpu\x00time\x00__vdso_time\x00gettimeofday\x00__vdso_gettimeofday\x00clock_gettime\x00_GLOBAL_OFFSET_TABLE_\x00__vdso_clock_gettime\x00__kernel_rt_sigreturn\x00\x00.text\x00.comment\x00.bss\x00.dynstr\x00.eh_frame_hdr\x00.gnu.version\x00.dynsym\x00.hash\x00.note\x00.eh_frame\x00.gnu.version_d\x00.dynamic\x00.shstrtab\x00.strtab\x00.symtab\x00.data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 p\xff\xff\xff\xff\xff \x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`p\xff\xff\xff\xff\xff`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00hp\xff\xff\xff\xff\xffh\x00\x00\x00\x00\x00\x00\x9b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\xff\xff\xffo\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x00\x00\x00\xfd\xff\xffo\x00\x00\x00\x00\x00\x00\x00p\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Tp\xff\xff\xff\xff\xffT\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00\x94p\xff\xff\xff\xff\xff\x94\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\x00\x00\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00\xd8p\xff\xff\xff\xff\xff\xd8\x00\x00\x00\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0p\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0p\xff\xff\xff\xff\xff\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000p\xff\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96p\xff\xff\xff\xff\xff\x96\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\x00\x00\x00\x00\x00\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x00\x00\x00\x00\x00\x00\x8e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
diff --git a/pkg/sentry/memmap/mappable_range.go b/pkg/sentry/memmap/mappable_range.go
index 6b6c2c685..6b6c2c685 100755..100644
--- a/pkg/sentry/memmap/mappable_range.go
+++ b/pkg/sentry/memmap/mappable_range.go
diff --git a/pkg/sentry/memmap/mapping_set_impl.go b/pkg/sentry/memmap/mapping_set_impl.go
index e632f28a5..cb4281950 100755..100644
--- a/pkg/sentry/memmap/mapping_set_impl.go
+++ b/pkg/sentry/memmap/mapping_set_impl.go
@@ -5,6 +5,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const MappingtrackGaps = 0
+
+var _ = uint8(MappingtrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type MappingdynamicGap [MappingtrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *MappingdynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *MappingdynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -263,8 +291,12 @@ func (s *MappingSet) Insert(gap MappingGapIterator, r MappableRange, val Mapping
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (mappingSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := MappingtrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (mappingSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -278,11 +310,16 @@ func (s *MappingSet) Insert(gap MappingGapIterator, r MappableRange, val Mapping
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (mappingSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := MappingtrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -309,11 +346,15 @@ func (s *MappingSet) InsertWithoutMerging(gap MappingGapIterator, r MappableRang
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *MappingSet) InsertWithoutMergingUnchecked(gap MappingGapIterator, r MappableRange, val MappingsOfRange) MappingIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := MappingtrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return MappingIterator{gap.node, gap.index}
}
@@ -328,12 +369,20 @@ func (s *MappingSet) Remove(seg MappingIterator) MappingGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if MappingtrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
mappingSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if MappingtrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(MappingGapIterator{seg.node, seg.index})
}
@@ -383,6 +432,7 @@ func (s *MappingSet) MergeUnchecked(first, second MappingIterator) MappingIterat
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -558,6 +608,12 @@ type Mappingnode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap MappingdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [MappingmaxDegree - 1]MappableRange
@@ -603,12 +659,12 @@ func (n *Mappingnode) nextSibling() *Mappingnode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *Mappingnode) rebalanceBeforeInsert(gap MappingGapIterator) MappingGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < MappingmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &Mappingnode{
@@ -644,6 +700,11 @@ func (n *Mappingnode) rebalanceBeforeInsert(gap MappingGapIterator) MappingGapIt
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if MappingtrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -681,6 +742,11 @@ func (n *Mappingnode) rebalanceBeforeInsert(gap MappingGapIterator) MappingGapIt
}
n.nrSegments = MappingminDegree - 1
+ if MappingtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -726,6 +792,11 @@ func (n *Mappingnode) rebalanceAfterRemove(gap MappingGapIterator) MappingGapIte
}
n.nrSegments++
sibling.nrSegments--
+
+ if MappingtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return MappingGapIterator{n, 0}
}
@@ -754,6 +825,11 @@ func (n *Mappingnode) rebalanceAfterRemove(gap MappingGapIterator) MappingGapIte
}
n.nrSegments++
sibling.nrSegments--
+
+ if MappingtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return MappingGapIterator{n, n.nrSegments}
@@ -786,6 +862,7 @@ func (n *Mappingnode) rebalanceAfterRemove(gap MappingGapIterator) MappingGapIte
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return MappingGapIterator{p, gap.index}
}
@@ -832,10 +909,146 @@ func (n *Mappingnode) rebalanceAfterRemove(gap MappingGapIterator) MappingGapIte
p.children[p.nrSegments] = nil
p.nrSegments--
+ if MappingtrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *Mappingnode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *Mappingnode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *Mappingnode) calculateMaxGapLeaf() uint64 {
+ max := MappingGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (MappingGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *Mappingnode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Mappingnode) searchFirstLargeEnoughGap(minSize uint64) MappingGapIterator {
+ if n.maxGap.Get() < minSize {
+ return MappingGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := MappingGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *Mappingnode) searchLastLargeEnoughGap(minSize uint64) MappingGapIterator {
+ if n.maxGap.Get() < minSize {
+ return MappingGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := MappingGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1141,6 +1354,114 @@ func (gap MappingGapIterator) NextGap() MappingGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap MappingGapIterator) NextLargeEnoughGap(minSize uint64) MappingGapIterator {
+ if MappingtrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap MappingGapIterator) nextLargeEnoughGapHelper(minSize uint64) MappingGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return MappingGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap MappingGapIterator) PrevLargeEnoughGap(minSize uint64) MappingGapIterator {
+ if MappingtrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap MappingGapIterator) prevLargeEnoughGapHelper(minSize uint64) MappingGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return MappingGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1207,7 +1528,15 @@ func (n *Mappingnode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if MappingtrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1259,6 +1588,46 @@ func (s *MappingSet) ImportSortedSlices(sds *MappingSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *MappingSet) segmentTestCheck(expectedSegments int, segFunc func(int, MappableRange, MappingsOfRange) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *MappingSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *MappingSet) saveRoot() *MappingSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/memmap/memmap_impl_state_autogen.go b/pkg/sentry/memmap/memmap_impl_state_autogen.go
index b231fd9c3..b66b03884 100755..100644
--- a/pkg/sentry/memmap/memmap_impl_state_autogen.go
+++ b/pkg/sentry/memmap/memmap_impl_state_autogen.go
@@ -25,6 +25,7 @@ func (x *Mappingnode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -36,6 +37,7 @@ func (x *Mappingnode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/memmap/memmap_state_autogen.go b/pkg/sentry/memmap/memmap_state_autogen.go
index 2072dbad2..2072dbad2 100755..100644
--- a/pkg/sentry/memmap/memmap_state_autogen.go
+++ b/pkg/sentry/memmap/memmap_state_autogen.go
diff --git a/pkg/sentry/mm/file_refcount_set.go b/pkg/sentry/mm/file_refcount_set.go
index 6b3081009..475c73fee 100755..100644
--- a/pkg/sentry/mm/file_refcount_set.go
+++ b/pkg/sentry/mm/file_refcount_set.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const fileRefcounttrackGaps = 0
+
+var _ = uint8(fileRefcounttrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type fileRefcountdynamicGap [fileRefcounttrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *fileRefcountdynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *fileRefcountdynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *fileRefcountSet) Insert(gap fileRefcountGapIterator, r __generics_impor
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (fileRefcountSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := fileRefcounttrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (fileRefcountSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *fileRefcountSet) Insert(gap fileRefcountGapIterator, r __generics_impor
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (fileRefcountSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := fileRefcounttrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *fileRefcountSet) InsertWithoutMerging(gap fileRefcountGapIterator, r __
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *fileRefcountSet) InsertWithoutMergingUnchecked(gap fileRefcountGapIterator, r __generics_imported0.FileRange, val int32) fileRefcountIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := fileRefcounttrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return fileRefcountIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *fileRefcountSet) Remove(seg fileRefcountIterator) fileRefcountGapIterat
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if fileRefcounttrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
fileRefcountSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if fileRefcounttrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(fileRefcountGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *fileRefcountSet) MergeUnchecked(first, second fileRefcountIterator) fil
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type fileRefcountnode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap fileRefcountdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [fileRefcountmaxDegree - 1]__generics_imported0.FileRange
@@ -607,12 +663,12 @@ func (n *fileRefcountnode) nextSibling() *fileRefcountnode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *fileRefcountnode) rebalanceBeforeInsert(gap fileRefcountGapIterator) fileRefcountGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < fileRefcountmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &fileRefcountnode{
@@ -648,6 +704,11 @@ func (n *fileRefcountnode) rebalanceBeforeInsert(gap fileRefcountGapIterator) fi
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if fileRefcounttrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *fileRefcountnode) rebalanceBeforeInsert(gap fileRefcountGapIterator) fi
}
n.nrSegments = fileRefcountminDegree - 1
+ if fileRefcounttrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *fileRefcountnode) rebalanceAfterRemove(gap fileRefcountGapIterator) fil
}
n.nrSegments++
sibling.nrSegments--
+
+ if fileRefcounttrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return fileRefcountGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *fileRefcountnode) rebalanceAfterRemove(gap fileRefcountGapIterator) fil
}
n.nrSegments++
sibling.nrSegments--
+
+ if fileRefcounttrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return fileRefcountGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *fileRefcountnode) rebalanceAfterRemove(gap fileRefcountGapIterator) fil
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return fileRefcountGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *fileRefcountnode) rebalanceAfterRemove(gap fileRefcountGapIterator) fil
p.children[p.nrSegments] = nil
p.nrSegments--
+ if fileRefcounttrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *fileRefcountnode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *fileRefcountnode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *fileRefcountnode) calculateMaxGapLeaf() uint64 {
+ max := fileRefcountGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (fileRefcountGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *fileRefcountnode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *fileRefcountnode) searchFirstLargeEnoughGap(minSize uint64) fileRefcountGapIterator {
+ if n.maxGap.Get() < minSize {
+ return fileRefcountGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := fileRefcountGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *fileRefcountnode) searchLastLargeEnoughGap(minSize uint64) fileRefcountGapIterator {
+ if n.maxGap.Get() < minSize {
+ return fileRefcountGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := fileRefcountGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap fileRefcountGapIterator) NextGap() fileRefcountGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap fileRefcountGapIterator) NextLargeEnoughGap(minSize uint64) fileRefcountGapIterator {
+ if fileRefcounttrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap fileRefcountGapIterator) nextLargeEnoughGapHelper(minSize uint64) fileRefcountGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return fileRefcountGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap fileRefcountGapIterator) PrevLargeEnoughGap(minSize uint64) fileRefcountGapIterator {
+ if fileRefcounttrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap fileRefcountGapIterator) prevLargeEnoughGapHelper(minSize uint64) fileRefcountGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return fileRefcountGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *fileRefcountnode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if fileRefcounttrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *fileRefcountSet) ImportSortedSlices(sds *fileRefcountSegmentDataSlices)
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *fileRefcountSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.FileRange, int32) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *fileRefcountSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *fileRefcountSet) saveRoot() *fileRefcountSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/mm/io_list.go b/pkg/sentry/mm/io_list.go
index ae0f19fc5..ae0f19fc5 100755..100644
--- a/pkg/sentry/mm/io_list.go
+++ b/pkg/sentry/mm/io_list.go
diff --git a/pkg/sentry/mm/mm_state_autogen.go b/pkg/sentry/mm/mm_state_autogen.go
index 4ef8fa9c6..fde35bcd8 100755..100644
--- a/pkg/sentry/mm/mm_state_autogen.go
+++ b/pkg/sentry/mm/mm_state_autogen.go
@@ -82,6 +82,7 @@ func (x *fileRefcountnode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -93,6 +94,7 @@ func (x *fileRefcountnode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
@@ -276,6 +278,7 @@ func (x *pmanode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -287,6 +290,7 @@ func (x *pmanode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
@@ -343,6 +347,7 @@ func (x *vmanode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -354,6 +359,7 @@ func (x *vmanode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/mm/pma_set.go b/pkg/sentry/mm/pma_set.go
index 8906e4edc..d0cc1f9d3 100755..100644
--- a/pkg/sentry/mm/pma_set.go
+++ b/pkg/sentry/mm/pma_set.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const pmatrackGaps = 0
+
+var _ = uint8(pmatrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type pmadynamicGap [pmatrackGaps]__generics_imported0.Addr
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *pmadynamicGap) Get() __generics_imported0.Addr {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *pmadynamicGap) Set(v __generics_imported0.Addr) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *pmaSet) Insert(gap pmaGapIterator, r __generics_imported0.AddrRange, va
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (pmaSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := pmatrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (pmaSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *pmaSet) Insert(gap pmaGapIterator, r __generics_imported0.AddrRange, va
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (pmaSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := pmatrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *pmaSet) InsertWithoutMerging(gap pmaGapIterator, r __generics_imported0
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *pmaSet) InsertWithoutMergingUnchecked(gap pmaGapIterator, r __generics_imported0.AddrRange, val pma) pmaIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := pmatrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return pmaIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *pmaSet) Remove(seg pmaIterator) pmaGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if pmatrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
pmaSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if pmatrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(pmaGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *pmaSet) MergeUnchecked(first, second pmaIterator) pmaIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type pmanode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap pmadynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [pmamaxDegree - 1]__generics_imported0.AddrRange
@@ -607,12 +663,12 @@ func (n *pmanode) nextSibling() *pmanode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *pmanode) rebalanceBeforeInsert(gap pmaGapIterator) pmaGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < pmamaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &pmanode{
@@ -648,6 +704,11 @@ func (n *pmanode) rebalanceBeforeInsert(gap pmaGapIterator) pmaGapIterator {
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if pmatrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *pmanode) rebalanceBeforeInsert(gap pmaGapIterator) pmaGapIterator {
}
n.nrSegments = pmaminDegree - 1
+ if pmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *pmanode) rebalanceAfterRemove(gap pmaGapIterator) pmaGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if pmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return pmaGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *pmanode) rebalanceAfterRemove(gap pmaGapIterator) pmaGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if pmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return pmaGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *pmanode) rebalanceAfterRemove(gap pmaGapIterator) pmaGapIterator {
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return pmaGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *pmanode) rebalanceAfterRemove(gap pmaGapIterator) pmaGapIterator {
p.children[p.nrSegments] = nil
p.nrSegments--
+ if pmatrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *pmanode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *pmanode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *pmanode) calculateMaxGapLeaf() __generics_imported0.Addr {
+ max := pmaGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (pmaGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *pmanode) calculateMaxGapInternal() __generics_imported0.Addr {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *pmanode) searchFirstLargeEnoughGap(minSize __generics_imported0.Addr) pmaGapIterator {
+ if n.maxGap.Get() < minSize {
+ return pmaGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := pmaGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *pmanode) searchLastLargeEnoughGap(minSize __generics_imported0.Addr) pmaGapIterator {
+ if n.maxGap.Get() < minSize {
+ return pmaGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := pmaGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap pmaGapIterator) NextGap() pmaGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap pmaGapIterator) NextLargeEnoughGap(minSize __generics_imported0.Addr) pmaGapIterator {
+ if pmatrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap pmaGapIterator) nextLargeEnoughGapHelper(minSize __generics_imported0.Addr) pmaGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return pmaGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap pmaGapIterator) PrevLargeEnoughGap(minSize __generics_imported0.Addr) pmaGapIterator {
+ if pmatrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap pmaGapIterator) prevLargeEnoughGapHelper(minSize __generics_imported0.Addr) pmaGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return pmaGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *pmanode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if pmatrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *pmaSet) ImportSortedSlices(sds *pmaSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *pmaSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.AddrRange, pma) error) error {
+ havePrev := false
+ prev := __generics_imported0.Addr(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *pmaSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *pmaSet) saveRoot() *pmaSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/mm/vma.go b/pkg/sentry/mm/vma.go
index 9a14e69e6..16d8207e9 100644
--- a/pkg/sentry/mm/vma.go
+++ b/pkg/sentry/mm/vma.go
@@ -195,7 +195,7 @@ func (mm *MemoryManager) applicationAddrRange() usermem.AddrRange {
// Preconditions: mm.mappingMu must be locked.
func (mm *MemoryManager) findLowestAvailableLocked(length, alignment uint64, bounds usermem.AddrRange) (usermem.Addr, error) {
- for gap := mm.vmas.LowerBoundGap(bounds.Start); gap.Ok() && gap.Start() < bounds.End; gap = gap.NextGap() {
+ for gap := mm.vmas.LowerBoundGap(bounds.Start); gap.Ok() && gap.Start() < bounds.End; gap = gap.NextLargeEnoughGap(usermem.Addr(length)) {
if gr := gap.availableRange().Intersect(bounds); uint64(gr.Length()) >= length {
// Can we shift up to match the alignment?
if offset := uint64(gr.Start) % alignment; offset != 0 {
@@ -214,7 +214,7 @@ func (mm *MemoryManager) findLowestAvailableLocked(length, alignment uint64, bou
// Preconditions: mm.mappingMu must be locked.
func (mm *MemoryManager) findHighestAvailableLocked(length, alignment uint64, bounds usermem.AddrRange) (usermem.Addr, error) {
- for gap := mm.vmas.UpperBoundGap(bounds.End); gap.Ok() && gap.End() > bounds.Start; gap = gap.PrevGap() {
+ for gap := mm.vmas.UpperBoundGap(bounds.End); gap.Ok() && gap.End() > bounds.Start; gap = gap.PrevLargeEnoughGap(usermem.Addr(length)) {
if gr := gap.availableRange().Intersect(bounds); uint64(gr.Length()) >= length {
// Can we shift down to match the alignment?
start := gr.End - usermem.Addr(length)
diff --git a/pkg/sentry/mm/vma_set.go b/pkg/sentry/mm/vma_set.go
index af6b1d317..e515ef105 100755..100644
--- a/pkg/sentry/mm/vma_set.go
+++ b/pkg/sentry/mm/vma_set.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const vmatrackGaps = 1
+
+var _ = uint8(vmatrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type vmadynamicGap [vmatrackGaps]__generics_imported0.Addr
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *vmadynamicGap) Get() __generics_imported0.Addr {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *vmadynamicGap) Set(v __generics_imported0.Addr) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *vmaSet) Insert(gap vmaGapIterator, r __generics_imported0.AddrRange, va
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (vmaSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := vmatrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (vmaSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *vmaSet) Insert(gap vmaGapIterator, r __generics_imported0.AddrRange, va
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (vmaSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := vmatrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *vmaSet) InsertWithoutMerging(gap vmaGapIterator, r __generics_imported0
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *vmaSet) InsertWithoutMergingUnchecked(gap vmaGapIterator, r __generics_imported0.AddrRange, val vma) vmaIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := vmatrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return vmaIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *vmaSet) Remove(seg vmaIterator) vmaGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if vmatrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
vmaSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if vmatrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(vmaGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *vmaSet) MergeUnchecked(first, second vmaIterator) vmaIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type vmanode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap vmadynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [vmamaxDegree - 1]__generics_imported0.AddrRange
@@ -607,12 +663,12 @@ func (n *vmanode) nextSibling() *vmanode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *vmanode) rebalanceBeforeInsert(gap vmaGapIterator) vmaGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < vmamaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &vmanode{
@@ -648,6 +704,11 @@ func (n *vmanode) rebalanceBeforeInsert(gap vmaGapIterator) vmaGapIterator {
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if vmatrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *vmanode) rebalanceBeforeInsert(gap vmaGapIterator) vmaGapIterator {
}
n.nrSegments = vmaminDegree - 1
+ if vmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *vmanode) rebalanceAfterRemove(gap vmaGapIterator) vmaGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if vmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return vmaGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *vmanode) rebalanceAfterRemove(gap vmaGapIterator) vmaGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if vmatrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return vmaGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *vmanode) rebalanceAfterRemove(gap vmaGapIterator) vmaGapIterator {
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return vmaGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *vmanode) rebalanceAfterRemove(gap vmaGapIterator) vmaGapIterator {
p.children[p.nrSegments] = nil
p.nrSegments--
+ if vmatrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *vmanode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *vmanode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *vmanode) calculateMaxGapLeaf() __generics_imported0.Addr {
+ max := vmaGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (vmaGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *vmanode) calculateMaxGapInternal() __generics_imported0.Addr {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *vmanode) searchFirstLargeEnoughGap(minSize __generics_imported0.Addr) vmaGapIterator {
+ if n.maxGap.Get() < minSize {
+ return vmaGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := vmaGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *vmanode) searchLastLargeEnoughGap(minSize __generics_imported0.Addr) vmaGapIterator {
+ if n.maxGap.Get() < minSize {
+ return vmaGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := vmaGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap vmaGapIterator) NextGap() vmaGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap vmaGapIterator) NextLargeEnoughGap(minSize __generics_imported0.Addr) vmaGapIterator {
+ if vmatrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap vmaGapIterator) nextLargeEnoughGapHelper(minSize __generics_imported0.Addr) vmaGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return vmaGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap vmaGapIterator) PrevLargeEnoughGap(minSize __generics_imported0.Addr) vmaGapIterator {
+ if vmatrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap vmaGapIterator) prevLargeEnoughGapHelper(minSize __generics_imported0.Addr) vmaGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return vmaGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *vmanode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if vmatrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *vmaSet) ImportSortedSlices(sds *vmaSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *vmaSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.AddrRange, vma) error) error {
+ havePrev := false
+ prev := __generics_imported0.Addr(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *vmaSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *vmaSet) saveRoot() *vmaSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/pgalloc/evictable_range.go b/pkg/sentry/pgalloc/evictable_range.go
index 10ce2ff44..10ce2ff44 100755..100644
--- a/pkg/sentry/pgalloc/evictable_range.go
+++ b/pkg/sentry/pgalloc/evictable_range.go
diff --git a/pkg/sentry/pgalloc/evictable_range_set.go b/pkg/sentry/pgalloc/evictable_range_set.go
index 6fbd02434..335446b4f 100755..100644
--- a/pkg/sentry/pgalloc/evictable_range_set.go
+++ b/pkg/sentry/pgalloc/evictable_range_set.go
@@ -5,6 +5,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const evictableRangetrackGaps = 0
+
+var _ = uint8(evictableRangetrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type evictableRangedynamicGap [evictableRangetrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *evictableRangedynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *evictableRangedynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -263,8 +291,12 @@ func (s *evictableRangeSet) Insert(gap evictableRangeGapIterator, r EvictableRan
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (evictableRangeSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := evictableRangetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (evictableRangeSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -278,11 +310,16 @@ func (s *evictableRangeSet) Insert(gap evictableRangeGapIterator, r EvictableRan
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (evictableRangeSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := evictableRangetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -309,11 +346,15 @@ func (s *evictableRangeSet) InsertWithoutMerging(gap evictableRangeGapIterator,
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *evictableRangeSet) InsertWithoutMergingUnchecked(gap evictableRangeGapIterator, r EvictableRange, val evictableRangeSetValue) evictableRangeIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := evictableRangetrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return evictableRangeIterator{gap.node, gap.index}
}
@@ -328,12 +369,20 @@ func (s *evictableRangeSet) Remove(seg evictableRangeIterator) evictableRangeGap
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if evictableRangetrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
evictableRangeSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if evictableRangetrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(evictableRangeGapIterator{seg.node, seg.index})
}
@@ -383,6 +432,7 @@ func (s *evictableRangeSet) MergeUnchecked(first, second evictableRangeIterator)
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -558,6 +608,12 @@ type evictableRangenode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap evictableRangedynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [evictableRangemaxDegree - 1]EvictableRange
@@ -603,12 +659,12 @@ func (n *evictableRangenode) nextSibling() *evictableRangenode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *evictableRangenode) rebalanceBeforeInsert(gap evictableRangeGapIterator) evictableRangeGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < evictableRangemaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &evictableRangenode{
@@ -644,6 +700,11 @@ func (n *evictableRangenode) rebalanceBeforeInsert(gap evictableRangeGapIterator
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if evictableRangetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -681,6 +742,11 @@ func (n *evictableRangenode) rebalanceBeforeInsert(gap evictableRangeGapIterator
}
n.nrSegments = evictableRangeminDegree - 1
+ if evictableRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -726,6 +792,11 @@ func (n *evictableRangenode) rebalanceAfterRemove(gap evictableRangeGapIterator)
}
n.nrSegments++
sibling.nrSegments--
+
+ if evictableRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return evictableRangeGapIterator{n, 0}
}
@@ -754,6 +825,11 @@ func (n *evictableRangenode) rebalanceAfterRemove(gap evictableRangeGapIterator)
}
n.nrSegments++
sibling.nrSegments--
+
+ if evictableRangetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return evictableRangeGapIterator{n, n.nrSegments}
@@ -786,6 +862,7 @@ func (n *evictableRangenode) rebalanceAfterRemove(gap evictableRangeGapIterator)
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return evictableRangeGapIterator{p, gap.index}
}
@@ -832,10 +909,146 @@ func (n *evictableRangenode) rebalanceAfterRemove(gap evictableRangeGapIterator)
p.children[p.nrSegments] = nil
p.nrSegments--
+ if evictableRangetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *evictableRangenode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *evictableRangenode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *evictableRangenode) calculateMaxGapLeaf() uint64 {
+ max := evictableRangeGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (evictableRangeGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *evictableRangenode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *evictableRangenode) searchFirstLargeEnoughGap(minSize uint64) evictableRangeGapIterator {
+ if n.maxGap.Get() < minSize {
+ return evictableRangeGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := evictableRangeGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *evictableRangenode) searchLastLargeEnoughGap(minSize uint64) evictableRangeGapIterator {
+ if n.maxGap.Get() < minSize {
+ return evictableRangeGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := evictableRangeGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1141,6 +1354,114 @@ func (gap evictableRangeGapIterator) NextGap() evictableRangeGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap evictableRangeGapIterator) NextLargeEnoughGap(minSize uint64) evictableRangeGapIterator {
+ if evictableRangetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap evictableRangeGapIterator) nextLargeEnoughGapHelper(minSize uint64) evictableRangeGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return evictableRangeGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap evictableRangeGapIterator) PrevLargeEnoughGap(minSize uint64) evictableRangeGapIterator {
+ if evictableRangetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap evictableRangeGapIterator) prevLargeEnoughGapHelper(minSize uint64) evictableRangeGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return evictableRangeGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1207,7 +1528,15 @@ func (n *evictableRangenode) writeDebugString(buf *bytes.Buffer, prefix string)
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if evictableRangetrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1259,6 +1588,46 @@ func (s *evictableRangeSet) ImportSortedSlices(sds *evictableRangeSegmentDataSli
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *evictableRangeSet) segmentTestCheck(expectedSegments int, segFunc func(int, EvictableRange, evictableRangeSetValue) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *evictableRangeSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *evictableRangeSet) saveRoot() *evictableRangeSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/pgalloc/pgalloc_state_autogen.go b/pkg/sentry/pgalloc/pgalloc_state_autogen.go
index 97e1c883b..469630448 100755..100644
--- a/pkg/sentry/pgalloc/pgalloc_state_autogen.go
+++ b/pkg/sentry/pgalloc/pgalloc_state_autogen.go
@@ -38,6 +38,7 @@ func (x *evictableRangenode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -49,6 +50,7 @@ func (x *evictableRangenode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
@@ -103,6 +105,7 @@ func (x *usagenode) save(m state.Map) {
m.Save("parent", &x.parent)
m.Save("parentIndex", &x.parentIndex)
m.Save("hasChildren", &x.hasChildren)
+ m.Save("maxGap", &x.maxGap)
m.Save("keys", &x.keys)
m.Save("values", &x.values)
m.Save("children", &x.children)
@@ -114,6 +117,7 @@ func (x *usagenode) load(m state.Map) {
m.Load("parent", &x.parent)
m.Load("parentIndex", &x.parentIndex)
m.Load("hasChildren", &x.hasChildren)
+ m.Load("maxGap", &x.maxGap)
m.Load("keys", &x.keys)
m.Load("values", &x.values)
m.Load("children", &x.children)
diff --git a/pkg/sentry/pgalloc/pgalloc_unsafe_state_autogen.go b/pkg/sentry/pgalloc/pgalloc_unsafe_state_autogen.go
index 87c214008..87c214008 100755..100644
--- a/pkg/sentry/pgalloc/pgalloc_unsafe_state_autogen.go
+++ b/pkg/sentry/pgalloc/pgalloc_unsafe_state_autogen.go
diff --git a/pkg/sentry/pgalloc/usage_set.go b/pkg/sentry/pgalloc/usage_set.go
index 37b9235ca..79db792d9 100755..100644
--- a/pkg/sentry/pgalloc/usage_set.go
+++ b/pkg/sentry/pgalloc/usage_set.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const usagetrackGaps = 0
+
+var _ = uint8(usagetrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type usagedynamicGap [usagetrackGaps]uint64
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *usagedynamicGap) Get() uint64 {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *usagedynamicGap) Set(v uint64) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *usageSet) Insert(gap usageGapIterator, r __generics_imported0.FileRange
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (usageSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := usagetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (usageSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *usageSet) Insert(gap usageGapIterator, r __generics_imported0.FileRange
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (usageSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := usagetrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *usageSet) InsertWithoutMerging(gap usageGapIterator, r __generics_impor
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *usageSet) InsertWithoutMergingUnchecked(gap usageGapIterator, r __generics_imported0.FileRange, val usageInfo) usageIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := usagetrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return usageIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *usageSet) Remove(seg usageIterator) usageGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if usagetrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
usageSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if usagetrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(usageGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *usageSet) MergeUnchecked(first, second usageIterator) usageIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type usagenode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap usagedynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [usagemaxDegree - 1]__generics_imported0.FileRange
@@ -607,12 +663,12 @@ func (n *usagenode) nextSibling() *usagenode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *usagenode) rebalanceBeforeInsert(gap usageGapIterator) usageGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < usagemaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &usagenode{
@@ -648,6 +704,11 @@ func (n *usagenode) rebalanceBeforeInsert(gap usageGapIterator) usageGapIterator
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if usagetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *usagenode) rebalanceBeforeInsert(gap usageGapIterator) usageGapIterator
}
n.nrSegments = usageminDegree - 1
+ if usagetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *usagenode) rebalanceAfterRemove(gap usageGapIterator) usageGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if usagetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return usageGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *usagenode) rebalanceAfterRemove(gap usageGapIterator) usageGapIterator
}
n.nrSegments++
sibling.nrSegments--
+
+ if usagetrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return usageGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *usagenode) rebalanceAfterRemove(gap usageGapIterator) usageGapIterator
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return usageGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *usagenode) rebalanceAfterRemove(gap usageGapIterator) usageGapIterator
p.children[p.nrSegments] = nil
p.nrSegments--
+ if usagetrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *usagenode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *usagenode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *usagenode) calculateMaxGapLeaf() uint64 {
+ max := usageGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (usageGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *usagenode) calculateMaxGapInternal() uint64 {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *usagenode) searchFirstLargeEnoughGap(minSize uint64) usageGapIterator {
+ if n.maxGap.Get() < minSize {
+ return usageGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := usageGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *usagenode) searchLastLargeEnoughGap(minSize uint64) usageGapIterator {
+ if n.maxGap.Get() < minSize {
+ return usageGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := usageGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap usageGapIterator) NextGap() usageGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap usageGapIterator) NextLargeEnoughGap(minSize uint64) usageGapIterator {
+ if usagetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap usageGapIterator) nextLargeEnoughGapHelper(minSize uint64) usageGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return usageGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap usageGapIterator) PrevLargeEnoughGap(minSize uint64) usageGapIterator {
+ if usagetrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap usageGapIterator) prevLargeEnoughGapHelper(minSize uint64) usageGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return usageGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *usagenode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if usagetrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *usageSet) ImportSortedSlices(sds *usageSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *usageSet) segmentTestCheck(expectedSegments int, segFunc func(int, __generics_imported0.FileRange, usageInfo) error) error {
+ havePrev := false
+ prev := uint64(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *usageSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *usageSet) saveRoot() *usageSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/sentry/platform/file_range.go b/pkg/sentry/platform/file_range.go
index 685d360e3..685d360e3 100755..100644
--- a/pkg/sentry/platform/file_range.go
+++ b/pkg/sentry/platform/file_range.go
diff --git a/pkg/sentry/platform/interrupt/interrupt_state_autogen.go b/pkg/sentry/platform/interrupt/interrupt_state_autogen.go
index 1336e5f01..1336e5f01 100755..100644
--- a/pkg/sentry/platform/interrupt/interrupt_state_autogen.go
+++ b/pkg/sentry/platform/interrupt/interrupt_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/bluepill_arm64.go b/pkg/sentry/platform/kvm/bluepill_arm64.go
index c215d443c..c215d443c 100755..100644
--- a/pkg/sentry/platform/kvm/bluepill_arm64.go
+++ b/pkg/sentry/platform/kvm/bluepill_arm64.go
diff --git a/pkg/sentry/platform/kvm/bluepill_arm64.s b/pkg/sentry/platform/kvm/bluepill_arm64.s
index 04efa0147..04efa0147 100755..100644
--- a/pkg/sentry/platform/kvm/bluepill_arm64.s
+++ b/pkg/sentry/platform/kvm/bluepill_arm64.s
diff --git a/pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go b/pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go
index 4ca2b7717..4ca2b7717 100755..100644
--- a/pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go
+++ b/pkg/sentry/platform/kvm/bluepill_arm64_unsafe.go
diff --git a/pkg/sentry/platform/kvm/filters_amd64.go b/pkg/sentry/platform/kvm/filters_amd64.go
index 7d949f1dd..7d949f1dd 100755..100644
--- a/pkg/sentry/platform/kvm/filters_amd64.go
+++ b/pkg/sentry/platform/kvm/filters_amd64.go
diff --git a/pkg/sentry/platform/kvm/filters_arm64.go b/pkg/sentry/platform/kvm/filters_arm64.go
index 9245d07c2..9245d07c2 100755..100644
--- a/pkg/sentry/platform/kvm/filters_arm64.go
+++ b/pkg/sentry/platform/kvm/filters_arm64.go
diff --git a/pkg/sentry/platform/kvm/kvm_amd64_state_autogen.go b/pkg/sentry/platform/kvm/kvm_amd64_state_autogen.go
index a69cbee8b..a69cbee8b 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_amd64_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_amd64_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/kvm_amd64_unsafe_state_autogen.go b/pkg/sentry/platform/kvm/kvm_amd64_unsafe_state_autogen.go
index a69cbee8b..a69cbee8b 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_amd64_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_amd64_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/kvm_arm64.go b/pkg/sentry/platform/kvm/kvm_arm64.go
index 29d457a7e..29d457a7e 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_arm64.go
+++ b/pkg/sentry/platform/kvm/kvm_arm64.go
diff --git a/pkg/sentry/platform/kvm/kvm_arm64_state_autogen.go b/pkg/sentry/platform/kvm/kvm_arm64_state_autogen.go
index 90183b764..90183b764 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_arm64_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_arm64_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/kvm_arm64_unsafe.go b/pkg/sentry/platform/kvm/kvm_arm64_unsafe.go
index 6531bae1d..6531bae1d 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_arm64_unsafe.go
+++ b/pkg/sentry/platform/kvm/kvm_arm64_unsafe.go
diff --git a/pkg/sentry/platform/kvm/kvm_arm64_unsafe_state_autogen.go b/pkg/sentry/platform/kvm/kvm_arm64_unsafe_state_autogen.go
index 90183b764..90183b764 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_arm64_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_arm64_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/kvm_const_arm64.go b/pkg/sentry/platform/kvm/kvm_const_arm64.go
index 531ae8b1e..531ae8b1e 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_const_arm64.go
+++ b/pkg/sentry/platform/kvm/kvm_const_arm64.go
diff --git a/pkg/sentry/platform/kvm/kvm_state_autogen.go b/pkg/sentry/platform/kvm/kvm_state_autogen.go
index 8d85b96d0..8d85b96d0 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/kvm_unsafe_state_autogen.go b/pkg/sentry/platform/kvm/kvm_unsafe_state_autogen.go
index 2325262dc..2325262dc 100755..100644
--- a/pkg/sentry/platform/kvm/kvm_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/kvm/kvm_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/kvm/machine_arm64.go b/pkg/sentry/platform/kvm/machine_arm64.go
index e42505542..e42505542 100755..100644
--- a/pkg/sentry/platform/kvm/machine_arm64.go
+++ b/pkg/sentry/platform/kvm/machine_arm64.go
diff --git a/pkg/sentry/platform/kvm/machine_arm64_unsafe.go b/pkg/sentry/platform/kvm/machine_arm64_unsafe.go
index 3c02cef7c..3c02cef7c 100755..100644
--- a/pkg/sentry/platform/kvm/machine_arm64_unsafe.go
+++ b/pkg/sentry/platform/kvm/machine_arm64_unsafe.go
diff --git a/pkg/sentry/platform/kvm/physical_map_amd64.go b/pkg/sentry/platform/kvm/physical_map_amd64.go
index c5adfb577..c5adfb577 100755..100644
--- a/pkg/sentry/platform/kvm/physical_map_amd64.go
+++ b/pkg/sentry/platform/kvm/physical_map_amd64.go
diff --git a/pkg/sentry/platform/kvm/physical_map_arm64.go b/pkg/sentry/platform/kvm/physical_map_arm64.go
index 4d8561453..4d8561453 100755..100644
--- a/pkg/sentry/platform/kvm/physical_map_arm64.go
+++ b/pkg/sentry/platform/kvm/physical_map_arm64.go
diff --git a/pkg/sentry/platform/platform_state_autogen.go b/pkg/sentry/platform/platform_state_autogen.go
index 7597195ef..7597195ef 100755..100644
--- a/pkg/sentry/platform/platform_state_autogen.go
+++ b/pkg/sentry/platform/platform_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_amd64_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_amd64_state_autogen.go
index f730ab393..f730ab393 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_amd64_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_amd64_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_arm64_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_arm64_state_autogen.go
index 6239d1305..6239d1305 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_arm64_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_arm64_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe.go b/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe.go
index 32b8a6be9..32b8a6be9 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe.go
+++ b/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe_state_autogen.go
index 6239d1305..6239d1305 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_arm64_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_linux_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_linux_state_autogen.go
index 9f90aef93..9f90aef93 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_linux_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_linux_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_linux_unsafe_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_linux_unsafe_state_autogen.go
index 45d94c547..45d94c547 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_linux_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_linux_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_state_autogen.go
index 1bf0526f9..1bf0526f9 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_state_autogen.go
diff --git a/pkg/sentry/platform/ptrace/ptrace_unsafe_state_autogen.go b/pkg/sentry/platform/ptrace/ptrace_unsafe_state_autogen.go
index 4526fc387..4526fc387 100755..100644
--- a/pkg/sentry/platform/ptrace/ptrace_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ptrace/ptrace_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/defs_impl_amd64.go b/pkg/sentry/platform/ring0/defs_impl_amd64.go
index 029d699fe..50ac3040e 100755..100644
--- a/pkg/sentry/platform/ring0/defs_impl_amd64.go
+++ b/pkg/sentry/platform/ring0/defs_impl_amd64.go
@@ -1,11 +1,11 @@
package ring0
import (
- "gvisor.dev/gvisor/pkg/cpuid"
- "gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/platform/ring0/pagetables"
"fmt"
+ "gvisor.dev/gvisor/pkg/cpuid"
+ "gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/usermem"
"io"
"reflect"
diff --git a/pkg/sentry/platform/ring0/defs_impl_arm64.go b/pkg/sentry/platform/ring0/defs_impl_arm64.go
index 93f23047d..93f23047d 100755..100644
--- a/pkg/sentry/platform/ring0/defs_impl_arm64.go
+++ b/pkg/sentry/platform/ring0/defs_impl_arm64.go
diff --git a/pkg/sentry/platform/ring0/entry_arm64.go b/pkg/sentry/platform/ring0/entry_arm64.go
index 62a93f3d6..62a93f3d6 100755..100644
--- a/pkg/sentry/platform/ring0/entry_arm64.go
+++ b/pkg/sentry/platform/ring0/entry_arm64.go
diff --git a/pkg/sentry/platform/ring0/entry_impl_amd64.s b/pkg/sentry/platform/ring0/entry_impl_amd64.s
index daba45f9d..daba45f9d 100755..100644
--- a/pkg/sentry/platform/ring0/entry_impl_amd64.s
+++ b/pkg/sentry/platform/ring0/entry_impl_amd64.s
diff --git a/pkg/sentry/platform/ring0/entry_impl_arm64.s b/pkg/sentry/platform/ring0/entry_impl_arm64.s
index ea202219a..ea202219a 100755..100644
--- a/pkg/sentry/platform/ring0/entry_impl_arm64.s
+++ b/pkg/sentry/platform/ring0/entry_impl_arm64.s
diff --git a/pkg/sentry/platform/ring0/kernel_arm64.go b/pkg/sentry/platform/ring0/kernel_arm64.go
index ccacaea6b..ccacaea6b 100755..100644
--- a/pkg/sentry/platform/ring0/kernel_arm64.go
+++ b/pkg/sentry/platform/ring0/kernel_arm64.go
diff --git a/pkg/sentry/platform/ring0/lib_arm64.go b/pkg/sentry/platform/ring0/lib_arm64.go
index 444a83913..a6345010d 100755..100644
--- a/pkg/sentry/platform/ring0/lib_arm64.go
+++ b/pkg/sentry/platform/ring0/lib_arm64.go
@@ -38,6 +38,12 @@ func SaveVRegs(*byte)
// LoadVRegs loads V0-V31 registers.
func LoadVRegs(*byte)
+// GetTLS returns the value of TPIDR_EL0 register.
+func GetTLS() (value uint64)
+
+// SetTLS writes the TPIDR_EL0 value.
+func SetTLS(value uint64)
+
// Init sets function pointers based on architectural features.
//
// This must be called prior to using ring0.
diff --git a/pkg/sentry/platform/ring0/lib_arm64.s b/pkg/sentry/platform/ring0/lib_arm64.s
index 0e6a6235b..b63e14b41 100755..100644
--- a/pkg/sentry/platform/ring0/lib_arm64.s
+++ b/pkg/sentry/platform/ring0/lib_arm64.s
@@ -15,6 +15,16 @@
#include "funcdata.h"
#include "textflag.h"
+TEXT ·GetTLS(SB),NOSPLIT,$0-8
+ MRS TPIDR_EL0, R1
+ MOVD R1, ret+0(FP)
+ RET
+
+TEXT ·SetTLS(SB),NOSPLIT,$0-8
+ MOVD addr+0(FP), R1
+ MSR R1, TPIDR_EL0
+ RET
+
TEXT ·CPACREL1(SB),NOSPLIT,$0-8
WORD $0xd5381041 // MRS CPACR_EL1, R1
MOVD R1, ret+0(FP)
diff --git a/pkg/sentry/platform/ring0/lib_arm64_unsafe.go b/pkg/sentry/platform/ring0/lib_arm64_unsafe.go
index c05166fea..c05166fea 100755..100644
--- a/pkg/sentry/platform/ring0/lib_arm64_unsafe.go
+++ b/pkg/sentry/platform/ring0/lib_arm64_unsafe.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64.go b/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64.go
index 78510ebed..78510ebed 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64_state_autogen.go
index a24523f87..a24523f87 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_aarch64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_amd64_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_amd64_state_autogen.go
index f48a8acd1..f48a8acd1 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_amd64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_amd64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_arm64.go b/pkg/sentry/platform/ring0/pagetables/pagetables_arm64.go
index 1a49f12a2..1a49f12a2 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_arm64.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_arm64.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_arm64_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_arm64_state_autogen.go
index ae9d2b272..ae9d2b272 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_arm64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_arm64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_state_autogen.go
index 4c4540603..4c4540603 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_unsafe_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_unsafe_state_autogen.go
index 4c4540603..4c4540603 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pagetables_x86_state_autogen.go b/pkg/sentry/platform/ring0/pagetables/pagetables_x86_state_autogen.go
index 6fe78c51c..6fe78c51c 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pagetables_x86_state_autogen.go
+++ b/pkg/sentry/platform/ring0/pagetables/pagetables_x86_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pcids.go b/pkg/sentry/platform/ring0/pagetables/pcids.go
index 964496aac..964496aac 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pcids.go
+++ b/pkg/sentry/platform/ring0/pagetables/pcids.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.go b/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.go
index fbfd41d83..fbfd41d83 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.go
+++ b/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.go
diff --git a/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.s b/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.s
index e9d62d768..e9d62d768 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.s
+++ b/pkg/sentry/platform/ring0/pagetables/pcids_aarch64.s
diff --git a/pkg/sentry/platform/ring0/pagetables/pcids_x86.go b/pkg/sentry/platform/ring0/pagetables/pcids_x86.go
index 91fc5e8dd..91fc5e8dd 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/pcids_x86.go
+++ b/pkg/sentry/platform/ring0/pagetables/pcids_x86.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_amd64.go b/pkg/sentry/platform/ring0/pagetables/walker_amd64.go
index 8f9dacd93..8f9dacd93 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_amd64.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_amd64.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_arm64.go b/pkg/sentry/platform/ring0/pagetables/walker_arm64.go
index c261d393a..c261d393a 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_arm64.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_arm64.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_empty.go b/pkg/sentry/platform/ring0/pagetables/walker_empty.go
index 417784e17..417784e17 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_empty.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_empty.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_lookup.go b/pkg/sentry/platform/ring0/pagetables/walker_lookup.go
index 906c9c50f..906c9c50f 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_lookup.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_lookup.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_map.go b/pkg/sentry/platform/ring0/pagetables/walker_map.go
index 61ee3c825..61ee3c825 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_map.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_map.go
diff --git a/pkg/sentry/platform/ring0/pagetables/walker_unmap.go b/pkg/sentry/platform/ring0/pagetables/walker_unmap.go
index be2aa0ce4..be2aa0ce4 100755..100644
--- a/pkg/sentry/platform/ring0/pagetables/walker_unmap.go
+++ b/pkg/sentry/platform/ring0/pagetables/walker_unmap.go
diff --git a/pkg/sentry/platform/ring0/ring0_amd64_state_autogen.go b/pkg/sentry/platform/ring0/ring0_amd64_state_autogen.go
index 96cf5d331..96cf5d331 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_amd64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_amd64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_arm64_state_autogen.go b/pkg/sentry/platform/ring0/ring0_arm64_state_autogen.go
index 7f2ab3537..7f2ab3537 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_arm64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_arm64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_arm64_unsafe_state_autogen.go b/pkg/sentry/platform/ring0/ring0_arm64_unsafe_state_autogen.go
index fa617c57e..fa617c57e 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_arm64_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_arm64_unsafe_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_impl_amd64_state_autogen.go b/pkg/sentry/platform/ring0/ring0_impl_amd64_state_autogen.go
index 327aba163..327aba163 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_impl_amd64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_impl_amd64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_impl_arm64_state_autogen.go b/pkg/sentry/platform/ring0/ring0_impl_arm64_state_autogen.go
index 327aba163..327aba163 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_impl_arm64_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_impl_arm64_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_state_autogen.go b/pkg/sentry/platform/ring0/ring0_state_autogen.go
index 327aba163..327aba163 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_state_autogen.go
diff --git a/pkg/sentry/platform/ring0/ring0_unsafe_state_autogen.go b/pkg/sentry/platform/ring0/ring0_unsafe_state_autogen.go
index 327aba163..327aba163 100755..100644
--- a/pkg/sentry/platform/ring0/ring0_unsafe_state_autogen.go
+++ b/pkg/sentry/platform/ring0/ring0_unsafe_state_autogen.go
diff --git a/pkg/sentry/sighandling/sighandling_state_autogen.go b/pkg/sentry/sighandling/sighandling_state_autogen.go
index da9d96382..da9d96382 100755..100644
--- a/pkg/sentry/sighandling/sighandling_state_autogen.go
+++ b/pkg/sentry/sighandling/sighandling_state_autogen.go
diff --git a/pkg/sentry/sighandling/sighandling_unsafe_state_autogen.go b/pkg/sentry/sighandling/sighandling_unsafe_state_autogen.go
index da9d96382..da9d96382 100755..100644
--- a/pkg/sentry/sighandling/sighandling_unsafe_state_autogen.go
+++ b/pkg/sentry/sighandling/sighandling_unsafe_state_autogen.go
diff --git a/pkg/sentry/socket/control/control_state_autogen.go b/pkg/sentry/socket/control/control_state_autogen.go
index 8a37b04c0..8a37b04c0 100755..100644
--- a/pkg/sentry/socket/control/control_state_autogen.go
+++ b/pkg/sentry/socket/control/control_state_autogen.go
diff --git a/pkg/sentry/socket/control/control_vfs2.go b/pkg/sentry/socket/control/control_vfs2.go
index fd08179be..fd08179be 100755..100644
--- a/pkg/sentry/socket/control/control_vfs2.go
+++ b/pkg/sentry/socket/control/control_vfs2.go
diff --git a/pkg/sentry/socket/hostinet/hostinet_impl_state_autogen.go b/pkg/sentry/socket/hostinet/hostinet_impl_state_autogen.go
index b0a59ba93..b0a59ba93 100755..100644
--- a/pkg/sentry/socket/hostinet/hostinet_impl_state_autogen.go
+++ b/pkg/sentry/socket/hostinet/hostinet_impl_state_autogen.go
diff --git a/pkg/sentry/socket/hostinet/hostinet_state_autogen.go b/pkg/sentry/socket/hostinet/hostinet_state_autogen.go
index 333811074..333811074 100755..100644
--- a/pkg/sentry/socket/hostinet/hostinet_state_autogen.go
+++ b/pkg/sentry/socket/hostinet/hostinet_state_autogen.go
diff --git a/pkg/sentry/socket/hostinet/hostinet_unsafe_state_autogen.go b/pkg/sentry/socket/hostinet/hostinet_unsafe_state_autogen.go
index b0a59ba93..b0a59ba93 100755..100644
--- a/pkg/sentry/socket/hostinet/hostinet_unsafe_state_autogen.go
+++ b/pkg/sentry/socket/hostinet/hostinet_unsafe_state_autogen.go
diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go
index b49433326..c11e82c10 100644
--- a/pkg/sentry/socket/hostinet/socket.go
+++ b/pkg/sentry/socket/hostinet/socket.go
@@ -555,7 +555,7 @@ func (s *socketOpsCommon) SendMsg(t *kernel.Task, src usermem.IOSequence, to []b
if uint64(src.NumBytes()) != srcs.NumBytes() {
return 0, nil
}
- if srcs.IsEmpty() {
+ if srcs.IsEmpty() && len(controlBuf) == 0 {
return 0, nil
}
diff --git a/pkg/sentry/socket/hostinet/socket_vfs2.go b/pkg/sentry/socket/hostinet/socket_vfs2.go
index 677743113..677743113 100755..100644
--- a/pkg/sentry/socket/hostinet/socket_vfs2.go
+++ b/pkg/sentry/socket/hostinet/socket_vfs2.go
diff --git a/pkg/sentry/socket/hostinet/sockopt_impl.go b/pkg/sentry/socket/hostinet/sockopt_impl.go
index 8a783712e..8a783712e 100755..100644
--- a/pkg/sentry/socket/hostinet/sockopt_impl.go
+++ b/pkg/sentry/socket/hostinet/sockopt_impl.go
diff --git a/pkg/sentry/socket/netfilter/extensions.go b/pkg/sentry/socket/netfilter/extensions.go
index 0336a32d8..0336a32d8 100755..100644
--- a/pkg/sentry/socket/netfilter/extensions.go
+++ b/pkg/sentry/socket/netfilter/extensions.go
diff --git a/pkg/sentry/socket/netfilter/netfilter_state_autogen.go b/pkg/sentry/socket/netfilter/netfilter_state_autogen.go
index 6e95d89a4..6e95d89a4 100755..100644
--- a/pkg/sentry/socket/netfilter/netfilter_state_autogen.go
+++ b/pkg/sentry/socket/netfilter/netfilter_state_autogen.go
diff --git a/pkg/sentry/socket/netfilter/owner_matcher.go b/pkg/sentry/socket/netfilter/owner_matcher.go
index 3863293c7..3863293c7 100755..100644
--- a/pkg/sentry/socket/netfilter/owner_matcher.go
+++ b/pkg/sentry/socket/netfilter/owner_matcher.go
diff --git a/pkg/sentry/socket/netfilter/targets.go b/pkg/sentry/socket/netfilter/targets.go
index 84abe8d29..84abe8d29 100755..100644
--- a/pkg/sentry/socket/netfilter/targets.go
+++ b/pkg/sentry/socket/netfilter/targets.go
diff --git a/pkg/sentry/socket/netfilter/tcp_matcher.go b/pkg/sentry/socket/netfilter/tcp_matcher.go
index 57a1e1c12..57a1e1c12 100755..100644
--- a/pkg/sentry/socket/netfilter/tcp_matcher.go
+++ b/pkg/sentry/socket/netfilter/tcp_matcher.go
diff --git a/pkg/sentry/socket/netfilter/udp_matcher.go b/pkg/sentry/socket/netfilter/udp_matcher.go
index cfa9e621d..cfa9e621d 100755..100644
--- a/pkg/sentry/socket/netfilter/udp_matcher.go
+++ b/pkg/sentry/socket/netfilter/udp_matcher.go
diff --git a/pkg/sentry/socket/netlink/netlink_state_autogen.go b/pkg/sentry/socket/netlink/netlink_state_autogen.go
index fa6a7ce74..fa6a7ce74 100755..100644
--- a/pkg/sentry/socket/netlink/netlink_state_autogen.go
+++ b/pkg/sentry/socket/netlink/netlink_state_autogen.go
diff --git a/pkg/sentry/socket/netlink/port/port_state_autogen.go b/pkg/sentry/socket/netlink/port/port_state_autogen.go
index c509cc7d5..c509cc7d5 100755..100644
--- a/pkg/sentry/socket/netlink/port/port_state_autogen.go
+++ b/pkg/sentry/socket/netlink/port/port_state_autogen.go
diff --git a/pkg/sentry/socket/netlink/provider_vfs2.go b/pkg/sentry/socket/netlink/provider_vfs2.go
index bb205be0d..bb205be0d 100755..100644
--- a/pkg/sentry/socket/netlink/provider_vfs2.go
+++ b/pkg/sentry/socket/netlink/provider_vfs2.go
diff --git a/pkg/sentry/socket/netlink/route/route_state_autogen.go b/pkg/sentry/socket/netlink/route/route_state_autogen.go
index bd10fe189..bd10fe189 100755..100644
--- a/pkg/sentry/socket/netlink/route/route_state_autogen.go
+++ b/pkg/sentry/socket/netlink/route/route_state_autogen.go
diff --git a/pkg/sentry/socket/netlink/socket_vfs2.go b/pkg/sentry/socket/netlink/socket_vfs2.go
index b854bf990..b854bf990 100755..100644
--- a/pkg/sentry/socket/netlink/socket_vfs2.go
+++ b/pkg/sentry/socket/netlink/socket_vfs2.go
diff --git a/pkg/sentry/socket/netlink/uevent/protocol.go b/pkg/sentry/socket/netlink/uevent/protocol.go
index 029ba21b5..029ba21b5 100755..100644
--- a/pkg/sentry/socket/netlink/uevent/protocol.go
+++ b/pkg/sentry/socket/netlink/uevent/protocol.go
diff --git a/pkg/sentry/socket/netlink/uevent/uevent_state_autogen.go b/pkg/sentry/socket/netlink/uevent/uevent_state_autogen.go
index b82dddf32..b82dddf32 100755..100644
--- a/pkg/sentry/socket/netlink/uevent/uevent_state_autogen.go
+++ b/pkg/sentry/socket/netlink/uevent/uevent_state_autogen.go
diff --git a/pkg/sentry/socket/netstack/device.go b/pkg/sentry/socket/netstack/device.go
index fbeb89fb8..fbeb89fb8 100755..100644
--- a/pkg/sentry/socket/netstack/device.go
+++ b/pkg/sentry/socket/netstack/device.go
diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go
index 60df51dae..60df51dae 100755..100644
--- a/pkg/sentry/socket/netstack/netstack.go
+++ b/pkg/sentry/socket/netstack/netstack.go
diff --git a/pkg/sentry/socket/netstack/netstack_state_autogen.go b/pkg/sentry/socket/netstack/netstack_state_autogen.go
index a1f61607f..a1f61607f 100755..100644
--- a/pkg/sentry/socket/netstack/netstack_state_autogen.go
+++ b/pkg/sentry/socket/netstack/netstack_state_autogen.go
diff --git a/pkg/sentry/socket/netstack/netstack_vfs2.go b/pkg/sentry/socket/netstack/netstack_vfs2.go
index fcd8013c0..fcd8013c0 100755..100644
--- a/pkg/sentry/socket/netstack/netstack_vfs2.go
+++ b/pkg/sentry/socket/netstack/netstack_vfs2.go
diff --git a/pkg/sentry/socket/netstack/provider.go b/pkg/sentry/socket/netstack/provider.go
index ead3b2b79..ead3b2b79 100755..100644
--- a/pkg/sentry/socket/netstack/provider.go
+++ b/pkg/sentry/socket/netstack/provider.go
diff --git a/pkg/sentry/socket/netstack/provider_vfs2.go b/pkg/sentry/socket/netstack/provider_vfs2.go
index 2a01143f6..2a01143f6 100755..100644
--- a/pkg/sentry/socket/netstack/provider_vfs2.go
+++ b/pkg/sentry/socket/netstack/provider_vfs2.go
diff --git a/pkg/sentry/socket/netstack/save_restore.go b/pkg/sentry/socket/netstack/save_restore.go
index c7aaf722a..c7aaf722a 100755..100644
--- a/pkg/sentry/socket/netstack/save_restore.go
+++ b/pkg/sentry/socket/netstack/save_restore.go
diff --git a/pkg/sentry/socket/netstack/stack.go b/pkg/sentry/socket/netstack/stack.go
index f5fa18136..f5fa18136 100755..100644
--- a/pkg/sentry/socket/netstack/stack.go
+++ b/pkg/sentry/socket/netstack/stack.go
diff --git a/pkg/sentry/socket/socket_state_autogen.go b/pkg/sentry/socket/socket_state_autogen.go
index 900c217c7..900c217c7 100755..100644
--- a/pkg/sentry/socket/socket_state_autogen.go
+++ b/pkg/sentry/socket/socket_state_autogen.go
diff --git a/pkg/sentry/socket/unix/transport/transport_message_list.go b/pkg/sentry/socket/unix/transport/transport_message_list.go
index 568cd5871..568cd5871 100755..100644
--- a/pkg/sentry/socket/unix/transport/transport_message_list.go
+++ b/pkg/sentry/socket/unix/transport/transport_message_list.go
diff --git a/pkg/sentry/socket/unix/transport/transport_state_autogen.go b/pkg/sentry/socket/unix/transport/transport_state_autogen.go
index b47951498..b47951498 100755..100644
--- a/pkg/sentry/socket/unix/transport/transport_state_autogen.go
+++ b/pkg/sentry/socket/unix/transport/transport_state_autogen.go
diff --git a/pkg/sentry/socket/unix/unix_state_autogen.go b/pkg/sentry/socket/unix/unix_state_autogen.go
index aa05e7b99..aa05e7b99 100755..100644
--- a/pkg/sentry/socket/unix/unix_state_autogen.go
+++ b/pkg/sentry/socket/unix/unix_state_autogen.go
diff --git a/pkg/sentry/socket/unix/unix_vfs2.go b/pkg/sentry/socket/unix/unix_vfs2.go
index 45e109361..45e109361 100755..100644
--- a/pkg/sentry/socket/unix/unix_vfs2.go
+++ b/pkg/sentry/socket/unix/unix_vfs2.go
diff --git a/pkg/sentry/state/state_state_autogen.go b/pkg/sentry/state/state_state_autogen.go
index 6c2b29632..6c2b29632 100755..100644
--- a/pkg/sentry/state/state_state_autogen.go
+++ b/pkg/sentry/state/state_state_autogen.go
diff --git a/pkg/sentry/state/state_unsafe_state_autogen.go b/pkg/sentry/state/state_unsafe_state_autogen.go
index 6c2b29632..6c2b29632 100755..100644
--- a/pkg/sentry/state/state_unsafe_state_autogen.go
+++ b/pkg/sentry/state/state_unsafe_state_autogen.go
diff --git a/pkg/sentry/strace/epoll.go b/pkg/sentry/strace/epoll.go
index a6e48b836..a6e48b836 100755..100644
--- a/pkg/sentry/strace/epoll.go
+++ b/pkg/sentry/strace/epoll.go
diff --git a/pkg/sentry/strace/linux64_amd64.go b/pkg/sentry/strace/linux64_amd64.go
index 71b92eaee..71b92eaee 100755..100644
--- a/pkg/sentry/strace/linux64_amd64.go
+++ b/pkg/sentry/strace/linux64_amd64.go
diff --git a/pkg/sentry/strace/linux64_arm64.go b/pkg/sentry/strace/linux64_arm64.go
index bd7361a52..bd7361a52 100755..100644
--- a/pkg/sentry/strace/linux64_arm64.go
+++ b/pkg/sentry/strace/linux64_arm64.go
diff --git a/pkg/sentry/strace/select.go b/pkg/sentry/strace/select.go
index 3a4c32aa0..3a4c32aa0 100755..100644
--- a/pkg/sentry/strace/select.go
+++ b/pkg/sentry/strace/select.go
diff --git a/pkg/sentry/strace/strace_amd64_state_autogen.go b/pkg/sentry/strace/strace_amd64_state_autogen.go
index c7d4b3eb4..c7d4b3eb4 100755..100644
--- a/pkg/sentry/strace/strace_amd64_state_autogen.go
+++ b/pkg/sentry/strace/strace_amd64_state_autogen.go
diff --git a/pkg/sentry/strace/strace_arm64_state_autogen.go b/pkg/sentry/strace/strace_arm64_state_autogen.go
index 9b8f66dc9..9b8f66dc9 100755..100644
--- a/pkg/sentry/strace/strace_arm64_state_autogen.go
+++ b/pkg/sentry/strace/strace_arm64_state_autogen.go
diff --git a/pkg/sentry/strace/strace_go_proto/strace.pb.go b/pkg/sentry/strace/strace_go_proto/strace.pb.go
index ef45661bc..ef45661bc 100755..100644
--- a/pkg/sentry/strace/strace_go_proto/strace.pb.go
+++ b/pkg/sentry/strace/strace_go_proto/strace.pb.go
diff --git a/pkg/sentry/strace/strace_state_autogen.go b/pkg/sentry/strace/strace_state_autogen.go
index 33f6a7a54..33f6a7a54 100755..100644
--- a/pkg/sentry/strace/strace_state_autogen.go
+++ b/pkg/sentry/strace/strace_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go b/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
index b3e3be0b6..b3e3be0b6 100755..100644
--- a/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/linux_amd64_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go b/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
index f03e36ddc..f03e36ddc 100755..100644
--- a/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/linux_arm64_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/linux_state_autogen.go b/pkg/sentry/syscalls/linux/linux_state_autogen.go
index cbae0a871..cbae0a871 100755..100644
--- a/pkg/sentry/syscalls/linux/linux_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/linux_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/sys_clone_amd64.go b/pkg/sentry/syscalls/linux/sys_clone_amd64.go
index dd43cf18d..dd43cf18d 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_clone_amd64.go
+++ b/pkg/sentry/syscalls/linux/sys_clone_amd64.go
diff --git a/pkg/sentry/syscalls/linux/sys_clone_arm64.go b/pkg/sentry/syscalls/linux/sys_clone_arm64.go
index cf68a8949..cf68a8949 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_clone_arm64.go
+++ b/pkg/sentry/syscalls/linux/sys_clone_arm64.go
diff --git a/pkg/sentry/syscalls/linux/sys_rseq.go b/pkg/sentry/syscalls/linux/sys_rseq.go
index 90db10ea6..90db10ea6 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_rseq.go
+++ b/pkg/sentry/syscalls/linux/sys_rseq.go
diff --git a/pkg/sentry/syscalls/linux/sys_stat_amd64.go b/pkg/sentry/syscalls/linux/sys_stat_amd64.go
index 0a04a6113..0a04a6113 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_stat_amd64.go
+++ b/pkg/sentry/syscalls/linux/sys_stat_amd64.go
diff --git a/pkg/sentry/syscalls/linux/sys_stat_arm64.go b/pkg/sentry/syscalls/linux/sys_stat_arm64.go
index 5a3b1bfad..5a3b1bfad 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_stat_arm64.go
+++ b/pkg/sentry/syscalls/linux/sys_stat_arm64.go
diff --git a/pkg/sentry/syscalls/linux/sys_tls_amd64.go b/pkg/sentry/syscalls/linux/sys_tls_amd64.go
index b3eb96a1c..b3eb96a1c 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_tls_amd64.go
+++ b/pkg/sentry/syscalls/linux/sys_tls_amd64.go
diff --git a/pkg/sentry/syscalls/linux/sys_tls_arm64.go b/pkg/sentry/syscalls/linux/sys_tls_arm64.go
index fb08a356e..fb08a356e 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_tls_arm64.go
+++ b/pkg/sentry/syscalls/linux/sys_tls_arm64.go
diff --git a/pkg/sentry/syscalls/linux/sys_xattr.go b/pkg/sentry/syscalls/linux/sys_xattr.go
index 2de5e3422..2de5e3422 100755..100644
--- a/pkg/sentry/syscalls/linux/sys_xattr.go
+++ b/pkg/sentry/syscalls/linux/sys_xattr.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/epoll.go b/pkg/sentry/syscalls/linux/vfs2/epoll.go
index 34c90ae3e..34c90ae3e 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/epoll.go
+++ b/pkg/sentry/syscalls/linux/vfs2/epoll.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/eventfd.go b/pkg/sentry/syscalls/linux/vfs2/eventfd.go
index aff1a2070..aff1a2070 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/eventfd.go
+++ b/pkg/sentry/syscalls/linux/vfs2/eventfd.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/execve.go b/pkg/sentry/syscalls/linux/vfs2/execve.go
index aef0078a8..aef0078a8 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/execve.go
+++ b/pkg/sentry/syscalls/linux/vfs2/execve.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/fd.go b/pkg/sentry/syscalls/linux/vfs2/fd.go
index ca0f7fd1e..ca0f7fd1e 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/fd.go
+++ b/pkg/sentry/syscalls/linux/vfs2/fd.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/filesystem.go b/pkg/sentry/syscalls/linux/vfs2/filesystem.go
index 46d3e189c..46d3e189c 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/filesystem.go
+++ b/pkg/sentry/syscalls/linux/vfs2/filesystem.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/fscontext.go b/pkg/sentry/syscalls/linux/vfs2/fscontext.go
index 317409a18..317409a18 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/fscontext.go
+++ b/pkg/sentry/syscalls/linux/vfs2/fscontext.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/getdents.go b/pkg/sentry/syscalls/linux/vfs2/getdents.go
index c7c7bf7ce..c7c7bf7ce 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/getdents.go
+++ b/pkg/sentry/syscalls/linux/vfs2/getdents.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/ioctl.go b/pkg/sentry/syscalls/linux/vfs2/ioctl.go
index 5a2418da9..5a2418da9 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/ioctl.go
+++ b/pkg/sentry/syscalls/linux/vfs2/ioctl.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/memfd.go b/pkg/sentry/syscalls/linux/vfs2/memfd.go
index bbe248d17..bbe248d17 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/memfd.go
+++ b/pkg/sentry/syscalls/linux/vfs2/memfd.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/mmap.go b/pkg/sentry/syscalls/linux/vfs2/mmap.go
index 60a43f0a0..60a43f0a0 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/mmap.go
+++ b/pkg/sentry/syscalls/linux/vfs2/mmap.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/path.go b/pkg/sentry/syscalls/linux/vfs2/path.go
index 97da6c647..97da6c647 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/path.go
+++ b/pkg/sentry/syscalls/linux/vfs2/path.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/pipe.go b/pkg/sentry/syscalls/linux/vfs2/pipe.go
index 4a01e4209..4a01e4209 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/pipe.go
+++ b/pkg/sentry/syscalls/linux/vfs2/pipe.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/poll.go b/pkg/sentry/syscalls/linux/vfs2/poll.go
index ff1b25d7b..ff1b25d7b 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/poll.go
+++ b/pkg/sentry/syscalls/linux/vfs2/poll.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/read_write.go b/pkg/sentry/syscalls/linux/vfs2/read_write.go
index 3a7ef24f5..3a7ef24f5 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/read_write.go
+++ b/pkg/sentry/syscalls/linux/vfs2/read_write.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/setstat.go b/pkg/sentry/syscalls/linux/vfs2/setstat.go
index 09ecfed26..09ecfed26 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/setstat.go
+++ b/pkg/sentry/syscalls/linux/vfs2/setstat.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/signal.go b/pkg/sentry/syscalls/linux/vfs2/signal.go
index 623992f6f..623992f6f 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/signal.go
+++ b/pkg/sentry/syscalls/linux/vfs2/signal.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/socket.go b/pkg/sentry/syscalls/linux/vfs2/socket.go
index 10b668477..10b668477 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/socket.go
+++ b/pkg/sentry/syscalls/linux/vfs2/socket.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/splice.go b/pkg/sentry/syscalls/linux/vfs2/splice.go
new file mode 100644
index 000000000..8f3c22a02
--- /dev/null
+++ b/pkg/sentry/syscalls/linux/vfs2/splice.go
@@ -0,0 +1,286 @@
+// Copyright 2020 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 vfs2
+
+import (
+ "gvisor.dev/gvisor/pkg/abi/linux"
+ "gvisor.dev/gvisor/pkg/sentry/arch"
+ "gvisor.dev/gvisor/pkg/sentry/kernel"
+ "gvisor.dev/gvisor/pkg/sentry/kernel/pipe"
+ "gvisor.dev/gvisor/pkg/sentry/vfs"
+ "gvisor.dev/gvisor/pkg/syserror"
+ "gvisor.dev/gvisor/pkg/waiter"
+)
+
+// Splice implements Linux syscall splice(2).
+func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+ inFD := args[0].Int()
+ inOffsetPtr := args[1].Pointer()
+ outFD := args[2].Int()
+ outOffsetPtr := args[3].Pointer()
+ count := int64(args[4].SizeT())
+ flags := args[5].Int()
+
+ if count == 0 {
+ return 0, nil, nil
+ }
+ if count > int64(kernel.MAX_RW_COUNT) {
+ count = int64(kernel.MAX_RW_COUNT)
+ }
+
+ // Check for invalid flags.
+ if flags&^(linux.SPLICE_F_MOVE|linux.SPLICE_F_NONBLOCK|linux.SPLICE_F_MORE|linux.SPLICE_F_GIFT) != 0 {
+ return 0, nil, syserror.EINVAL
+ }
+
+ // Get file descriptions.
+ inFile := t.GetFileVFS2(inFD)
+ if inFile == nil {
+ return 0, nil, syserror.EBADF
+ }
+ defer inFile.DecRef()
+ outFile := t.GetFileVFS2(outFD)
+ if outFile == nil {
+ return 0, nil, syserror.EBADF
+ }
+ defer outFile.DecRef()
+
+ // Check that both files support the required directionality.
+ if !inFile.IsReadable() || !outFile.IsWritable() {
+ return 0, nil, syserror.EBADF
+ }
+
+ // The operation is non-blocking if anything is non-blocking.
+ //
+ // N.B. This is a rather simplistic heuristic that avoids some
+ // poor edge case behavior since the exact semantics here are
+ // underspecified and vary between versions of Linux itself.
+ nonBlock := ((inFile.StatusFlags()|outFile.StatusFlags())&linux.O_NONBLOCK != 0) || (flags&linux.SPLICE_F_NONBLOCK != 0)
+
+ // At least one file description must represent a pipe.
+ inPipeFD, inIsPipe := inFile.Impl().(*pipe.VFSPipeFD)
+ outPipeFD, outIsPipe := outFile.Impl().(*pipe.VFSPipeFD)
+ if !inIsPipe && !outIsPipe {
+ return 0, nil, syserror.EINVAL
+ }
+
+ // Copy in offsets.
+ inOffset := int64(-1)
+ if inOffsetPtr != 0 {
+ if inIsPipe {
+ return 0, nil, syserror.ESPIPE
+ }
+ if inFile.Options().DenyPRead {
+ return 0, nil, syserror.EINVAL
+ }
+ if _, err := t.CopyIn(inOffsetPtr, &inOffset); err != nil {
+ return 0, nil, err
+ }
+ if inOffset < 0 {
+ return 0, nil, syserror.EINVAL
+ }
+ }
+ outOffset := int64(-1)
+ if outOffsetPtr != 0 {
+ if outIsPipe {
+ return 0, nil, syserror.ESPIPE
+ }
+ if outFile.Options().DenyPWrite {
+ return 0, nil, syserror.EINVAL
+ }
+ if _, err := t.CopyIn(outOffsetPtr, &outOffset); err != nil {
+ return 0, nil, err
+ }
+ if outOffset < 0 {
+ return 0, nil, syserror.EINVAL
+ }
+ }
+
+ // Move data.
+ var (
+ n int64
+ err error
+ inCh chan struct{}
+ outCh chan struct{}
+ )
+ for {
+ // If both input and output are pipes, delegate to the pipe
+ // implementation. Otherwise, exactly one end is a pipe, which we
+ // ensure is consistently ordered after the non-pipe FD's locks by
+ // passing the pipe FD as usermem.IO to the non-pipe end.
+ switch {
+ case inIsPipe && outIsPipe:
+ n, err = pipe.Splice(t, outPipeFD, inPipeFD, count)
+ case inIsPipe:
+ if outOffset != -1 {
+ n, err = outFile.PWrite(t, inPipeFD.IOSequence(count), outOffset, vfs.WriteOptions{})
+ outOffset += n
+ } else {
+ n, err = outFile.Write(t, inPipeFD.IOSequence(count), vfs.WriteOptions{})
+ }
+ case outIsPipe:
+ if inOffset != -1 {
+ n, err = inFile.PRead(t, outPipeFD.IOSequence(count), inOffset, vfs.ReadOptions{})
+ inOffset += n
+ } else {
+ n, err = inFile.Read(t, outPipeFD.IOSequence(count), vfs.ReadOptions{})
+ }
+ }
+ if n != 0 || err != syserror.ErrWouldBlock || nonBlock {
+ break
+ }
+
+ // Note that the blocking behavior here is a bit different than the
+ // normal pattern. Because we need to have both data to read and data
+ // to write simultaneously, we actually explicitly block on both of
+ // these cases in turn before returning to the splice operation.
+ if inFile.Readiness(eventMaskRead)&eventMaskRead == 0 {
+ if inCh == nil {
+ inCh = make(chan struct{}, 1)
+ inW, _ := waiter.NewChannelEntry(inCh)
+ inFile.EventRegister(&inW, eventMaskRead)
+ defer inFile.EventUnregister(&inW)
+ continue // Need to refresh readiness.
+ }
+ if err = t.Block(inCh); err != nil {
+ break
+ }
+ }
+ if outFile.Readiness(eventMaskWrite)&eventMaskWrite == 0 {
+ if outCh == nil {
+ outCh = make(chan struct{}, 1)
+ outW, _ := waiter.NewChannelEntry(outCh)
+ outFile.EventRegister(&outW, eventMaskWrite)
+ defer outFile.EventUnregister(&outW)
+ continue // Need to refresh readiness.
+ }
+ if err = t.Block(outCh); err != nil {
+ break
+ }
+ }
+ }
+
+ // Copy updated offsets out.
+ if inOffsetPtr != 0 {
+ if _, err := t.CopyOut(inOffsetPtr, &inOffset); err != nil {
+ return 0, nil, err
+ }
+ }
+ if outOffsetPtr != 0 {
+ if _, err := t.CopyOut(outOffsetPtr, &outOffset); err != nil {
+ return 0, nil, err
+ }
+ }
+
+ if n == 0 {
+ return 0, nil, err
+ }
+ return uintptr(n), nil, nil
+}
+
+// Tee implements Linux syscall tee(2).
+func Tee(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
+ inFD := args[0].Int()
+ outFD := args[1].Int()
+ count := int64(args[2].SizeT())
+ flags := args[3].Int()
+
+ if count == 0 {
+ return 0, nil, nil
+ }
+ if count > int64(kernel.MAX_RW_COUNT) {
+ count = int64(kernel.MAX_RW_COUNT)
+ }
+
+ // Check for invalid flags.
+ if flags&^(linux.SPLICE_F_MOVE|linux.SPLICE_F_NONBLOCK|linux.SPLICE_F_MORE|linux.SPLICE_F_GIFT) != 0 {
+ return 0, nil, syserror.EINVAL
+ }
+
+ // Get file descriptions.
+ inFile := t.GetFileVFS2(inFD)
+ if inFile == nil {
+ return 0, nil, syserror.EBADF
+ }
+ defer inFile.DecRef()
+ outFile := t.GetFileVFS2(outFD)
+ if outFile == nil {
+ return 0, nil, syserror.EBADF
+ }
+ defer outFile.DecRef()
+
+ // Check that both files support the required directionality.
+ if !inFile.IsReadable() || !outFile.IsWritable() {
+ return 0, nil, syserror.EBADF
+ }
+
+ // The operation is non-blocking if anything is non-blocking.
+ //
+ // N.B. This is a rather simplistic heuristic that avoids some
+ // poor edge case behavior since the exact semantics here are
+ // underspecified and vary between versions of Linux itself.
+ nonBlock := ((inFile.StatusFlags()|outFile.StatusFlags())&linux.O_NONBLOCK != 0) || (flags&linux.SPLICE_F_NONBLOCK != 0)
+
+ // Both file descriptions must represent pipes.
+ inPipeFD, inIsPipe := inFile.Impl().(*pipe.VFSPipeFD)
+ outPipeFD, outIsPipe := outFile.Impl().(*pipe.VFSPipeFD)
+ if !inIsPipe || !outIsPipe {
+ return 0, nil, syserror.EINVAL
+ }
+
+ // Copy data.
+ var (
+ inCh chan struct{}
+ outCh chan struct{}
+ )
+ for {
+ n, err := pipe.Tee(t, outPipeFD, inPipeFD, count)
+ if n != 0 {
+ return uintptr(n), nil, nil
+ }
+ if err != syserror.ErrWouldBlock || nonBlock {
+ return 0, nil, err
+ }
+
+ // Note that the blocking behavior here is a bit different than the
+ // normal pattern. Because we need to have both data to read and data
+ // to write simultaneously, we actually explicitly block on both of
+ // these cases in turn before returning to the tee operation.
+ if inFile.Readiness(eventMaskRead)&eventMaskRead == 0 {
+ if inCh == nil {
+ inCh = make(chan struct{}, 1)
+ inW, _ := waiter.NewChannelEntry(inCh)
+ inFile.EventRegister(&inW, eventMaskRead)
+ defer inFile.EventUnregister(&inW)
+ continue // Need to refresh readiness.
+ }
+ if err := t.Block(inCh); err != nil {
+ return 0, nil, err
+ }
+ }
+ if outFile.Readiness(eventMaskWrite)&eventMaskWrite == 0 {
+ if outCh == nil {
+ outCh = make(chan struct{}, 1)
+ outW, _ := waiter.NewChannelEntry(outCh)
+ outFile.EventRegister(&outW, eventMaskWrite)
+ defer outFile.EventUnregister(&outW)
+ continue // Need to refresh readiness.
+ }
+ if err := t.Block(outCh); err != nil {
+ return 0, nil, err
+ }
+ }
+ }
+}
diff --git a/pkg/sentry/syscalls/linux/vfs2/stat.go b/pkg/sentry/syscalls/linux/vfs2/stat.go
index bb1d5cac4..bb1d5cac4 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/stat.go
+++ b/pkg/sentry/syscalls/linux/vfs2/stat.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/stat_amd64.go b/pkg/sentry/syscalls/linux/vfs2/stat_amd64.go
index 2da538fc6..2da538fc6 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/stat_amd64.go
+++ b/pkg/sentry/syscalls/linux/vfs2/stat_amd64.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/stat_arm64.go b/pkg/sentry/syscalls/linux/vfs2/stat_arm64.go
index 88b9c7627..88b9c7627 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/stat_arm64.go
+++ b/pkg/sentry/syscalls/linux/vfs2/stat_arm64.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/sync.go b/pkg/sentry/syscalls/linux/vfs2/sync.go
index 365250b0b..365250b0b 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/sync.go
+++ b/pkg/sentry/syscalls/linux/vfs2/sync.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/timerfd.go b/pkg/sentry/syscalls/linux/vfs2/timerfd.go
index 5ac79bc09..5ac79bc09 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/timerfd.go
+++ b/pkg/sentry/syscalls/linux/vfs2/timerfd.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2.go b/pkg/sentry/syscalls/linux/vfs2/vfs2.go
index a332d01bd..083fdcf82 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2.go
@@ -134,8 +134,8 @@ func Override() {
s.Table[269] = syscalls.Supported("faccessat", Faccessat)
s.Table[270] = syscalls.Supported("pselect", Pselect)
s.Table[271] = syscalls.Supported("ppoll", Ppoll)
- delete(s.Table, 275) // splice
- delete(s.Table, 276) // tee
+ s.Table[275] = syscalls.Supported("splice", Splice)
+ s.Table[276] = syscalls.Supported("tee", Tee)
s.Table[277] = syscalls.Supported("sync_file_range", SyncFileRange)
s.Table[280] = syscalls.Supported("utimensat", Utimensat)
s.Table[281] = syscalls.Supported("epoll_pwait", EpollPwait)
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_abi_autogen_unsafe.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_abi_autogen_unsafe.go
index 372fbcd8e..372fbcd8e 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_abi_autogen_unsafe.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_abi_autogen_unsafe.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_abi_autogen_unsafe.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_abi_autogen_unsafe.go
index 204c7ceaf..204c7ceaf 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_abi_autogen_unsafe.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_abi_autogen_unsafe.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_state_autogen.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_state_autogen.go
index 7f5556f9c..7f5556f9c 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_amd64_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_abi_autogen_unsafe.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_abi_autogen_unsafe.go
index 08e10d735..08e10d735 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_abi_autogen_unsafe.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_abi_autogen_unsafe.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_state_autogen.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_state_autogen.go
index 3e3862045..3e3862045 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_arm64_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/vfs2_state_autogen.go b/pkg/sentry/syscalls/linux/vfs2/vfs2_state_autogen.go
index 570100331..570100331 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/vfs2_state_autogen.go
+++ b/pkg/sentry/syscalls/linux/vfs2/vfs2_state_autogen.go
diff --git a/pkg/sentry/syscalls/linux/vfs2/xattr.go b/pkg/sentry/syscalls/linux/vfs2/xattr.go
index af455d5c1..af455d5c1 100755..100644
--- a/pkg/sentry/syscalls/linux/vfs2/xattr.go
+++ b/pkg/sentry/syscalls/linux/vfs2/xattr.go
diff --git a/pkg/sentry/syscalls/syscalls_state_autogen.go b/pkg/sentry/syscalls/syscalls_state_autogen.go
index b577e39a3..b577e39a3 100755..100644
--- a/pkg/sentry/syscalls/syscalls_state_autogen.go
+++ b/pkg/sentry/syscalls/syscalls_state_autogen.go
diff --git a/pkg/sentry/time/seqatomic_parameters_unsafe.go b/pkg/sentry/time/seqatomic_parameters_unsafe.go
index e2c85d862..efd3ccae2 100755..100644
--- a/pkg/sentry/time/seqatomic_parameters_unsafe.go
+++ b/pkg/sentry/time/seqatomic_parameters_unsafe.go
@@ -1,11 +1,11 @@
package time
import (
+ "fmt"
"reflect"
"strings"
"unsafe"
- "fmt"
"gvisor.dev/gvisor/pkg/sync"
)
diff --git a/pkg/sentry/time/time_arm64_state_autogen.go b/pkg/sentry/time/time_arm64_state_autogen.go
index 2adc9c9e0..2adc9c9e0 100755..100644
--- a/pkg/sentry/time/time_arm64_state_autogen.go
+++ b/pkg/sentry/time/time_arm64_state_autogen.go
diff --git a/pkg/sentry/time/time_state_autogen.go b/pkg/sentry/time/time_state_autogen.go
index 2adc9c9e0..2adc9c9e0 100755..100644
--- a/pkg/sentry/time/time_state_autogen.go
+++ b/pkg/sentry/time/time_state_autogen.go
diff --git a/pkg/sentry/time/time_unsafe_state_autogen.go b/pkg/sentry/time/time_unsafe_state_autogen.go
index 2adc9c9e0..2adc9c9e0 100755..100644
--- a/pkg/sentry/time/time_unsafe_state_autogen.go
+++ b/pkg/sentry/time/time_unsafe_state_autogen.go
diff --git a/pkg/sentry/unimpl/unimpl_state_autogen.go b/pkg/sentry/unimpl/unimpl_state_autogen.go
index b37d16f87..b37d16f87 100755..100644
--- a/pkg/sentry/unimpl/unimpl_state_autogen.go
+++ b/pkg/sentry/unimpl/unimpl_state_autogen.go
diff --git a/pkg/sentry/unimpl/unimplemented_syscall_go_proto/unimplemented_syscall.pb.go b/pkg/sentry/unimpl/unimplemented_syscall_go_proto/unimplemented_syscall.pb.go
index 4dfb169cc..4dfb169cc 100755..100644
--- a/pkg/sentry/unimpl/unimplemented_syscall_go_proto/unimplemented_syscall.pb.go
+++ b/pkg/sentry/unimpl/unimplemented_syscall_go_proto/unimplemented_syscall.pb.go
diff --git a/pkg/sentry/uniqueid/uniqueid_state_autogen.go b/pkg/sentry/uniqueid/uniqueid_state_autogen.go
index 1890fdf46..1890fdf46 100755..100644
--- a/pkg/sentry/uniqueid/uniqueid_state_autogen.go
+++ b/pkg/sentry/uniqueid/uniqueid_state_autogen.go
diff --git a/pkg/sentry/usage/usage_state_autogen.go b/pkg/sentry/usage/usage_state_autogen.go
index 42979ea25..42979ea25 100755..100644
--- a/pkg/sentry/usage/usage_state_autogen.go
+++ b/pkg/sentry/usage/usage_state_autogen.go
diff --git a/pkg/sentry/usage/usage_unsafe_state_autogen.go b/pkg/sentry/usage/usage_unsafe_state_autogen.go
index 5d9e86efa..5d9e86efa 100755..100644
--- a/pkg/sentry/usage/usage_unsafe_state_autogen.go
+++ b/pkg/sentry/usage/usage_unsafe_state_autogen.go
diff --git a/pkg/sentry/vfs/anonfs.go b/pkg/sentry/vfs/anonfs.go
index caf770fd5..caf770fd5 100755..100644
--- a/pkg/sentry/vfs/anonfs.go
+++ b/pkg/sentry/vfs/anonfs.go
diff --git a/pkg/sentry/vfs/context.go b/pkg/sentry/vfs/context.go
index c9e724fef..c9e724fef 100755..100644
--- a/pkg/sentry/vfs/context.go
+++ b/pkg/sentry/vfs/context.go
diff --git a/pkg/sentry/vfs/debug.go b/pkg/sentry/vfs/debug.go
index 0ed20f249..0ed20f249 100755..100644
--- a/pkg/sentry/vfs/debug.go
+++ b/pkg/sentry/vfs/debug.go
diff --git a/pkg/sentry/vfs/dentry.go b/pkg/sentry/vfs/dentry.go
index 8624dbd5d..8624dbd5d 100755..100644
--- a/pkg/sentry/vfs/dentry.go
+++ b/pkg/sentry/vfs/dentry.go
diff --git a/pkg/sentry/vfs/device.go b/pkg/sentry/vfs/device.go
index 1e9dffc8f..1e9dffc8f 100755..100644
--- a/pkg/sentry/vfs/device.go
+++ b/pkg/sentry/vfs/device.go
diff --git a/pkg/sentry/vfs/epoll.go b/pkg/sentry/vfs/epoll.go
index 8297f964b..8297f964b 100755..100644
--- a/pkg/sentry/vfs/epoll.go
+++ b/pkg/sentry/vfs/epoll.go
diff --git a/pkg/sentry/vfs/epoll_interest_list.go b/pkg/sentry/vfs/epoll_interest_list.go
index 67104a9c6..67104a9c6 100755..100644
--- a/pkg/sentry/vfs/epoll_interest_list.go
+++ b/pkg/sentry/vfs/epoll_interest_list.go
diff --git a/pkg/sentry/vfs/file_description.go b/pkg/sentry/vfs/file_description.go
index cfabd936c..bb294563d 100755..100644
--- a/pkg/sentry/vfs/file_description.go
+++ b/pkg/sentry/vfs/file_description.go
@@ -210,6 +210,11 @@ func (fd *FileDescription) VirtualDentry() VirtualDentry {
return fd.vd
}
+// Options returns the options passed to fd.Init().
+func (fd *FileDescription) Options() FileDescriptionOptions {
+ return fd.opts
+}
+
// StatusFlags returns file description status flags, as for fcntl(F_GETFL).
func (fd *FileDescription) StatusFlags() uint32 {
return atomic.LoadUint32(&fd.statusFlags)
diff --git a/pkg/sentry/vfs/file_description_impl_util.go b/pkg/sentry/vfs/file_description_impl_util.go
index f4c111926..f4c111926 100755..100644
--- a/pkg/sentry/vfs/file_description_impl_util.go
+++ b/pkg/sentry/vfs/file_description_impl_util.go
diff --git a/pkg/sentry/vfs/filesystem.go b/pkg/sentry/vfs/filesystem.go
index 1edd584c9..1edd584c9 100755..100644
--- a/pkg/sentry/vfs/filesystem.go
+++ b/pkg/sentry/vfs/filesystem.go
diff --git a/pkg/sentry/vfs/filesystem_impl_util.go b/pkg/sentry/vfs/filesystem_impl_util.go
index 465e610e0..465e610e0 100755..100644
--- a/pkg/sentry/vfs/filesystem_impl_util.go
+++ b/pkg/sentry/vfs/filesystem_impl_util.go
diff --git a/pkg/sentry/vfs/filesystem_type.go b/pkg/sentry/vfs/filesystem_type.go
index f2298f7f6..f2298f7f6 100755..100644
--- a/pkg/sentry/vfs/filesystem_type.go
+++ b/pkg/sentry/vfs/filesystem_type.go
diff --git a/pkg/sentry/vfs/lock/lock.go b/pkg/sentry/vfs/lock/lock.go
index 724dfe743..724dfe743 100755..100644
--- a/pkg/sentry/vfs/lock/lock.go
+++ b/pkg/sentry/vfs/lock/lock.go
diff --git a/pkg/sentry/vfs/lock/lock_state_autogen.go b/pkg/sentry/vfs/lock/lock_state_autogen.go
index 682254baf..682254baf 100755..100644
--- a/pkg/sentry/vfs/lock/lock_state_autogen.go
+++ b/pkg/sentry/vfs/lock/lock_state_autogen.go
diff --git a/pkg/sentry/vfs/memxattr/memxattr_state_autogen.go b/pkg/sentry/vfs/memxattr/memxattr_state_autogen.go
index 6b366cea4..6b366cea4 100755..100644
--- a/pkg/sentry/vfs/memxattr/memxattr_state_autogen.go
+++ b/pkg/sentry/vfs/memxattr/memxattr_state_autogen.go
diff --git a/pkg/sentry/vfs/memxattr/xattr.go b/pkg/sentry/vfs/memxattr/xattr.go
index cc1e7d764..cc1e7d764 100755..100644
--- a/pkg/sentry/vfs/memxattr/xattr.go
+++ b/pkg/sentry/vfs/memxattr/xattr.go
diff --git a/pkg/sentry/vfs/mount.go b/pkg/sentry/vfs/mount.go
index 02850b65c..02850b65c 100755..100644
--- a/pkg/sentry/vfs/mount.go
+++ b/pkg/sentry/vfs/mount.go
diff --git a/pkg/sentry/vfs/mount_unsafe.go b/pkg/sentry/vfs/mount_unsafe.go
index bc7581698..bc7581698 100755..100644
--- a/pkg/sentry/vfs/mount_unsafe.go
+++ b/pkg/sentry/vfs/mount_unsafe.go
diff --git a/pkg/sentry/vfs/options.go b/pkg/sentry/vfs/options.go
index 53d364c5c..53d364c5c 100755..100644
--- a/pkg/sentry/vfs/options.go
+++ b/pkg/sentry/vfs/options.go
diff --git a/pkg/sentry/vfs/pathname.go b/pkg/sentry/vfs/pathname.go
index cd78d66bc..cd78d66bc 100755..100644
--- a/pkg/sentry/vfs/pathname.go
+++ b/pkg/sentry/vfs/pathname.go
diff --git a/pkg/sentry/vfs/permissions.go b/pkg/sentry/vfs/permissions.go
index f9647f90e..f9647f90e 100755..100644
--- a/pkg/sentry/vfs/permissions.go
+++ b/pkg/sentry/vfs/permissions.go
diff --git a/pkg/sentry/vfs/resolving_path.go b/pkg/sentry/vfs/resolving_path.go
index 9d047ff88..9d047ff88 100755..100644
--- a/pkg/sentry/vfs/resolving_path.go
+++ b/pkg/sentry/vfs/resolving_path.go
diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go
index 8d7f8f8af..8d7f8f8af 100755..100644
--- a/pkg/sentry/vfs/vfs.go
+++ b/pkg/sentry/vfs/vfs.go
diff --git a/pkg/sentry/vfs/vfs_state_autogen.go b/pkg/sentry/vfs/vfs_state_autogen.go
index 0cf6ed48d..0cf6ed48d 100755..100644
--- a/pkg/sentry/vfs/vfs_state_autogen.go
+++ b/pkg/sentry/vfs/vfs_state_autogen.go
diff --git a/pkg/sentry/vfs/vfs_unsafe_state_autogen.go b/pkg/sentry/vfs/vfs_unsafe_state_autogen.go
index 8b198c5dd..8b198c5dd 100755..100644
--- a/pkg/sentry/vfs/vfs_unsafe_state_autogen.go
+++ b/pkg/sentry/vfs/vfs_unsafe_state_autogen.go
diff --git a/pkg/sentry/watchdog/watchdog_state_autogen.go b/pkg/sentry/watchdog/watchdog_state_autogen.go
index bce0200e7..bce0200e7 100755..100644
--- a/pkg/sentry/watchdog/watchdog_state_autogen.go
+++ b/pkg/sentry/watchdog/watchdog_state_autogen.go
diff --git a/pkg/sleep/commit_arm64.s b/pkg/sleep/commit_arm64.s
index d0ef15b20..d0ef15b20 100755..100644
--- a/pkg/sleep/commit_arm64.s
+++ b/pkg/sleep/commit_arm64.s
diff --git a/pkg/sleep/sleep_state_autogen.go b/pkg/sleep/sleep_state_autogen.go
index 39986b478..39986b478 100755..100644
--- a/pkg/sleep/sleep_state_autogen.go
+++ b/pkg/sleep/sleep_state_autogen.go
diff --git a/pkg/sleep/sleep_unsafe_state_autogen.go b/pkg/sleep/sleep_unsafe_state_autogen.go
index 023c828d7..023c828d7 100755..100644
--- a/pkg/sleep/sleep_unsafe_state_autogen.go
+++ b/pkg/sleep/sleep_unsafe_state_autogen.go
diff --git a/pkg/state/addr_range.go b/pkg/state/addr_range.go
index 45720c643..45720c643 100755..100644
--- a/pkg/state/addr_range.go
+++ b/pkg/state/addr_range.go
diff --git a/pkg/state/addr_set.go b/pkg/state/addr_set.go
index 5261aa488..f8eaf0cd1 100755..100644
--- a/pkg/state/addr_set.go
+++ b/pkg/state/addr_set.go
@@ -9,6 +9,34 @@ import (
"fmt"
)
+// trackGaps is an optional parameter.
+//
+// If trackGaps is 1, the Set will track maximum gap size recursively,
+// enabling the GapIterator.{Prev,Next}LargeEnoughGap functions. In this
+// case, Key must be an unsigned integer.
+//
+// trackGaps must be 0 or 1.
+const addrtrackGaps = 0
+
+var _ = uint8(addrtrackGaps << 7) // Will fail if not zero or one.
+
+// dynamicGap is a type that disappears if trackGaps is 0.
+type addrdynamicGap [addrtrackGaps]uintptr
+
+// Get returns the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *addrdynamicGap) Get() uintptr {
+ return d[:][0]
+}
+
+// Set sets the value of the gap.
+//
+// Precondition: trackGaps must be non-zero.
+func (d *addrdynamicGap) Set(v uintptr) {
+ d[:][0] = v
+}
+
const (
// minDegree is the minimum degree of an internal node in a Set B-tree.
//
@@ -267,8 +295,12 @@ func (s *addrSet) Insert(gap addrGapIterator, r addrRange, val __generics_import
}
if prev.Ok() && prev.End() == r.Start {
if mval, ok := (addrSetFunctions{}).Merge(prev.Range(), prev.Value(), r, val); ok {
+ shrinkMaxGap := addrtrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
prev.SetEndUnchecked(r.End)
prev.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
if next.Ok() && next.Start() == r.End {
val = mval
if mval, ok := (addrSetFunctions{}).Merge(prev.Range(), val, next.Range(), next.Value()); ok {
@@ -282,11 +314,16 @@ func (s *addrSet) Insert(gap addrGapIterator, r addrRange, val __generics_import
}
if next.Ok() && next.Start() == r.End {
if mval, ok := (addrSetFunctions{}).Merge(r, val, next.Range(), next.Value()); ok {
+ shrinkMaxGap := addrtrackGaps != 0 && gap.Range().Length() == gap.node.maxGap.Get()
next.SetStartUnchecked(r.Start)
next.SetValue(mval)
+ if shrinkMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return next
}
}
+
return s.InsertWithoutMergingUnchecked(gap, r, val)
}
@@ -313,11 +350,15 @@ func (s *addrSet) InsertWithoutMerging(gap addrGapIterator, r addrRange, val __g
// Preconditions: r.Start >= gap.Start(); r.End <= gap.End().
func (s *addrSet) InsertWithoutMergingUnchecked(gap addrGapIterator, r addrRange, val __generics_imported0.Value) addrIterator {
gap = gap.node.rebalanceBeforeInsert(gap)
+ splitMaxGap := addrtrackGaps != 0 && (gap.node.nrSegments == 0 || gap.Range().Length() == gap.node.maxGap.Get())
copy(gap.node.keys[gap.index+1:], gap.node.keys[gap.index:gap.node.nrSegments])
copy(gap.node.values[gap.index+1:], gap.node.values[gap.index:gap.node.nrSegments])
gap.node.keys[gap.index] = r
gap.node.values[gap.index] = val
gap.node.nrSegments++
+ if splitMaxGap {
+ gap.node.updateMaxGapLeaf()
+ }
return addrIterator{gap.node, gap.index}
}
@@ -332,12 +373,20 @@ func (s *addrSet) Remove(seg addrIterator) addrGapIterator {
seg.SetRangeUnchecked(victim.Range())
seg.SetValue(victim.Value())
+
+ nextAdjacentNode := seg.NextSegment().node
+ if addrtrackGaps != 0 {
+ nextAdjacentNode.updateMaxGapLeaf()
+ }
return s.Remove(victim).NextGap()
}
copy(seg.node.keys[seg.index:], seg.node.keys[seg.index+1:seg.node.nrSegments])
copy(seg.node.values[seg.index:], seg.node.values[seg.index+1:seg.node.nrSegments])
addrSetFunctions{}.ClearValue(&seg.node.values[seg.node.nrSegments-1])
seg.node.nrSegments--
+ if addrtrackGaps != 0 {
+ seg.node.updateMaxGapLeaf()
+ }
return seg.node.rebalanceAfterRemove(addrGapIterator{seg.node, seg.index})
}
@@ -387,6 +436,7 @@ func (s *addrSet) MergeUnchecked(first, second addrIterator) addrIterator {
first.SetEndUnchecked(second.End())
first.SetValue(mval)
+
return s.Remove(second).PrevSegment()
}
}
@@ -562,6 +612,12 @@ type addrnode struct {
// than "isLeaf" because false must be the correct value for an empty root.
hasChildren bool
+ // The longest gap within this node. If the node is a leaf, it's simply the
+ // maximum gap among all the (nrSegments+1) gaps formed by its nrSegments keys
+ // including the 0th and nrSegments-th gap possibly shared with its upper-level
+ // nodes; if it's a non-leaf node, it's the max of all children's maxGap.
+ maxGap addrdynamicGap
+
// Nodes store keys and values in separate arrays to maximize locality in
// the common case (scanning keys for lookup).
keys [addrmaxDegree - 1]addrRange
@@ -607,12 +663,12 @@ func (n *addrnode) nextSibling() *addrnode {
// required for insertion, and returns an updated iterator to the position
// represented by gap.
func (n *addrnode) rebalanceBeforeInsert(gap addrGapIterator) addrGapIterator {
- if n.parent != nil {
- gap = n.parent.rebalanceBeforeInsert(gap)
- }
if n.nrSegments < addrmaxDegree-1 {
return gap
}
+ if n.parent != nil {
+ gap = n.parent.rebalanceBeforeInsert(gap)
+ }
if n.parent == nil {
left := &addrnode{
@@ -648,6 +704,11 @@ func (n *addrnode) rebalanceBeforeInsert(gap addrGapIterator) addrGapIterator {
n.hasChildren = true
n.children[0] = left
n.children[1] = right
+
+ if addrtrackGaps != 0 {
+ left.updateMaxGapLocal()
+ right.updateMaxGapLocal()
+ }
if gap.node != n {
return gap
}
@@ -685,6 +746,11 @@ func (n *addrnode) rebalanceBeforeInsert(gap addrGapIterator) addrGapIterator {
}
n.nrSegments = addrminDegree - 1
+ if addrtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
+
if gap.node != n {
return gap
}
@@ -730,6 +796,11 @@ func (n *addrnode) rebalanceAfterRemove(gap addrGapIterator) addrGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if addrtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling && gap.index == sibling.nrSegments {
return addrGapIterator{n, 0}
}
@@ -758,6 +829,11 @@ func (n *addrnode) rebalanceAfterRemove(gap addrGapIterator) addrGapIterator {
}
n.nrSegments++
sibling.nrSegments--
+
+ if addrtrackGaps != 0 {
+ n.updateMaxGapLocal()
+ sibling.updateMaxGapLocal()
+ }
if gap.node == sibling {
if gap.index == 0 {
return addrGapIterator{n, n.nrSegments}
@@ -790,6 +866,7 @@ func (n *addrnode) rebalanceAfterRemove(gap addrGapIterator) addrGapIterator {
p.children[0] = nil
p.children[1] = nil
}
+
if gap.node == left {
return addrGapIterator{p, gap.index}
}
@@ -836,10 +913,146 @@ func (n *addrnode) rebalanceAfterRemove(gap addrGapIterator) addrGapIterator {
p.children[p.nrSegments] = nil
p.nrSegments--
+ if addrtrackGaps != 0 {
+ left.updateMaxGapLocal()
+ }
+
n = p
}
}
+// updateMaxGapLeaf updates maxGap bottom-up from the calling leaf until no
+// necessary update.
+//
+// Preconditions: n must be a leaf node, trackGaps must be 1.
+func (n *addrnode) updateMaxGapLeaf() {
+ if n.hasChildren {
+ panic(fmt.Sprintf("updateMaxGapLeaf should always be called on leaf node: %v", n))
+ }
+ max := n.calculateMaxGapLeaf()
+ if max == n.maxGap.Get() {
+
+ return
+ }
+ oldMax := n.maxGap.Get()
+ n.maxGap.Set(max)
+ if max > oldMax {
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() >= max {
+
+ break
+ }
+
+ p.maxGap.Set(max)
+ }
+ return
+ }
+
+ for p := n.parent; p != nil; p = p.parent {
+ if p.maxGap.Get() > oldMax {
+
+ break
+ }
+
+ parentNewMax := p.calculateMaxGapInternal()
+ if p.maxGap.Get() == parentNewMax {
+
+ break
+ }
+
+ p.maxGap.Set(parentNewMax)
+ }
+}
+
+// updateMaxGapLocal updates maxGap of the calling node solely with no
+// propagation to ancestor nodes.
+//
+// Precondition: trackGaps must be 1.
+func (n *addrnode) updateMaxGapLocal() {
+ if !n.hasChildren {
+
+ n.maxGap.Set(n.calculateMaxGapLeaf())
+ } else {
+
+ n.maxGap.Set(n.calculateMaxGapInternal())
+ }
+}
+
+// calculateMaxGapLeaf iterates the gaps within a leaf node and calculate the
+// max.
+//
+// Preconditions: n must be a leaf node.
+func (n *addrnode) calculateMaxGapLeaf() uintptr {
+ max := addrGapIterator{n, 0}.Range().Length()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := (addrGapIterator{n, i}).Range().Length(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// calculateMaxGapInternal iterates children's maxGap within an internal node n
+// and calculate the max.
+//
+// Preconditions: n must be a non-leaf node.
+func (n *addrnode) calculateMaxGapInternal() uintptr {
+ max := n.children[0].maxGap.Get()
+ for i := 1; i <= n.nrSegments; i++ {
+ if current := n.children[i].maxGap.Get(); current > max {
+ max = current
+ }
+ }
+ return max
+}
+
+// searchFirstLargeEnoughGap returns the first gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *addrnode) searchFirstLargeEnoughGap(minSize uintptr) addrGapIterator {
+ if n.maxGap.Get() < minSize {
+ return addrGapIterator{}
+ }
+ if n.hasChildren {
+ for i := 0; i <= n.nrSegments; i++ {
+ if largeEnoughGap := n.children[i].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := 0; i <= n.nrSegments; i++ {
+ currentGap := addrGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
+// searchLastLargeEnoughGap returns the last gap having at least minSize length
+// in the subtree rooted by n. If not found, return a terminal gap iterator.
+func (n *addrnode) searchLastLargeEnoughGap(minSize uintptr) addrGapIterator {
+ if n.maxGap.Get() < minSize {
+ return addrGapIterator{}
+ }
+ if n.hasChildren {
+ for i := n.nrSegments; i >= 0; i-- {
+ if largeEnoughGap := n.children[i].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ }
+ } else {
+ for i := n.nrSegments; i >= 0; i-- {
+ currentGap := addrGapIterator{n, i}
+ if currentGap.Range().Length() >= minSize {
+ return currentGap
+ }
+ }
+ }
+ panic(fmt.Sprintf("invalid maxGap in %v", n))
+}
+
// A Iterator is conceptually one of:
//
// - A pointer to a segment in a set; or
@@ -1145,6 +1358,114 @@ func (gap addrGapIterator) NextGap() addrGapIterator {
return seg.NextGap()
}
+// NextLargeEnoughGap returns the iterated gap's first next gap with larger
+// length than minSize. If not found, return a terminal gap iterator (does NOT
+// include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap addrGapIterator) NextLargeEnoughGap(minSize uintptr) addrGapIterator {
+ if addrtrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == gap.node.nrSegments {
+
+ gap.node = gap.NextSegment().node
+ gap.index = 0
+ return gap.nextLargeEnoughGapHelper(minSize)
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// nextLargeEnoughGapHelper is the helper function used by NextLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the trailing gap of a non-leaf node.
+func (gap addrGapIterator) nextLargeEnoughGapHelper(minSize uintptr) addrGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == gap.node.nrSegments)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return addrGapIterator{}
+ }
+
+ gap.index++
+ for gap.index <= gap.node.nrSegments {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchFirstLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index++
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == gap.node.nrSegments {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.nextLargeEnoughGapHelper(minSize)
+}
+
+// PrevLargeEnoughGap returns the iterated gap's first prev gap with larger or
+// equal length than minSize. If not found, return a terminal gap iterator
+// (does NOT include this gap itself).
+//
+// Precondition: trackGaps must be 1.
+func (gap addrGapIterator) PrevLargeEnoughGap(minSize uintptr) addrGapIterator {
+ if addrtrackGaps != 1 {
+ panic("set is not tracking gaps")
+ }
+ if gap.node != nil && gap.node.hasChildren && gap.index == 0 {
+
+ gap.node = gap.PrevSegment().node
+ gap.index = gap.node.nrSegments
+ return gap.prevLargeEnoughGapHelper(minSize)
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
+// prevLargeEnoughGapHelper is the helper function used by PrevLargeEnoughGap
+// to do the real recursions.
+//
+// Preconditions: gap is NOT the first gap of a non-leaf node.
+func (gap addrGapIterator) prevLargeEnoughGapHelper(minSize uintptr) addrGapIterator {
+
+ for gap.node != nil &&
+ (gap.node.maxGap.Get() < minSize || (!gap.node.hasChildren && gap.index == 0)) {
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+
+ if gap.node == nil {
+ return addrGapIterator{}
+ }
+
+ gap.index--
+ for gap.index >= 0 {
+ if gap.node.hasChildren {
+ if largeEnoughGap := gap.node.children[gap.index].searchLastLargeEnoughGap(minSize); largeEnoughGap.Ok() {
+ return largeEnoughGap
+ }
+ } else {
+ if gap.Range().Length() >= minSize {
+ return gap
+ }
+ }
+ gap.index--
+ }
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ if gap.node != nil && gap.index == 0 {
+
+ gap.node, gap.index = gap.node.parent, gap.node.parentIndex
+ }
+ return gap.prevLargeEnoughGapHelper(minSize)
+}
+
// segmentBeforePosition returns the predecessor segment of the position given
// by n.children[i], which may or may not contain a child. If no such segment
// exists, segmentBeforePosition returns a terminal iterator.
@@ -1211,7 +1532,15 @@ func (n *addrnode) writeDebugString(buf *bytes.Buffer, prefix string) {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
}
buf.WriteString(prefix)
- buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ if n.hasChildren {
+ if addrtrackGaps != 0 {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
+ } else {
+ buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
+ }
}
if child := n.children[n.nrSegments]; child != nil {
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, n.nrSegments))
@@ -1263,6 +1592,46 @@ func (s *addrSet) ImportSortedSlices(sds *addrSegmentDataSlices) error {
}
return nil
}
+
+// segmentTestCheck returns an error if s is incorrectly sorted, does not
+// contain exactly expectedSegments segments, or contains a segment which
+// fails the passed check.
+//
+// This should be used only for testing, and has been added to this package for
+// templating convenience.
+func (s *addrSet) segmentTestCheck(expectedSegments int, segFunc func(int, addrRange, __generics_imported0.Value) error) error {
+ havePrev := false
+ prev := uintptr(0)
+ nrSegments := 0
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ next := seg.Start()
+ if havePrev && prev >= next {
+ return fmt.Errorf("incorrect order: key %d (segment %d) >= key %d (segment %d)", prev, nrSegments-1, next, nrSegments)
+ }
+ if segFunc != nil {
+ if err := segFunc(nrSegments, seg.Range(), seg.Value()); err != nil {
+ return err
+ }
+ }
+ prev = next
+ havePrev = true
+ nrSegments++
+ }
+ if nrSegments != expectedSegments {
+ return fmt.Errorf("incorrect number of segments: got %d, wanted %d", nrSegments, expectedSegments)
+ }
+ return nil
+}
+
+// countSegments counts the number of segments in the set.
+//
+// Similar to Check, this should only be used for testing.
+func (s *addrSet) countSegments() (segments int) {
+ for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
+ segments++
+ }
+ return segments
+}
func (s *addrSet) saveRoot() *addrSegmentDataSlices {
return s.ExportSortedSlices()
}
diff --git a/pkg/state/object_go_proto/object.pb.go b/pkg/state/object_go_proto/object.pb.go
index dc5127149..dc5127149 100755..100644
--- a/pkg/state/object_go_proto/object.pb.go
+++ b/pkg/state/object_go_proto/object.pb.go
diff --git a/pkg/state/statefile/statefile_state_autogen.go b/pkg/state/statefile/statefile_state_autogen.go
index a2cdaa3f1..a2cdaa3f1 100755..100644
--- a/pkg/state/statefile/statefile_state_autogen.go
+++ b/pkg/state/statefile/statefile_state_autogen.go
diff --git a/pkg/sync/aliases.go b/pkg/sync/aliases.go
index 0d4316254..0d4316254 100755..100644
--- a/pkg/sync/aliases.go
+++ b/pkg/sync/aliases.go
diff --git a/pkg/sync/memmove_unsafe.go b/pkg/sync/memmove_unsafe.go
index ad4a3a37e..ad4a3a37e 100755..100644
--- a/pkg/sync/memmove_unsafe.go
+++ b/pkg/sync/memmove_unsafe.go
diff --git a/pkg/sync/mutex_unsafe.go b/pkg/sync/mutex_unsafe.go
index 3dd15578b..3dd15578b 100755..100644
--- a/pkg/sync/mutex_unsafe.go
+++ b/pkg/sync/mutex_unsafe.go
diff --git a/pkg/sync/norace_unsafe.go b/pkg/sync/norace_unsafe.go
index 006055dd6..006055dd6 100755..100644
--- a/pkg/sync/norace_unsafe.go
+++ b/pkg/sync/norace_unsafe.go
diff --git a/pkg/sync/race_unsafe.go b/pkg/sync/race_unsafe.go
index 31d8fa9a6..31d8fa9a6 100755..100644
--- a/pkg/sync/race_unsafe.go
+++ b/pkg/sync/race_unsafe.go
diff --git a/pkg/sync/rwmutex_unsafe.go b/pkg/sync/rwmutex_unsafe.go
index ea6cdc447..ea6cdc447 100755..100644
--- a/pkg/sync/rwmutex_unsafe.go
+++ b/pkg/sync/rwmutex_unsafe.go
diff --git a/pkg/sync/seqcount.go b/pkg/sync/seqcount.go
index a1e895352..a1e895352 100755..100644
--- a/pkg/sync/seqcount.go
+++ b/pkg/sync/seqcount.go
diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go
index b16cf5333..b16cf5333 100755..100644
--- a/pkg/sync/sync.go
+++ b/pkg/sync/sync.go
diff --git a/pkg/sync/sync_state_autogen.go b/pkg/sync/sync_state_autogen.go
deleted file mode 100755
index c6dc2c7e7..000000000
--- a/pkg/sync/sync_state_autogen.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// automatically generated by stateify.
-
-package sync
diff --git a/pkg/sync/sync_unsafe_state_autogen.go b/pkg/sync/sync_unsafe_state_autogen.go
deleted file mode 100755
index 6876ee883..000000000
--- a/pkg/sync/sync_unsafe_state_autogen.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// automatically generated by stateify.
-
-// +build go1.12
-// +build !go1.15
-// +build go1.13
-// +build !go1.15
-// +build !race
-// +build race
-// +build go1.13
-// +build !go1.15
-
-package sync
diff --git a/pkg/syserr/syserr_linux_state_autogen.go b/pkg/syserr/syserr_linux_state_autogen.go
index 7fd5a68b8..7fd5a68b8 100755..100644
--- a/pkg/syserr/syserr_linux_state_autogen.go
+++ b/pkg/syserr/syserr_linux_state_autogen.go
diff --git a/pkg/syserr/syserr_state_autogen.go b/pkg/syserr/syserr_state_autogen.go
index 712631a64..712631a64 100755..100644
--- a/pkg/syserr/syserr_state_autogen.go
+++ b/pkg/syserr/syserr_state_autogen.go
diff --git a/pkg/syserror/syserror_state_autogen.go b/pkg/syserror/syserror_state_autogen.go
index 456dcf093..456dcf093 100755..100644
--- a/pkg/syserror/syserror_state_autogen.go
+++ b/pkg/syserror/syserror_state_autogen.go
diff --git a/pkg/tcpip/adapters/gonet/gonet.go b/pkg/tcpip/adapters/gonet/gonet.go
index 6e0db2741..6e0db2741 100755..100644
--- a/pkg/tcpip/adapters/gonet/gonet.go
+++ b/pkg/tcpip/adapters/gonet/gonet.go
diff --git a/pkg/tcpip/adapters/gonet/gonet_state_autogen.go b/pkg/tcpip/adapters/gonet/gonet_state_autogen.go
index 7a5c5419e..7a5c5419e 100755..100644
--- a/pkg/tcpip/adapters/gonet/gonet_state_autogen.go
+++ b/pkg/tcpip/adapters/gonet/gonet_state_autogen.go
diff --git a/pkg/tcpip/buffer/buffer_state_autogen.go b/pkg/tcpip/buffer/buffer_state_autogen.go
index 954487771..954487771 100755..100644
--- a/pkg/tcpip/buffer/buffer_state_autogen.go
+++ b/pkg/tcpip/buffer/buffer_state_autogen.go
diff --git a/pkg/tcpip/hash/jenkins/jenkins_state_autogen.go b/pkg/tcpip/hash/jenkins/jenkins_state_autogen.go
index 216cc5a2e..216cc5a2e 100755..100644
--- a/pkg/tcpip/hash/jenkins/jenkins_state_autogen.go
+++ b/pkg/tcpip/hash/jenkins/jenkins_state_autogen.go
diff --git a/pkg/tcpip/header/header_state_autogen.go b/pkg/tcpip/header/header_state_autogen.go
index 015d7e12a..015d7e12a 100755..100644
--- a/pkg/tcpip/header/header_state_autogen.go
+++ b/pkg/tcpip/header/header_state_autogen.go
diff --git a/pkg/tcpip/header/ipv6_extension_headers.go b/pkg/tcpip/header/ipv6_extension_headers.go
index 2c4591409..2c4591409 100755..100644
--- a/pkg/tcpip/header/ipv6_extension_headers.go
+++ b/pkg/tcpip/header/ipv6_extension_headers.go
diff --git a/pkg/tcpip/header/ndp_neighbor_advert.go b/pkg/tcpip/header/ndp_neighbor_advert.go
index 505c92668..505c92668 100755..100644
--- a/pkg/tcpip/header/ndp_neighbor_advert.go
+++ b/pkg/tcpip/header/ndp_neighbor_advert.go
diff --git a/pkg/tcpip/header/ndp_neighbor_solicit.go b/pkg/tcpip/header/ndp_neighbor_solicit.go
index 3a1b8e139..3a1b8e139 100755..100644
--- a/pkg/tcpip/header/ndp_neighbor_solicit.go
+++ b/pkg/tcpip/header/ndp_neighbor_solicit.go
diff --git a/pkg/tcpip/header/ndp_options.go b/pkg/tcpip/header/ndp_options.go
index 5d3975c56..5d3975c56 100755..100644
--- a/pkg/tcpip/header/ndp_options.go
+++ b/pkg/tcpip/header/ndp_options.go
diff --git a/pkg/tcpip/header/ndp_router_advert.go b/pkg/tcpip/header/ndp_router_advert.go
index bf7610863..bf7610863 100755..100644
--- a/pkg/tcpip/header/ndp_router_advert.go
+++ b/pkg/tcpip/header/ndp_router_advert.go
diff --git a/pkg/tcpip/header/ndp_router_solicit.go b/pkg/tcpip/header/ndp_router_solicit.go
index 9e67ba95d..9e67ba95d 100755..100644
--- a/pkg/tcpip/header/ndp_router_solicit.go
+++ b/pkg/tcpip/header/ndp_router_solicit.go
diff --git a/pkg/tcpip/header/ndpoptionidentifier_string.go b/pkg/tcpip/header/ndpoptionidentifier_string.go
index 6fe9a336b..6fe9a336b 100755..100644
--- a/pkg/tcpip/header/ndpoptionidentifier_string.go
+++ b/pkg/tcpip/header/ndpoptionidentifier_string.go
diff --git a/pkg/tcpip/header/tcp.go b/pkg/tcpip/header/tcp.go
index 29454c4b9..4c6f808e5 100644
--- a/pkg/tcpip/header/tcp.go
+++ b/pkg/tcpip/header/tcp.go
@@ -66,6 +66,14 @@ const (
TCPOptionSACK = 5
)
+// Option Lengths.
+const (
+ TCPOptionMSSLength = 4
+ TCPOptionTSLength = 10
+ TCPOptionWSLength = 3
+ TCPOptionSackPermittedLength = 2
+)
+
// TCPFields contains the fields of a TCP packet. It is used to describe the
// fields of a packet that needs to be encoded.
type TCPFields struct {
@@ -494,14 +502,11 @@ func ParseTCPOptions(b []byte) TCPOptions {
// returns without encoding anything. It returns the number of bytes written to
// the provided buffer.
func EncodeMSSOption(mss uint32, b []byte) int {
- // mssOptionSize is the number of bytes in a valid MSS option.
- const mssOptionSize = 4
-
- if len(b) < mssOptionSize {
+ if len(b) < TCPOptionMSSLength {
return 0
}
- b[0], b[1], b[2], b[3] = TCPOptionMSS, mssOptionSize, byte(mss>>8), byte(mss)
- return mssOptionSize
+ b[0], b[1], b[2], b[3] = TCPOptionMSS, TCPOptionMSSLength, byte(mss>>8), byte(mss)
+ return TCPOptionMSSLength
}
// EncodeWSOption encodes the WS TCP option with the WS value in the
@@ -509,10 +514,10 @@ func EncodeMSSOption(mss uint32, b []byte) int {
// returns without encoding anything. It returns the number of bytes written to
// the provided buffer.
func EncodeWSOption(ws int, b []byte) int {
- if len(b) < 3 {
+ if len(b) < TCPOptionWSLength {
return 0
}
- b[0], b[1], b[2] = TCPOptionWS, 3, uint8(ws)
+ b[0], b[1], b[2] = TCPOptionWS, TCPOptionWSLength, uint8(ws)
return int(b[1])
}
@@ -521,10 +526,10 @@ func EncodeWSOption(ws int, b []byte) int {
// just returns without encoding anything. It returns the number of bytes
// written to the provided buffer.
func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int {
- if len(b) < 10 {
+ if len(b) < TCPOptionTSLength {
return 0
}
- b[0], b[1] = TCPOptionTS, 10
+ b[0], b[1] = TCPOptionTS, TCPOptionTSLength
binary.BigEndian.PutUint32(b[2:], tsVal)
binary.BigEndian.PutUint32(b[6:], tsEcr)
return int(b[1])
@@ -535,11 +540,11 @@ func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int {
// encoding anything. It returns the number of bytes written to the provided
// buffer.
func EncodeSACKPermittedOption(b []byte) int {
- if len(b) < 2 {
+ if len(b) < TCPOptionSackPermittedLength {
return 0
}
- b[0], b[1] = TCPOptionSACKPermitted, 2
+ b[0], b[1] = TCPOptionSACKPermitted, TCPOptionSackPermittedLength
return int(b[1])
}
diff --git a/pkg/tcpip/link/channel/channel.go b/pkg/tcpip/link/channel/channel.go
index 9bf67686d..9bf67686d 100755..100644
--- a/pkg/tcpip/link/channel/channel.go
+++ b/pkg/tcpip/link/channel/channel.go
diff --git a/pkg/tcpip/link/channel/channel_state_autogen.go b/pkg/tcpip/link/channel/channel_state_autogen.go
index ce52482a2..ce52482a2 100755..100644
--- a/pkg/tcpip/link/channel/channel_state_autogen.go
+++ b/pkg/tcpip/link/channel/channel_state_autogen.go
diff --git a/pkg/tcpip/link/fdbased/fdbased_state_autogen.go b/pkg/tcpip/link/fdbased/fdbased_state_autogen.go
index b84e8f21c..b84e8f21c 100755..100644
--- a/pkg/tcpip/link/fdbased/fdbased_state_autogen.go
+++ b/pkg/tcpip/link/fdbased/fdbased_state_autogen.go
diff --git a/pkg/tcpip/link/fdbased/fdbased_unsafe_state_autogen.go b/pkg/tcpip/link/fdbased/fdbased_unsafe_state_autogen.go
index e2ed505b2..e2ed505b2 100755..100644
--- a/pkg/tcpip/link/fdbased/fdbased_unsafe_state_autogen.go
+++ b/pkg/tcpip/link/fdbased/fdbased_unsafe_state_autogen.go
diff --git a/pkg/tcpip/link/fdbased/packet_dispatchers.go b/pkg/tcpip/link/fdbased/packet_dispatchers.go
index cb4cbea69..3aaabd1aa 100644
--- a/pkg/tcpip/link/fdbased/packet_dispatchers.go
+++ b/pkg/tcpip/link/fdbased/packet_dispatchers.go
@@ -169,7 +169,7 @@ type recvMMsgDispatcher struct {
// iovecs is an array of array of iovec records where each iovec base
// pointer and length are initialzed to the corresponding view above,
- // except when GSO is neabled then the first iovec in each array of
+ // except when GSO is enabled then the first iovec in each array of
// iovecs points to a buffer for the vnet header which is stripped
// before the views are passed up the stack for further processing.
iovecs [][]syscall.Iovec
diff --git a/pkg/tcpip/link/loopback/loopback_state_autogen.go b/pkg/tcpip/link/loopback/loopback_state_autogen.go
index c00fd9f19..c00fd9f19 100755..100644
--- a/pkg/tcpip/link/loopback/loopback_state_autogen.go
+++ b/pkg/tcpip/link/loopback/loopback_state_autogen.go
diff --git a/pkg/tcpip/link/muxed/injectable.go b/pkg/tcpip/link/muxed/injectable.go
index a5478ce17..a5478ce17 100755..100644
--- a/pkg/tcpip/link/muxed/injectable.go
+++ b/pkg/tcpip/link/muxed/injectable.go
diff --git a/pkg/tcpip/link/muxed/muxed_state_autogen.go b/pkg/tcpip/link/muxed/muxed_state_autogen.go
index 56330e2a5..56330e2a5 100755..100644
--- a/pkg/tcpip/link/muxed/muxed_state_autogen.go
+++ b/pkg/tcpip/link/muxed/muxed_state_autogen.go
diff --git a/pkg/tcpip/link/qdisc/fifo/endpoint.go b/pkg/tcpip/link/qdisc/fifo/endpoint.go
index 54432194d..54432194d 100755..100644
--- a/pkg/tcpip/link/qdisc/fifo/endpoint.go
+++ b/pkg/tcpip/link/qdisc/fifo/endpoint.go
diff --git a/pkg/tcpip/link/qdisc/fifo/fifo_state_autogen.go b/pkg/tcpip/link/qdisc/fifo/fifo_state_autogen.go
index 9eb52b1cb..9eb52b1cb 100755..100644
--- a/pkg/tcpip/link/qdisc/fifo/fifo_state_autogen.go
+++ b/pkg/tcpip/link/qdisc/fifo/fifo_state_autogen.go
diff --git a/pkg/tcpip/link/qdisc/fifo/packet_buffer_queue.go b/pkg/tcpip/link/qdisc/fifo/packet_buffer_queue.go
index eb5abb906..eb5abb906 100755..100644
--- a/pkg/tcpip/link/qdisc/fifo/packet_buffer_queue.go
+++ b/pkg/tcpip/link/qdisc/fifo/packet_buffer_queue.go
diff --git a/pkg/tcpip/link/rawfile/rawfile_state_autogen.go b/pkg/tcpip/link/rawfile/rawfile_state_autogen.go
index 338e9679b..338e9679b 100755..100644
--- a/pkg/tcpip/link/rawfile/rawfile_state_autogen.go
+++ b/pkg/tcpip/link/rawfile/rawfile_state_autogen.go
diff --git a/pkg/tcpip/link/rawfile/rawfile_unsafe_state_autogen.go b/pkg/tcpip/link/rawfile/rawfile_unsafe_state_autogen.go
index 70d62c4a1..70d62c4a1 100755..100644
--- a/pkg/tcpip/link/rawfile/rawfile_unsafe_state_autogen.go
+++ b/pkg/tcpip/link/rawfile/rawfile_unsafe_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/pipe.go b/pkg/tcpip/link/sharedmem/pipe/pipe.go
index 74c9f0311..74c9f0311 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/pipe.go
+++ b/pkg/tcpip/link/sharedmem/pipe/pipe.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/pipe_state_autogen.go b/pkg/tcpip/link/sharedmem/pipe/pipe_state_autogen.go
index d3b40feb4..d3b40feb4 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/pipe_state_autogen.go
+++ b/pkg/tcpip/link/sharedmem/pipe/pipe_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe.go b/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe.go
index 62d17029e..62d17029e 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe.go
+++ b/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe_state_autogen.go b/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe_state_autogen.go
index d3b40feb4..d3b40feb4 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe_state_autogen.go
+++ b/pkg/tcpip/link/sharedmem/pipe/pipe_unsafe_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/rx.go b/pkg/tcpip/link/sharedmem/pipe/rx.go
index f22e533ac..f22e533ac 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/rx.go
+++ b/pkg/tcpip/link/sharedmem/pipe/rx.go
diff --git a/pkg/tcpip/link/sharedmem/pipe/tx.go b/pkg/tcpip/link/sharedmem/pipe/tx.go
index 9841eb231..9841eb231 100755..100644
--- a/pkg/tcpip/link/sharedmem/pipe/tx.go
+++ b/pkg/tcpip/link/sharedmem/pipe/tx.go
diff --git a/pkg/tcpip/link/sharedmem/queue/queue_state_autogen.go b/pkg/tcpip/link/sharedmem/queue/queue_state_autogen.go
index 563d4fbb4..563d4fbb4 100755..100644
--- a/pkg/tcpip/link/sharedmem/queue/queue_state_autogen.go
+++ b/pkg/tcpip/link/sharedmem/queue/queue_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/queue/rx.go b/pkg/tcpip/link/sharedmem/queue/rx.go
index 696e6c9e5..696e6c9e5 100755..100644
--- a/pkg/tcpip/link/sharedmem/queue/rx.go
+++ b/pkg/tcpip/link/sharedmem/queue/rx.go
diff --git a/pkg/tcpip/link/sharedmem/queue/tx.go b/pkg/tcpip/link/sharedmem/queue/tx.go
index beffe807b..beffe807b 100755..100644
--- a/pkg/tcpip/link/sharedmem/queue/tx.go
+++ b/pkg/tcpip/link/sharedmem/queue/tx.go
diff --git a/pkg/tcpip/link/sharedmem/rx.go b/pkg/tcpip/link/sharedmem/rx.go
index eec11e4cb..eec11e4cb 100755..100644
--- a/pkg/tcpip/link/sharedmem/rx.go
+++ b/pkg/tcpip/link/sharedmem/rx.go
diff --git a/pkg/tcpip/link/sharedmem/sharedmem.go b/pkg/tcpip/link/sharedmem/sharedmem.go
index 0796d717e..0796d717e 100755..100644
--- a/pkg/tcpip/link/sharedmem/sharedmem.go
+++ b/pkg/tcpip/link/sharedmem/sharedmem.go
diff --git a/pkg/tcpip/link/sharedmem/sharedmem_state_autogen.go b/pkg/tcpip/link/sharedmem/sharedmem_state_autogen.go
index bc12017b2..bc12017b2 100755..100644
--- a/pkg/tcpip/link/sharedmem/sharedmem_state_autogen.go
+++ b/pkg/tcpip/link/sharedmem/sharedmem_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go b/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go
index f7e816a41..f7e816a41 100755..100644
--- a/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go
+++ b/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go
diff --git a/pkg/tcpip/link/sharedmem/sharedmem_unsafe_state_autogen.go b/pkg/tcpip/link/sharedmem/sharedmem_unsafe_state_autogen.go
index ac3a66520..ac3a66520 100755..100644
--- a/pkg/tcpip/link/sharedmem/sharedmem_unsafe_state_autogen.go
+++ b/pkg/tcpip/link/sharedmem/sharedmem_unsafe_state_autogen.go
diff --git a/pkg/tcpip/link/sharedmem/tx.go b/pkg/tcpip/link/sharedmem/tx.go
index 6b8d7859d..6b8d7859d 100755..100644
--- a/pkg/tcpip/link/sharedmem/tx.go
+++ b/pkg/tcpip/link/sharedmem/tx.go
diff --git a/pkg/tcpip/link/sniffer/sniffer_state_autogen.go b/pkg/tcpip/link/sniffer/sniffer_state_autogen.go
index 8d79defea..8d79defea 100755..100644
--- a/pkg/tcpip/link/sniffer/sniffer_state_autogen.go
+++ b/pkg/tcpip/link/sniffer/sniffer_state_autogen.go
diff --git a/pkg/tcpip/link/tun/device.go b/pkg/tcpip/link/tun/device.go
index 617446ea2..617446ea2 100755..100644
--- a/pkg/tcpip/link/tun/device.go
+++ b/pkg/tcpip/link/tun/device.go
diff --git a/pkg/tcpip/link/tun/protocol.go b/pkg/tcpip/link/tun/protocol.go
index 89d9d91a9..89d9d91a9 100755..100644
--- a/pkg/tcpip/link/tun/protocol.go
+++ b/pkg/tcpip/link/tun/protocol.go
diff --git a/pkg/tcpip/link/tun/tun_state_autogen.go b/pkg/tcpip/link/tun/tun_state_autogen.go
index 4b70647af..4b70647af 100755..100644
--- a/pkg/tcpip/link/tun/tun_state_autogen.go
+++ b/pkg/tcpip/link/tun/tun_state_autogen.go
diff --git a/pkg/tcpip/link/tun/tun_unsafe.go b/pkg/tcpip/link/tun/tun_unsafe.go
index 09ca9b527..09ca9b527 100755..100644
--- a/pkg/tcpip/link/tun/tun_unsafe.go
+++ b/pkg/tcpip/link/tun/tun_unsafe.go
diff --git a/pkg/tcpip/link/tun/tun_unsafe_state_autogen.go b/pkg/tcpip/link/tun/tun_unsafe_state_autogen.go
index 149299ea3..149299ea3 100755..100644
--- a/pkg/tcpip/link/tun/tun_unsafe_state_autogen.go
+++ b/pkg/tcpip/link/tun/tun_unsafe_state_autogen.go
diff --git a/pkg/tcpip/link/waitable/waitable.go b/pkg/tcpip/link/waitable/waitable.go
index 2b3741276..2b3741276 100755..100644
--- a/pkg/tcpip/link/waitable/waitable.go
+++ b/pkg/tcpip/link/waitable/waitable.go
diff --git a/pkg/tcpip/link/waitable/waitable_state_autogen.go b/pkg/tcpip/link/waitable/waitable_state_autogen.go
index 059424fa0..059424fa0 100755..100644
--- a/pkg/tcpip/link/waitable/waitable_state_autogen.go
+++ b/pkg/tcpip/link/waitable/waitable_state_autogen.go
diff --git a/pkg/tcpip/network/arp/arp_state_autogen.go b/pkg/tcpip/network/arp/arp_state_autogen.go
index 5cd8535e3..5cd8535e3 100755..100644
--- a/pkg/tcpip/network/arp/arp_state_autogen.go
+++ b/pkg/tcpip/network/arp/arp_state_autogen.go
diff --git a/pkg/tcpip/network/fragmentation/fragmentation_state_autogen.go b/pkg/tcpip/network/fragmentation/fragmentation_state_autogen.go
index cbaecdaa7..cbaecdaa7 100755..100644
--- a/pkg/tcpip/network/fragmentation/fragmentation_state_autogen.go
+++ b/pkg/tcpip/network/fragmentation/fragmentation_state_autogen.go
diff --git a/pkg/tcpip/network/fragmentation/reassembler_list.go b/pkg/tcpip/network/fragmentation/reassembler_list.go
index b5d40bd25..b5d40bd25 100755..100644
--- a/pkg/tcpip/network/fragmentation/reassembler_list.go
+++ b/pkg/tcpip/network/fragmentation/reassembler_list.go
diff --git a/pkg/tcpip/network/hash/hash_state_autogen.go b/pkg/tcpip/network/hash/hash_state_autogen.go
index 9467fe298..9467fe298 100755..100644
--- a/pkg/tcpip/network/hash/hash_state_autogen.go
+++ b/pkg/tcpip/network/hash/hash_state_autogen.go
diff --git a/pkg/tcpip/network/ipv4/ipv4_state_autogen.go b/pkg/tcpip/network/ipv4/ipv4_state_autogen.go
index 250b2128e..250b2128e 100755..100644
--- a/pkg/tcpip/network/ipv4/ipv4_state_autogen.go
+++ b/pkg/tcpip/network/ipv4/ipv4_state_autogen.go
diff --git a/pkg/tcpip/network/ipv6/ipv6_state_autogen.go b/pkg/tcpip/network/ipv6/ipv6_state_autogen.go
index 40c67d440..40c67d440 100755..100644
--- a/pkg/tcpip/network/ipv6/ipv6_state_autogen.go
+++ b/pkg/tcpip/network/ipv6/ipv6_state_autogen.go
diff --git a/pkg/tcpip/ports/ports_state_autogen.go b/pkg/tcpip/ports/ports_state_autogen.go
index f0ee1bb11..f0ee1bb11 100755..100644
--- a/pkg/tcpip/ports/ports_state_autogen.go
+++ b/pkg/tcpip/ports/ports_state_autogen.go
diff --git a/pkg/tcpip/seqnum/seqnum_state_autogen.go b/pkg/tcpip/seqnum/seqnum_state_autogen.go
index 23e79811d..23e79811d 100755..100644
--- a/pkg/tcpip/seqnum/seqnum_state_autogen.go
+++ b/pkg/tcpip/seqnum/seqnum_state_autogen.go
diff --git a/pkg/tcpip/stack/conntrack.go b/pkg/tcpip/stack/conntrack.go
index 7d1ede1f2..7d1ede1f2 100755..100644
--- a/pkg/tcpip/stack/conntrack.go
+++ b/pkg/tcpip/stack/conntrack.go
diff --git a/pkg/tcpip/stack/dhcpv6configurationfromndpra_string.go b/pkg/tcpip/stack/dhcpv6configurationfromndpra_string.go
index d199ded6a..d199ded6a 100755..100644
--- a/pkg/tcpip/stack/dhcpv6configurationfromndpra_string.go
+++ b/pkg/tcpip/stack/dhcpv6configurationfromndpra_string.go
diff --git a/pkg/tcpip/stack/forwarder.go b/pkg/tcpip/stack/forwarder.go
index 6b64cd37f..6b64cd37f 100755..100644
--- a/pkg/tcpip/stack/forwarder.go
+++ b/pkg/tcpip/stack/forwarder.go
diff --git a/pkg/tcpip/stack/iptables.go b/pkg/tcpip/stack/iptables.go
index 443423b3c..443423b3c 100755..100644
--- a/pkg/tcpip/stack/iptables.go
+++ b/pkg/tcpip/stack/iptables.go
diff --git a/pkg/tcpip/stack/iptables_targets.go b/pkg/tcpip/stack/iptables_targets.go
index 36cc6275d..36cc6275d 100755..100644
--- a/pkg/tcpip/stack/iptables_targets.go
+++ b/pkg/tcpip/stack/iptables_targets.go
diff --git a/pkg/tcpip/stack/iptables_types.go b/pkg/tcpip/stack/iptables_types.go
index fe06007ae..fe06007ae 100755..100644
--- a/pkg/tcpip/stack/iptables_types.go
+++ b/pkg/tcpip/stack/iptables_types.go
diff --git a/pkg/tcpip/stack/linkaddrentry_list.go b/pkg/tcpip/stack/linkaddrentry_list.go
index 43022f9b3..43022f9b3 100755..100644
--- a/pkg/tcpip/stack/linkaddrentry_list.go
+++ b/pkg/tcpip/stack/linkaddrentry_list.go
diff --git a/pkg/tcpip/stack/ndp.go b/pkg/tcpip/stack/ndp.go
index 526c7d6ff..526c7d6ff 100755..100644
--- a/pkg/tcpip/stack/ndp.go
+++ b/pkg/tcpip/stack/ndp.go
diff --git a/pkg/tcpip/stack/packet_buffer.go b/pkg/tcpip/stack/packet_buffer.go
index 926df4d7b..926df4d7b 100755..100644
--- a/pkg/tcpip/stack/packet_buffer.go
+++ b/pkg/tcpip/stack/packet_buffer.go
diff --git a/pkg/tcpip/stack/packet_buffer_list.go b/pkg/tcpip/stack/packet_buffer_list.go
index 460c74c5a..460c74c5a 100755..100644
--- a/pkg/tcpip/stack/packet_buffer_list.go
+++ b/pkg/tcpip/stack/packet_buffer_list.go
diff --git a/pkg/tcpip/stack/rand.go b/pkg/tcpip/stack/rand.go
index 421fb5c15..421fb5c15 100755..100644
--- a/pkg/tcpip/stack/rand.go
+++ b/pkg/tcpip/stack/rand.go
diff --git a/pkg/tcpip/stack/stack_state_autogen.go b/pkg/tcpip/stack/stack_state_autogen.go
index 6e98e8e95..6e98e8e95 100755..100644
--- a/pkg/tcpip/stack/stack_state_autogen.go
+++ b/pkg/tcpip/stack/stack_state_autogen.go
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index 45e930ad8..b7b227328 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -110,6 +110,71 @@ var (
ErrAddressFamilyNotSupported = &Error{msg: "address family not supported by protocol"}
)
+var messageToError map[string]*Error
+
+var populate sync.Once
+
+// StringToError converts an error message to the error.
+func StringToError(s string) *Error {
+ populate.Do(func() {
+ var errors = []*Error{
+ ErrUnknownProtocol,
+ ErrUnknownNICID,
+ ErrUnknownDevice,
+ ErrUnknownProtocolOption,
+ ErrDuplicateNICID,
+ ErrDuplicateAddress,
+ ErrNoRoute,
+ ErrBadLinkEndpoint,
+ ErrAlreadyBound,
+ ErrInvalidEndpointState,
+ ErrAlreadyConnecting,
+ ErrAlreadyConnected,
+ ErrNoPortAvailable,
+ ErrPortInUse,
+ ErrBadLocalAddress,
+ ErrClosedForSend,
+ ErrClosedForReceive,
+ ErrWouldBlock,
+ ErrConnectionRefused,
+ ErrTimeout,
+ ErrAborted,
+ ErrConnectStarted,
+ ErrDestinationRequired,
+ ErrNotSupported,
+ ErrQueueSizeNotSupported,
+ ErrNotConnected,
+ ErrConnectionReset,
+ ErrConnectionAborted,
+ ErrNoSuchFile,
+ ErrInvalidOptionValue,
+ ErrNoLinkAddress,
+ ErrBadAddress,
+ ErrNetworkUnreachable,
+ ErrMessageTooLong,
+ ErrNoBufferSpace,
+ ErrBroadcastDisabled,
+ ErrNotPermitted,
+ ErrAddressFamilyNotSupported,
+ }
+
+ messageToError = make(map[string]*Error)
+ for _, e := range errors {
+ if messageToError[e.String()] != nil {
+ panic("tcpip errors with duplicated message: " + e.String())
+ }
+ messageToError[e.String()] = e
+ }
+ })
+
+ e, ok := messageToError[s]
+ if !ok {
+ panic("unknown error message: " + s)
+ }
+
+ return e
+}
+
// Errors related to Subnet
var (
errSubnetLengthMismatch = errors.New("subnet length of address and mask differ")
diff --git a/pkg/tcpip/tcpip_state_autogen.go b/pkg/tcpip/tcpip_state_autogen.go
index 8ea900688..8ea900688 100755..100644
--- a/pkg/tcpip/tcpip_state_autogen.go
+++ b/pkg/tcpip/tcpip_state_autogen.go
diff --git a/pkg/tcpip/tcpip_unsafe_state_autogen.go b/pkg/tcpip/tcpip_unsafe_state_autogen.go
index 32d2350f4..32d2350f4 100755..100644
--- a/pkg/tcpip/tcpip_unsafe_state_autogen.go
+++ b/pkg/tcpip/tcpip_unsafe_state_autogen.go
diff --git a/pkg/tcpip/timer.go b/pkg/tcpip/timer.go
index 59f3b391f..59f3b391f 100755..100644
--- a/pkg/tcpip/timer.go
+++ b/pkg/tcpip/timer.go
diff --git a/pkg/tcpip/transport/icmp/icmp_packet_list.go b/pkg/tcpip/transport/icmp/icmp_packet_list.go
index 42d63f976..42d63f976 100755..100644
--- a/pkg/tcpip/transport/icmp/icmp_packet_list.go
+++ b/pkg/tcpip/transport/icmp/icmp_packet_list.go
diff --git a/pkg/tcpip/transport/icmp/icmp_state_autogen.go b/pkg/tcpip/transport/icmp/icmp_state_autogen.go
index c26460a4b..c26460a4b 100755..100644
--- a/pkg/tcpip/transport/icmp/icmp_state_autogen.go
+++ b/pkg/tcpip/transport/icmp/icmp_state_autogen.go
diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go
index 23158173d..23158173d 100755..100644
--- a/pkg/tcpip/transport/packet/endpoint.go
+++ b/pkg/tcpip/transport/packet/endpoint.go
diff --git a/pkg/tcpip/transport/packet/endpoint_state.go b/pkg/tcpip/transport/packet/endpoint_state.go
index 9b88f17e4..9b88f17e4 100755..100644
--- a/pkg/tcpip/transport/packet/endpoint_state.go
+++ b/pkg/tcpip/transport/packet/endpoint_state.go
diff --git a/pkg/tcpip/transport/packet/packet_list.go b/pkg/tcpip/transport/packet/packet_list.go
index 5231b066f..5231b066f 100755..100644
--- a/pkg/tcpip/transport/packet/packet_list.go
+++ b/pkg/tcpip/transport/packet/packet_list.go
diff --git a/pkg/tcpip/transport/packet/packet_state_autogen.go b/pkg/tcpip/transport/packet/packet_state_autogen.go
index 8ff339e08..8ff339e08 100755..100644
--- a/pkg/tcpip/transport/packet/packet_state_autogen.go
+++ b/pkg/tcpip/transport/packet/packet_state_autogen.go
diff --git a/pkg/tcpip/transport/raw/raw_packet_list.go b/pkg/tcpip/transport/raw/raw_packet_list.go
index 15a8c845b..15a8c845b 100755..100644
--- a/pkg/tcpip/transport/raw/raw_packet_list.go
+++ b/pkg/tcpip/transport/raw/raw_packet_list.go
diff --git a/pkg/tcpip/transport/raw/raw_state_autogen.go b/pkg/tcpip/transport/raw/raw_state_autogen.go
index c755fa847..c755fa847 100755..100644
--- a/pkg/tcpip/transport/raw/raw_state_autogen.go
+++ b/pkg/tcpip/transport/raw/raw_state_autogen.go
diff --git a/pkg/tcpip/transport/tcp/connect_unsafe.go b/pkg/tcpip/transport/tcp/connect_unsafe.go
index cfc304616..cfc304616 100755..100644
--- a/pkg/tcpip/transport/tcp/connect_unsafe.go
+++ b/pkg/tcpip/transport/tcp/connect_unsafe.go
diff --git a/pkg/tcpip/transport/tcp/dispatcher.go b/pkg/tcpip/transport/tcp/dispatcher.go
index 6062ca916..6062ca916 100755..100644
--- a/pkg/tcpip/transport/tcp/dispatcher.go
+++ b/pkg/tcpip/transport/tcp/dispatcher.go
diff --git a/pkg/tcpip/transport/tcp/endpoint_state.go b/pkg/tcpip/transport/tcp/endpoint_state.go
index 8b7562396..fc43c11e2 100644
--- a/pkg/tcpip/transport/tcp/endpoint_state.go
+++ b/pkg/tcpip/transport/tcp/endpoint_state.go
@@ -314,7 +314,7 @@ func (e *endpoint) loadLastError(s string) {
return
}
- e.lastError = loadError(s)
+ e.lastError = tcpip.StringToError(s)
}
// saveHardError is invoked by stateify.
@@ -332,71 +332,7 @@ func (e *EndpointInfo) loadHardError(s string) {
return
}
- e.HardError = loadError(s)
-}
-
-var messageToError map[string]*tcpip.Error
-
-var populate sync.Once
-
-func loadError(s string) *tcpip.Error {
- populate.Do(func() {
- var errors = []*tcpip.Error{
- tcpip.ErrUnknownProtocol,
- tcpip.ErrUnknownNICID,
- tcpip.ErrUnknownDevice,
- tcpip.ErrUnknownProtocolOption,
- tcpip.ErrDuplicateNICID,
- tcpip.ErrDuplicateAddress,
- tcpip.ErrNoRoute,
- tcpip.ErrBadLinkEndpoint,
- tcpip.ErrAlreadyBound,
- tcpip.ErrInvalidEndpointState,
- tcpip.ErrAlreadyConnecting,
- tcpip.ErrAlreadyConnected,
- tcpip.ErrNoPortAvailable,
- tcpip.ErrPortInUse,
- tcpip.ErrBadLocalAddress,
- tcpip.ErrClosedForSend,
- tcpip.ErrClosedForReceive,
- tcpip.ErrWouldBlock,
- tcpip.ErrConnectionRefused,
- tcpip.ErrTimeout,
- tcpip.ErrAborted,
- tcpip.ErrConnectStarted,
- tcpip.ErrDestinationRequired,
- tcpip.ErrNotSupported,
- tcpip.ErrQueueSizeNotSupported,
- tcpip.ErrNotConnected,
- tcpip.ErrConnectionReset,
- tcpip.ErrConnectionAborted,
- tcpip.ErrNoSuchFile,
- tcpip.ErrInvalidOptionValue,
- tcpip.ErrNoLinkAddress,
- tcpip.ErrBadAddress,
- tcpip.ErrNetworkUnreachable,
- tcpip.ErrMessageTooLong,
- tcpip.ErrNoBufferSpace,
- tcpip.ErrBroadcastDisabled,
- tcpip.ErrNotPermitted,
- tcpip.ErrAddressFamilyNotSupported,
- }
-
- messageToError = make(map[string]*tcpip.Error)
- for _, e := range errors {
- if messageToError[e.String()] != nil {
- panic("tcpip errors with duplicated message: " + e.String())
- }
- messageToError[e.String()] = e
- }
- })
-
- e, ok := messageToError[s]
- if !ok {
- panic("unknown error message: " + s)
- }
-
- return e
+ e.HardError = tcpip.StringToError(s)
}
// saveMeasureTime is invoked by stateify.
diff --git a/pkg/tcpip/transport/tcp/rcv_state.go b/pkg/tcpip/transport/tcp/rcv_state.go
index 2bf21a2e7..2bf21a2e7 100755..100644
--- a/pkg/tcpip/transport/tcp/rcv_state.go
+++ b/pkg/tcpip/transport/tcp/rcv_state.go
diff --git a/pkg/tcpip/transport/tcp/tcp_endpoint_list.go b/pkg/tcpip/transport/tcp/tcp_endpoint_list.go
index fb7046d8f..fb7046d8f 100755..100644
--- a/pkg/tcpip/transport/tcp/tcp_endpoint_list.go
+++ b/pkg/tcpip/transport/tcp/tcp_endpoint_list.go
diff --git a/pkg/tcpip/transport/tcp/tcp_segment_list.go b/pkg/tcpip/transport/tcp/tcp_segment_list.go
index 21638041c..21638041c 100755..100644
--- a/pkg/tcpip/transport/tcp/tcp_segment_list.go
+++ b/pkg/tcpip/transport/tcp/tcp_segment_list.go
diff --git a/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_state_autogen.go
index e5d0a218a..e5d0a218a 100755..100644
--- a/pkg/tcpip/transport/tcp/tcp_state_autogen.go
+++ b/pkg/tcpip/transport/tcp/tcp_state_autogen.go
diff --git a/pkg/tcpip/transport/tcp/tcp_unsafe_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_unsafe_state_autogen.go
index 4cb82fcc9..4cb82fcc9 100755..100644
--- a/pkg/tcpip/transport/tcp/tcp_unsafe_state_autogen.go
+++ b/pkg/tcpip/transport/tcp/tcp_unsafe_state_autogen.go
diff --git a/pkg/tcpip/transport/tcpconntrack/tcp_conntrack.go b/pkg/tcpip/transport/tcpconntrack/tcp_conntrack.go
index 12bc1b5b5..12bc1b5b5 100755..100644
--- a/pkg/tcpip/transport/tcpconntrack/tcp_conntrack.go
+++ b/pkg/tcpip/transport/tcpconntrack/tcp_conntrack.go
diff --git a/pkg/tcpip/transport/tcpconntrack/tcpconntrack_state_autogen.go b/pkg/tcpip/transport/tcpconntrack/tcpconntrack_state_autogen.go
index ff53204da..ff53204da 100755..100644
--- a/pkg/tcpip/transport/tcpconntrack/tcpconntrack_state_autogen.go
+++ b/pkg/tcpip/transport/tcpconntrack/tcpconntrack_state_autogen.go
diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go
index 756ab913a..647b2067a 100644
--- a/pkg/tcpip/transport/udp/endpoint.go
+++ b/pkg/tcpip/transport/udp/endpoint.go
@@ -106,6 +106,9 @@ type endpoint struct {
bindToDevice tcpip.NICID
broadcast bool
+ lastErrorMu sync.Mutex `state:"nosave"`
+ lastError *tcpip.Error `state:".(string)"`
+
// Values used to reserve a port or register a transport endpoint.
// (which ever happens first).
boundBindToDevice tcpip.NICID
@@ -188,6 +191,15 @@ func (e *endpoint) UniqueID() uint64 {
return e.uniqueID
}
+func (e *endpoint) takeLastError() *tcpip.Error {
+ e.lastErrorMu.Lock()
+ defer e.lastErrorMu.Unlock()
+
+ err := e.lastError
+ e.lastError = nil
+ return err
+}
+
// Abort implements stack.TransportEndpoint.Abort.
func (e *endpoint) Abort() {
e.Close()
@@ -243,6 +255,10 @@ func (e *endpoint) IPTables() (stack.IPTables, error) {
// Read reads data from the endpoint. This method does not block if
// there is no data pending.
func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
+ if err := e.takeLastError(); err != nil {
+ return buffer.View{}, tcpip.ControlMessages{}, err
+ }
+
e.rcvMu.Lock()
if e.rcvList.Empty() {
@@ -382,6 +398,10 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
}
func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-chan struct{}, *tcpip.Error) {
+ if err := e.takeLastError(); err != nil {
+ return 0, nil, err
+ }
+
// MSG_MORE is unimplemented. (This also means that MSG_EOR is a no-op.)
if opts.More {
return 0, nil, tcpip.ErrInvalidOptionValue
@@ -853,6 +873,7 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
case tcpip.ErrorOption:
+ return e.takeLastError()
case *tcpip.MulticastInterfaceOption:
e.mu.Lock()
*o = tcpip.MulticastInterfaceOption{
@@ -1316,6 +1337,17 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, pk
// HandleControlPacket implements stack.TransportEndpoint.HandleControlPacket.
func (e *endpoint) HandleControlPacket(id stack.TransportEndpointID, typ stack.ControlType, extra uint32, pkt stack.PacketBuffer) {
+ if typ == stack.ControlPortUnreachable {
+ e.mu.RLock()
+ defer e.mu.RUnlock()
+
+ if e.state == StateConnected {
+ e.lastErrorMu.Lock()
+ defer e.lastErrorMu.Unlock()
+
+ e.lastError = tcpip.ErrConnectionRefused
+ }
+ }
}
// State implements tcpip.Endpoint.State.
diff --git a/pkg/tcpip/transport/udp/endpoint_state.go b/pkg/tcpip/transport/udp/endpoint_state.go
index 466bd9381..851e6b635 100644
--- a/pkg/tcpip/transport/udp/endpoint_state.go
+++ b/pkg/tcpip/transport/udp/endpoint_state.go
@@ -37,6 +37,24 @@ func (u *udpPacket) loadData(data buffer.VectorisedView) {
u.data = data
}
+// saveLastError is invoked by stateify.
+func (e *endpoint) saveLastError() string {
+ if e.lastError == nil {
+ return ""
+ }
+
+ return e.lastError.String()
+}
+
+// loadLastError is invoked by stateify.
+func (e *endpoint) loadLastError(s string) {
+ if s == "" {
+ return
+ }
+
+ e.lastError = tcpip.StringToError(s)
+}
+
// beforeSave is invoked by stateify.
func (e *endpoint) beforeSave() {
// Stop incoming packets from being handled (and mutate endpoint state).
diff --git a/pkg/tcpip/transport/udp/udp_packet_list.go b/pkg/tcpip/transport/udp/udp_packet_list.go
index a6513e1e4..a6513e1e4 100755..100644
--- a/pkg/tcpip/transport/udp/udp_packet_list.go
+++ b/pkg/tcpip/transport/udp/udp_packet_list.go
diff --git a/pkg/tcpip/transport/udp/udp_state_autogen.go b/pkg/tcpip/transport/udp/udp_state_autogen.go
index e8ab82021..a6d58f290 100755..100644
--- a/pkg/tcpip/transport/udp/udp_state_autogen.go
+++ b/pkg/tcpip/transport/udp/udp_state_autogen.go
@@ -33,6 +33,8 @@ func (x *endpoint) save(m state.Map) {
x.beforeSave()
var rcvBufSizeMax int = x.saveRcvBufSizeMax()
m.SaveValue("rcvBufSizeMax", rcvBufSizeMax)
+ var lastError string = x.saveLastError()
+ m.SaveValue("lastError", lastError)
m.Save("TransportEndpointInfo", &x.TransportEndpointInfo)
m.Save("waiterQueue", &x.waiterQueue)
m.Save("uniqueID", &x.uniqueID)
@@ -95,6 +97,7 @@ func (x *endpoint) load(m state.Map) {
m.Load("effectiveNetProtos", &x.effectiveNetProtos)
m.Load("owner", &x.owner)
m.LoadValue("rcvBufSizeMax", new(int), func(y interface{}) { x.loadRcvBufSizeMax(y.(int)) })
+ m.LoadValue("lastError", new(string), func(y interface{}) { x.loadLastError(y.(string)) })
m.AfterLoad(x.afterLoad)
}
diff --git a/pkg/unet/unet_state_autogen.go b/pkg/unet/unet_state_autogen.go
index 9bbf31d35..9bbf31d35 100755..100644
--- a/pkg/unet/unet_state_autogen.go
+++ b/pkg/unet/unet_state_autogen.go
diff --git a/pkg/unet/unet_unsafe_state_autogen.go b/pkg/unet/unet_unsafe_state_autogen.go
index 9bbf31d35..9bbf31d35 100755..100644
--- a/pkg/unet/unet_unsafe_state_autogen.go
+++ b/pkg/unet/unet_unsafe_state_autogen.go
diff --git a/pkg/urpc/urpc_state_autogen.go b/pkg/urpc/urpc_state_autogen.go
index 5fdca6717..5fdca6717 100755..100644
--- a/pkg/urpc/urpc_state_autogen.go
+++ b/pkg/urpc/urpc_state_autogen.go
diff --git a/pkg/usermem/access_type.go b/pkg/usermem/access_type.go
index 9c1742a59..9c1742a59 100755..100644
--- a/pkg/usermem/access_type.go
+++ b/pkg/usermem/access_type.go
diff --git a/pkg/usermem/addr.go b/pkg/usermem/addr.go
index e79210804..c4100481e 100755..100644
--- a/pkg/usermem/addr.go
+++ b/pkg/usermem/addr.go
@@ -106,3 +106,20 @@ func (ar AddrRange) IsPageAligned() bool {
func (ar AddrRange) String() string {
return fmt.Sprintf("[%#x, %#x)", ar.Start, ar.End)
}
+
+// PageRoundDown/Up are equivalent to Addr.RoundDown/Up, but without the
+// potentially truncating conversion from uint64 to Addr. This is necessary
+// because there is no way to define generic "PageRoundDown/Up" functions in Go.
+
+// PageRoundDown returns x rounded down to the nearest page boundary.
+func PageRoundDown(x uint64) uint64 {
+ return x &^ (PageSize - 1)
+}
+
+// PageRoundUp returns x rounded up to the nearest page boundary.
+// ok is true iff rounding up did not wrap around.
+func PageRoundUp(x uint64) (addr uint64, ok bool) {
+ addr = PageRoundDown(x + PageSize - 1)
+ ok = addr >= x
+ return
+}
diff --git a/pkg/usermem/addr_range.go b/pkg/usermem/addr_range.go
index 152ed1434..152ed1434 100755..100644
--- a/pkg/usermem/addr_range.go
+++ b/pkg/usermem/addr_range.go
diff --git a/pkg/usermem/addr_range_seq_unsafe.go b/pkg/usermem/addr_range_seq_unsafe.go
index c09337c15..c09337c15 100755..100644
--- a/pkg/usermem/addr_range_seq_unsafe.go
+++ b/pkg/usermem/addr_range_seq_unsafe.go
diff --git a/pkg/usermem/bytes_io.go b/pkg/usermem/bytes_io.go
index e177d30eb..e177d30eb 100755..100644
--- a/pkg/usermem/bytes_io.go
+++ b/pkg/usermem/bytes_io.go
diff --git a/pkg/usermem/bytes_io_unsafe.go b/pkg/usermem/bytes_io_unsafe.go
index 20de5037d..20de5037d 100755..100644
--- a/pkg/usermem/bytes_io_unsafe.go
+++ b/pkg/usermem/bytes_io_unsafe.go
diff --git a/pkg/usermem/usermem.go b/pkg/usermem/usermem.go
index cd6a0ea6b..cd6a0ea6b 100755..100644
--- a/pkg/usermem/usermem.go
+++ b/pkg/usermem/usermem.go
diff --git a/pkg/usermem/usermem_arm64.go b/pkg/usermem/usermem_arm64.go
index fdfc30a66..fdfc30a66 100755..100644
--- a/pkg/usermem/usermem_arm64.go
+++ b/pkg/usermem/usermem_arm64.go
diff --git a/pkg/usermem/usermem_arm64_state_autogen.go b/pkg/usermem/usermem_arm64_state_autogen.go
index d7c365e5d..d7c365e5d 100755..100644
--- a/pkg/usermem/usermem_arm64_state_autogen.go
+++ b/pkg/usermem/usermem_arm64_state_autogen.go
diff --git a/pkg/usermem/usermem_state_autogen.go b/pkg/usermem/usermem_state_autogen.go
index 20aa2d2de..20aa2d2de 100755..100644
--- a/pkg/usermem/usermem_state_autogen.go
+++ b/pkg/usermem/usermem_state_autogen.go
diff --git a/pkg/usermem/usermem_unsafe_state_autogen.go b/pkg/usermem/usermem_unsafe_state_autogen.go
index 62f8af4c9..62f8af4c9 100755..100644
--- a/pkg/usermem/usermem_unsafe_state_autogen.go
+++ b/pkg/usermem/usermem_unsafe_state_autogen.go
diff --git a/pkg/usermem/usermem_x86.go b/pkg/usermem/usermem_x86.go
index d96f829fb..d96f829fb 100755..100644
--- a/pkg/usermem/usermem_x86.go
+++ b/pkg/usermem/usermem_x86.go
diff --git a/pkg/usermem/usermem_x86_state_autogen.go b/pkg/usermem/usermem_x86_state_autogen.go
index cca386593..cca386593 100755..100644
--- a/pkg/usermem/usermem_x86_state_autogen.go
+++ b/pkg/usermem/usermem_x86_state_autogen.go
diff --git a/pkg/waiter/waiter_list.go b/pkg/waiter/waiter_list.go
index 35431f5a4..35431f5a4 100755..100644
--- a/pkg/waiter/waiter_list.go
+++ b/pkg/waiter/waiter_list.go
diff --git a/pkg/waiter/waiter_state_autogen.go b/pkg/waiter/waiter_state_autogen.go
index cf7f5fc2c..cf7f5fc2c 100755..100644
--- a/pkg/waiter/waiter_state_autogen.go
+++ b/pkg/waiter/waiter_state_autogen.go
diff --git a/runsc/boot/boot_amd64_state_autogen.go b/runsc/boot/boot_amd64_state_autogen.go
index 23dd4b7b3..23dd4b7b3 100755..100644
--- a/runsc/boot/boot_amd64_state_autogen.go
+++ b/runsc/boot/boot_amd64_state_autogen.go
diff --git a/runsc/boot/boot_arm64_state_autogen.go b/runsc/boot/boot_arm64_state_autogen.go
index 23dd4b7b3..23dd4b7b3 100755..100644
--- a/runsc/boot/boot_arm64_state_autogen.go
+++ b/runsc/boot/boot_arm64_state_autogen.go
diff --git a/runsc/boot/boot_state_autogen.go b/runsc/boot/boot_state_autogen.go
index 167d1cf02..167d1cf02 100755..100644
--- a/runsc/boot/boot_state_autogen.go
+++ b/runsc/boot/boot_state_autogen.go
diff --git a/runsc/boot/compat_arm64.go b/runsc/boot/compat_arm64.go
index bce9d95b3..bce9d95b3 100755..100644
--- a/runsc/boot/compat_arm64.go
+++ b/runsc/boot/compat_arm64.go
diff --git a/runsc/boot/filter/config_amd64.go b/runsc/boot/filter/config_amd64.go
index 5335ff82c..5335ff82c 100755..100644
--- a/runsc/boot/filter/config_amd64.go
+++ b/runsc/boot/filter/config_amd64.go
diff --git a/runsc/boot/filter/config_arm64.go b/runsc/boot/filter/config_arm64.go
index 7fa9bbda3..7fa9bbda3 100755..100644
--- a/runsc/boot/filter/config_arm64.go
+++ b/runsc/boot/filter/config_arm64.go
diff --git a/runsc/boot/filter/config_profile.go b/runsc/boot/filter/config_profile.go
index 194952a7b..194952a7b 100755..100644
--- a/runsc/boot/filter/config_profile.go
+++ b/runsc/boot/filter/config_profile.go
diff --git a/runsc/boot/filter/filter_amd64_state_autogen.go b/runsc/boot/filter/filter_amd64_state_autogen.go
index 0f27e5568..0f27e5568 100755..100644
--- a/runsc/boot/filter/filter_amd64_state_autogen.go
+++ b/runsc/boot/filter/filter_amd64_state_autogen.go
diff --git a/runsc/boot/filter/filter_arm64_state_autogen.go b/runsc/boot/filter/filter_arm64_state_autogen.go
index e87cf5af7..e87cf5af7 100755..100644
--- a/runsc/boot/filter/filter_arm64_state_autogen.go
+++ b/runsc/boot/filter/filter_arm64_state_autogen.go
diff --git a/runsc/boot/filter/filter_race_state_autogen.go b/runsc/boot/filter/filter_race_state_autogen.go
index c4a858e80..c4a858e80 100755..100644
--- a/runsc/boot/filter/filter_race_state_autogen.go
+++ b/runsc/boot/filter/filter_race_state_autogen.go
diff --git a/runsc/boot/filter/filter_state_autogen.go b/runsc/boot/filter/filter_state_autogen.go
index 41ff99424..41ff99424 100755..100644
--- a/runsc/boot/filter/filter_state_autogen.go
+++ b/runsc/boot/filter/filter_state_autogen.go
diff --git a/runsc/boot/platforms/platforms_state_autogen.go b/runsc/boot/platforms/platforms_state_autogen.go
index 8676d25c1..8676d25c1 100755..100644
--- a/runsc/boot/platforms/platforms_state_autogen.go
+++ b/runsc/boot/platforms/platforms_state_autogen.go
diff --git a/runsc/boot/pprof/pprof.go b/runsc/boot/pprof/pprof.go
index 1ded20dee..1ded20dee 100755..100644
--- a/runsc/boot/pprof/pprof.go
+++ b/runsc/boot/pprof/pprof.go
diff --git a/runsc/boot/pprof/pprof_state_autogen.go b/runsc/boot/pprof/pprof_state_autogen.go
index cabd43173..cabd43173 100755..100644
--- a/runsc/boot/pprof/pprof_state_autogen.go
+++ b/runsc/boot/pprof/pprof_state_autogen.go
diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go
index 147c901c4..147c901c4 100755..100644
--- a/runsc/boot/vfs.go
+++ b/runsc/boot/vfs.go
diff --git a/runsc/cgroup/cgroup.go b/runsc/cgroup/cgroup.go
index fa40ee509..19c8b0db6 100644
--- a/runsc/cgroup/cgroup.go
+++ b/runsc/cgroup/cgroup.go
@@ -19,6 +19,7 @@ package cgroup
import (
"bufio"
"context"
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -38,21 +39,23 @@ const (
cgroupRoot = "/sys/fs/cgroup"
)
-var controllers = map[string]controller{
- "blkio": &blockIO{},
- "cpu": &cpu{},
- "cpuset": &cpuSet{},
- "memory": &memory{},
- "net_cls": &networkClass{},
- "net_prio": &networkPrio{},
- "pids": &pids{},
+var controllers = map[string]config{
+ "blkio": config{ctrlr: &blockIO{}},
+ "cpu": config{ctrlr: &cpu{}},
+ "cpuset": config{ctrlr: &cpuSet{}},
+ "memory": config{ctrlr: &memory{}},
+ "net_cls": config{ctrlr: &networkClass{}},
+ "net_prio": config{ctrlr: &networkPrio{}},
+ "pids": config{ctrlr: &pids{}},
// These controllers either don't have anything in the OCI spec or is
// irrelevant for a sandbox.
- "devices": &noop{},
- "freezer": &noop{},
- "perf_event": &noop{},
- "systemd": &noop{},
+ "devices": config{ctrlr: &noop{}},
+ "freezer": config{ctrlr: &noop{}},
+ "hugetlb": config{ctrlr: &noop{}, optional: true},
+ "perf_event": config{ctrlr: &noop{}},
+ "rdma": config{ctrlr: &noop{}, optional: true},
+ "systemd": config{ctrlr: &noop{}},
}
func setOptionalValueInt(path, name string, val *int64) error {
@@ -196,8 +199,9 @@ func LoadPaths(pid string) (map[string]string, error) {
return paths, nil
}
-// Cgroup represents a group inside all controllers. For example: Name='/foo/bar'
-// maps to /sys/fs/cgroup/<controller>/foo/bar on all controllers.
+// Cgroup represents a group inside all controllers. For example:
+// Name='/foo/bar' maps to /sys/fs/cgroup/<controller>/foo/bar on
+// all controllers.
type Cgroup struct {
Name string `json:"name"`
Parents map[string]string `json:"parents"`
@@ -245,13 +249,17 @@ func (c *Cgroup) Install(res *specs.LinuxResources) error {
clean := specutils.MakeCleanup(func() { _ = c.Uninstall() })
defer clean.Clean()
- for key, ctrl := range controllers {
+ for key, cfg := range controllers {
path := c.makePath(key)
if err := os.MkdirAll(path, 0755); err != nil {
+ if cfg.optional && errors.Is(err, syscall.EROFS) {
+ log.Infof("Skipping cgroup %q", key)
+ continue
+ }
return err
}
if res != nil {
- if err := ctrl.set(res, path); err != nil {
+ if err := cfg.ctrlr.set(res, path); err != nil {
return err
}
}
@@ -321,10 +329,13 @@ func (c *Cgroup) Join() (func(), error) {
}
// Now join the cgroups.
- for key := range controllers {
+ for key, cfg := range controllers {
path := c.makePath(key)
log.Debugf("Joining cgroup %q", path)
if err := setValue(path, "cgroup.procs", "0"); err != nil {
+ if cfg.optional && os.IsNotExist(err) {
+ continue
+ }
return undo, err
}
}
@@ -375,6 +386,11 @@ func (c *Cgroup) makePath(controllerName string) string {
return filepath.Join(cgroupRoot, controllerName, path)
}
+type config struct {
+ ctrlr controller
+ optional bool
+}
+
type controller interface {
set(*specs.LinuxResources, string) error
}
diff --git a/runsc/cgroup/cgroup_state_autogen.go b/runsc/cgroup/cgroup_state_autogen.go
index 934ed169b..934ed169b 100755..100644
--- a/runsc/cgroup/cgroup_state_autogen.go
+++ b/runsc/cgroup/cgroup_state_autogen.go
diff --git a/runsc/cmd/cmd_state_autogen.go b/runsc/cmd/cmd_state_autogen.go
index de8aa267b..de8aa267b 100755..100644
--- a/runsc/cmd/cmd_state_autogen.go
+++ b/runsc/cmd/cmd_state_autogen.go
diff --git a/runsc/cmd/statefile.go b/runsc/cmd/statefile.go
index e6f1907da..e6f1907da 100755..100644
--- a/runsc/cmd/statefile.go
+++ b/runsc/cmd/statefile.go
diff --git a/runsc/console/console_state_autogen.go b/runsc/console/console_state_autogen.go
index 80521cdb7..80521cdb7 100755..100644
--- a/runsc/console/console_state_autogen.go
+++ b/runsc/console/console_state_autogen.go
diff --git a/runsc/container/container_state_autogen.go b/runsc/container/container_state_autogen.go
index 5bc1c1aff..5bc1c1aff 100755..100644
--- a/runsc/container/container_state_autogen.go
+++ b/runsc/container/container_state_autogen.go
diff --git a/runsc/container/state_file.go b/runsc/container/state_file.go
index 17a251530..17a251530 100755..100644
--- a/runsc/container/state_file.go
+++ b/runsc/container/state_file.go
diff --git a/runsc/flag/flag.go b/runsc/flag/flag.go
index 0ca4829d7..0ca4829d7 100755..100644
--- a/runsc/flag/flag.go
+++ b/runsc/flag/flag.go
diff --git a/runsc/flag/flag_state_autogen.go b/runsc/flag/flag_state_autogen.go
index 933063e6c..933063e6c 100755..100644
--- a/runsc/flag/flag_state_autogen.go
+++ b/runsc/flag/flag_state_autogen.go
diff --git a/runsc/fsgofer/filter/config_amd64.go b/runsc/fsgofer/filter/config_amd64.go
index a4b28cb8b..a4b28cb8b 100755..100644
--- a/runsc/fsgofer/filter/config_amd64.go
+++ b/runsc/fsgofer/filter/config_amd64.go
diff --git a/runsc/fsgofer/filter/config_arm64.go b/runsc/fsgofer/filter/config_arm64.go
index d2697deb7..d2697deb7 100755..100644
--- a/runsc/fsgofer/filter/config_arm64.go
+++ b/runsc/fsgofer/filter/config_arm64.go
diff --git a/runsc/fsgofer/filter/filter_amd64_state_autogen.go b/runsc/fsgofer/filter/filter_amd64_state_autogen.go
index 0f27e5568..0f27e5568 100755..100644
--- a/runsc/fsgofer/filter/filter_amd64_state_autogen.go
+++ b/runsc/fsgofer/filter/filter_amd64_state_autogen.go
diff --git a/runsc/fsgofer/filter/filter_arm64_state_autogen.go b/runsc/fsgofer/filter/filter_arm64_state_autogen.go
index e87cf5af7..e87cf5af7 100755..100644
--- a/runsc/fsgofer/filter/filter_arm64_state_autogen.go
+++ b/runsc/fsgofer/filter/filter_arm64_state_autogen.go
diff --git a/runsc/fsgofer/filter/filter_race_state_autogen.go b/runsc/fsgofer/filter/filter_race_state_autogen.go
index c4a858e80..c4a858e80 100755..100644
--- a/runsc/fsgofer/filter/filter_race_state_autogen.go
+++ b/runsc/fsgofer/filter/filter_race_state_autogen.go
diff --git a/runsc/fsgofer/filter/filter_state_autogen.go b/runsc/fsgofer/filter/filter_state_autogen.go
index 41ff99424..41ff99424 100755..100644
--- a/runsc/fsgofer/filter/filter_state_autogen.go
+++ b/runsc/fsgofer/filter/filter_state_autogen.go
diff --git a/runsc/fsgofer/fsgofer_amd64_unsafe.go b/runsc/fsgofer/fsgofer_amd64_unsafe.go
index 5d4aab597..5d4aab597 100755..100644
--- a/runsc/fsgofer/fsgofer_amd64_unsafe.go
+++ b/runsc/fsgofer/fsgofer_amd64_unsafe.go
diff --git a/runsc/fsgofer/fsgofer_amd64_unsafe_state_autogen.go b/runsc/fsgofer/fsgofer_amd64_unsafe_state_autogen.go
index df6721aaa..df6721aaa 100755..100644
--- a/runsc/fsgofer/fsgofer_amd64_unsafe_state_autogen.go
+++ b/runsc/fsgofer/fsgofer_amd64_unsafe_state_autogen.go
diff --git a/runsc/fsgofer/fsgofer_arm64_unsafe.go b/runsc/fsgofer/fsgofer_arm64_unsafe.go
index 8041fd352..8041fd352 100755..100644
--- a/runsc/fsgofer/fsgofer_arm64_unsafe.go
+++ b/runsc/fsgofer/fsgofer_arm64_unsafe.go
diff --git a/runsc/fsgofer/fsgofer_arm64_unsafe_state_autogen.go b/runsc/fsgofer/fsgofer_arm64_unsafe_state_autogen.go
index d2a18c61c..d2a18c61c 100755..100644
--- a/runsc/fsgofer/fsgofer_arm64_unsafe_state_autogen.go
+++ b/runsc/fsgofer/fsgofer_arm64_unsafe_state_autogen.go
diff --git a/runsc/fsgofer/fsgofer_state_autogen.go b/runsc/fsgofer/fsgofer_state_autogen.go
index d2f978fb9..d2f978fb9 100755..100644
--- a/runsc/fsgofer/fsgofer_state_autogen.go
+++ b/runsc/fsgofer/fsgofer_state_autogen.go
diff --git a/runsc/fsgofer/fsgofer_unsafe_state_autogen.go b/runsc/fsgofer/fsgofer_unsafe_state_autogen.go
index d2f978fb9..d2f978fb9 100755..100644
--- a/runsc/fsgofer/fsgofer_unsafe_state_autogen.go
+++ b/runsc/fsgofer/fsgofer_unsafe_state_autogen.go
diff --git a/runsc/sandbox/sandbox_state_autogen.go b/runsc/sandbox/sandbox_state_autogen.go
index 79ebc2220..79ebc2220 100755..100644
--- a/runsc/sandbox/sandbox_state_autogen.go
+++ b/runsc/sandbox/sandbox_state_autogen.go
diff --git a/runsc/sandbox/sandbox_unsafe_state_autogen.go b/runsc/sandbox/sandbox_unsafe_state_autogen.go
index 79ebc2220..79ebc2220 100755..100644
--- a/runsc/sandbox/sandbox_unsafe_state_autogen.go
+++ b/runsc/sandbox/sandbox_unsafe_state_autogen.go
diff --git a/runsc/specutils/cri.go b/runsc/specutils/cri.go
index 9c5877cd5..9c5877cd5 100755..100644
--- a/runsc/specutils/cri.go
+++ b/runsc/specutils/cri.go
diff --git a/runsc/specutils/specutils_state_autogen.go b/runsc/specutils/specutils_state_autogen.go
index 11eefbaa2..11eefbaa2 100755..100644
--- a/runsc/specutils/specutils_state_autogen.go
+++ b/runsc/specutils/specutils_state_autogen.go
diff --git a/tools/go_marshal/marshal/marshal.go b/tools/go_marshal/marshal/marshal.go
index cb2166252..cb2166252 100755..100644
--- a/tools/go_marshal/marshal/marshal.go
+++ b/tools/go_marshal/marshal/marshal.go
diff --git a/tools/go_marshal/marshal/marshal_state_autogen.go b/tools/go_marshal/marshal/marshal_state_autogen.go
index a0a953158..a0a953158 100755..100644
--- a/tools/go_marshal/marshal/marshal_state_autogen.go
+++ b/tools/go_marshal/marshal/marshal_state_autogen.go