From af543328ea3efb4d2a39f577ae3a6991babff87d Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Sun, 18 Jul 2021 09:18:35 -0700 Subject: [PATCH] Kernel: Instrument syscalls with their process big lock requirements Currently all syscalls run under the Process:m_big_lock, which is an obvious bottleneck. Long term we would like to remove the big lock and replace it with the required fine grained locking. To facilitate this goal we need a way of gradually decomposing the big lock into the all of the required fine grained locks. This commit introduces instrumentation to the syscall table, allowing the big lock requirement to be toggled on/off per syscall. Eventually when we are finished, no syscall will required the big lock, and we'll be able to remove all of this instrumentation. --- Kernel/API/Syscall.h | 321 ++++++++++++++++++++++--------------------- Kernel/Process.h | 6 + Kernel/Syscall.cpp | 15 +- 3 files changed, 179 insertions(+), 163 deletions(-) diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 88854ef726..1357b9fc54 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -28,165 +28,170 @@ typedef u32 socklen_t; namespace Kernel { -#define ENUMERATE_SYSCALLS(S) \ - S(yield) \ - S(open) \ - S(close) \ - S(read) \ - S(lseek) \ - S(kill) \ - S(getuid) \ - S(exit) \ - S(geteuid) \ - S(getegid) \ - S(getgid) \ - S(getpid) \ - S(getppid) \ - S(getresuid) \ - S(getresgid) \ - S(waitid) \ - S(mmap) \ - S(munmap) \ - S(get_dir_entries) \ - S(getcwd) \ - S(gettimeofday) \ - S(gethostname) \ - S(sethostname) \ - S(chdir) \ - S(uname) \ - S(set_mmap_name) \ - S(readlink) \ - S(write) \ - S(ttyname) \ - S(stat) \ - S(getsid) \ - S(setsid) \ - S(getpgid) \ - S(setpgid) \ - S(getpgrp) \ - S(fork) \ - S(execve) \ - S(dup2) \ - S(sigaction) \ - S(umask) \ - S(getgroups) \ - S(setgroups) \ - S(sigreturn) \ - S(sigprocmask) \ - S(sigpending) \ - S(pipe) \ - S(killpg) \ - S(seteuid) \ - S(setegid) \ - S(setuid) \ - S(setgid) \ - S(setreuid) \ - S(setresuid) \ - S(setresgid) \ - S(alarm) \ - S(fstat) \ - S(access) \ - S(fcntl) \ - S(ioctl) \ - S(mkdir) \ - S(times) \ - S(utime) \ - S(sync) \ - S(ptsname) \ - S(select) \ - S(unlink) \ - S(poll) \ - S(rmdir) \ - S(chmod) \ - S(socket) \ - S(bind) \ - S(accept4) \ - S(listen) \ - S(connect) \ - S(link) \ - S(chown) \ - S(fchmod) \ - S(symlink) \ - S(sendmsg) \ - S(recvmsg) \ - S(getsockopt) \ - S(setsockopt) \ - S(create_thread) \ - S(gettid) \ - S(rename) \ - S(ftruncate) \ - S(exit_thread) \ - S(mknod) \ - S(writev) \ - S(beep) \ - S(getsockname) \ - S(getpeername) \ - S(socketpair) \ - S(sched_setparam) \ - S(sched_getparam) \ - S(fchown) \ - S(halt) \ - S(reboot) \ - S(mount) \ - S(umount) \ - S(dump_backtrace) \ - S(dbgputch) \ - S(dbgputstr) \ - S(create_inode_watcher) \ - S(inode_watcher_add_watch) \ - S(inode_watcher_remove_watch) \ - S(mprotect) \ - S(realpath) \ - S(get_process_name) \ - S(fchdir) \ - S(getrandom) \ - S(getkeymap) \ - S(setkeymap) \ - S(clock_gettime) \ - S(clock_settime) \ - S(clock_nanosleep) \ - S(join_thread) \ - S(module_load) \ - S(module_unload) \ - S(detach_thread) \ - S(set_thread_name) \ - S(get_thread_name) \ - S(madvise) \ - S(purge) \ - S(profiling_enable) \ - S(profiling_disable) \ - S(profiling_free_buffer) \ - S(futex) \ - S(chroot) \ - S(pledge) \ - S(unveil) \ - S(perf_event) \ - S(shutdown) \ - S(get_stack_bounds) \ - S(ptrace) \ - S(sendfd) \ - S(recvfd) \ - S(sysconf) \ - S(set_process_name) \ - S(disown) \ - S(adjtime) \ - S(allocate_tls) \ - S(prctl) \ - S(mremap) \ - S(set_coredump_metadata) \ - S(anon_create) \ - S(msyscall) \ - S(readv) \ - S(emuctl) \ - S(statvfs) \ - S(fstatvfs) \ - S(kill_thread) +enum class NeedsBigProcessLock { + Yes, + No +}; + +#define ENUMERATE_SYSCALLS(S) \ + S(yield, NeedsBigProcessLock::Yes) \ + S(open, NeedsBigProcessLock::Yes) \ + S(close, NeedsBigProcessLock::Yes) \ + S(read, NeedsBigProcessLock::Yes) \ + S(lseek, NeedsBigProcessLock::Yes) \ + S(kill, NeedsBigProcessLock::Yes) \ + S(getuid, NeedsBigProcessLock::Yes) \ + S(exit, NeedsBigProcessLock::Yes) \ + S(geteuid, NeedsBigProcessLock::Yes) \ + S(getegid, NeedsBigProcessLock::Yes) \ + S(getgid, NeedsBigProcessLock::Yes) \ + S(getpid, NeedsBigProcessLock::Yes) \ + S(getppid, NeedsBigProcessLock::Yes) \ + S(getresuid, NeedsBigProcessLock::Yes) \ + S(getresgid, NeedsBigProcessLock::Yes) \ + S(waitid, NeedsBigProcessLock::Yes) \ + S(mmap, NeedsBigProcessLock::Yes) \ + S(munmap, NeedsBigProcessLock::Yes) \ + S(get_dir_entries, NeedsBigProcessLock::Yes) \ + S(getcwd, NeedsBigProcessLock::Yes) \ + S(gettimeofday, NeedsBigProcessLock::Yes) \ + S(gethostname, NeedsBigProcessLock::Yes) \ + S(sethostname, NeedsBigProcessLock::Yes) \ + S(chdir, NeedsBigProcessLock::Yes) \ + S(uname, NeedsBigProcessLock::Yes) \ + S(set_mmap_name, NeedsBigProcessLock::Yes) \ + S(readlink, NeedsBigProcessLock::Yes) \ + S(write, NeedsBigProcessLock::Yes) \ + S(ttyname, NeedsBigProcessLock::Yes) \ + S(stat, NeedsBigProcessLock::Yes) \ + S(getsid, NeedsBigProcessLock::Yes) \ + S(setsid, NeedsBigProcessLock::Yes) \ + S(getpgid, NeedsBigProcessLock::Yes) \ + S(setpgid, NeedsBigProcessLock::Yes) \ + S(getpgrp, NeedsBigProcessLock::Yes) \ + S(fork, NeedsBigProcessLock::Yes) \ + S(execve, NeedsBigProcessLock::Yes) \ + S(dup2, NeedsBigProcessLock::Yes) \ + S(sigaction, NeedsBigProcessLock::Yes) \ + S(umask, NeedsBigProcessLock::Yes) \ + S(getgroups, NeedsBigProcessLock::Yes) \ + S(setgroups, NeedsBigProcessLock::Yes) \ + S(sigreturn, NeedsBigProcessLock::Yes) \ + S(sigprocmask, NeedsBigProcessLock::Yes) \ + S(sigpending, NeedsBigProcessLock::Yes) \ + S(pipe, NeedsBigProcessLock::Yes) \ + S(killpg, NeedsBigProcessLock::Yes) \ + S(seteuid, NeedsBigProcessLock::Yes) \ + S(setegid, NeedsBigProcessLock::Yes) \ + S(setuid, NeedsBigProcessLock::Yes) \ + S(setgid, NeedsBigProcessLock::Yes) \ + S(setreuid, NeedsBigProcessLock::Yes) \ + S(setresuid, NeedsBigProcessLock::Yes) \ + S(setresgid, NeedsBigProcessLock::Yes) \ + S(alarm, NeedsBigProcessLock::Yes) \ + S(fstat, NeedsBigProcessLock::Yes) \ + S(access, NeedsBigProcessLock::Yes) \ + S(fcntl, NeedsBigProcessLock::Yes) \ + S(ioctl, NeedsBigProcessLock::Yes) \ + S(mkdir, NeedsBigProcessLock::Yes) \ + S(times, NeedsBigProcessLock::Yes) \ + S(utime, NeedsBigProcessLock::Yes) \ + S(sync, NeedsBigProcessLock::Yes) \ + S(ptsname, NeedsBigProcessLock::Yes) \ + S(select, NeedsBigProcessLock::Yes) \ + S(unlink, NeedsBigProcessLock::Yes) \ + S(poll, NeedsBigProcessLock::Yes) \ + S(rmdir, NeedsBigProcessLock::Yes) \ + S(chmod, NeedsBigProcessLock::Yes) \ + S(socket, NeedsBigProcessLock::Yes) \ + S(bind, NeedsBigProcessLock::Yes) \ + S(accept4, NeedsBigProcessLock::Yes) \ + S(listen, NeedsBigProcessLock::Yes) \ + S(connect, NeedsBigProcessLock::Yes) \ + S(link, NeedsBigProcessLock::Yes) \ + S(chown, NeedsBigProcessLock::Yes) \ + S(fchmod, NeedsBigProcessLock::Yes) \ + S(symlink, NeedsBigProcessLock::Yes) \ + S(sendmsg, NeedsBigProcessLock::Yes) \ + S(recvmsg, NeedsBigProcessLock::Yes) \ + S(getsockopt, NeedsBigProcessLock::Yes) \ + S(setsockopt, NeedsBigProcessLock::Yes) \ + S(create_thread, NeedsBigProcessLock::Yes) \ + S(gettid, NeedsBigProcessLock::Yes) \ + S(rename, NeedsBigProcessLock::Yes) \ + S(ftruncate, NeedsBigProcessLock::Yes) \ + S(exit_thread, NeedsBigProcessLock::Yes) \ + S(mknod, NeedsBigProcessLock::Yes) \ + S(writev, NeedsBigProcessLock::Yes) \ + S(beep, NeedsBigProcessLock::Yes) \ + S(getsockname, NeedsBigProcessLock::Yes) \ + S(getpeername, NeedsBigProcessLock::Yes) \ + S(socketpair, NeedsBigProcessLock::Yes) \ + S(sched_setparam, NeedsBigProcessLock::Yes) \ + S(sched_getparam, NeedsBigProcessLock::Yes) \ + S(fchown, NeedsBigProcessLock::Yes) \ + S(halt, NeedsBigProcessLock::Yes) \ + S(reboot, NeedsBigProcessLock::Yes) \ + S(mount, NeedsBigProcessLock::Yes) \ + S(umount, NeedsBigProcessLock::Yes) \ + S(dump_backtrace, NeedsBigProcessLock::Yes) \ + S(dbgputch, NeedsBigProcessLock::Yes) \ + S(dbgputstr, NeedsBigProcessLock::Yes) \ + S(create_inode_watcher, NeedsBigProcessLock::Yes) \ + S(inode_watcher_add_watch, NeedsBigProcessLock::Yes) \ + S(inode_watcher_remove_watch, NeedsBigProcessLock::Yes) \ + S(mprotect, NeedsBigProcessLock::Yes) \ + S(realpath, NeedsBigProcessLock::Yes) \ + S(get_process_name, NeedsBigProcessLock::Yes) \ + S(fchdir, NeedsBigProcessLock::Yes) \ + S(getrandom, NeedsBigProcessLock::Yes) \ + S(getkeymap, NeedsBigProcessLock::Yes) \ + S(setkeymap, NeedsBigProcessLock::Yes) \ + S(clock_gettime, NeedsBigProcessLock::Yes) \ + S(clock_settime, NeedsBigProcessLock::Yes) \ + S(clock_nanosleep, NeedsBigProcessLock::Yes) \ + S(join_thread, NeedsBigProcessLock::Yes) \ + S(module_load, NeedsBigProcessLock::Yes) \ + S(module_unload, NeedsBigProcessLock::Yes) \ + S(detach_thread, NeedsBigProcessLock::Yes) \ + S(set_thread_name, NeedsBigProcessLock::Yes) \ + S(get_thread_name, NeedsBigProcessLock::Yes) \ + S(madvise, NeedsBigProcessLock::Yes) \ + S(purge, NeedsBigProcessLock::Yes) \ + S(profiling_enable, NeedsBigProcessLock::Yes) \ + S(profiling_disable, NeedsBigProcessLock::Yes) \ + S(profiling_free_buffer, NeedsBigProcessLock::Yes) \ + S(futex, NeedsBigProcessLock::Yes) \ + S(chroot, NeedsBigProcessLock::Yes) \ + S(pledge, NeedsBigProcessLock::Yes) \ + S(unveil, NeedsBigProcessLock::Yes) \ + S(perf_event, NeedsBigProcessLock::Yes) \ + S(shutdown, NeedsBigProcessLock::Yes) \ + S(get_stack_bounds, NeedsBigProcessLock::Yes) \ + S(ptrace, NeedsBigProcessLock::Yes) \ + S(sendfd, NeedsBigProcessLock::Yes) \ + S(recvfd, NeedsBigProcessLock::Yes) \ + S(sysconf, NeedsBigProcessLock::Yes) \ + S(set_process_name, NeedsBigProcessLock::Yes) \ + S(disown, NeedsBigProcessLock::Yes) \ + S(adjtime, NeedsBigProcessLock::Yes) \ + S(allocate_tls, NeedsBigProcessLock::Yes) \ + S(prctl, NeedsBigProcessLock::Yes) \ + S(mremap, NeedsBigProcessLock::Yes) \ + S(set_coredump_metadata, NeedsBigProcessLock::Yes) \ + S(anon_create, NeedsBigProcessLock::Yes) \ + S(msyscall, NeedsBigProcessLock::Yes) \ + S(readv, NeedsBigProcessLock::Yes) \ + S(emuctl, NeedsBigProcessLock::Yes) \ + S(statvfs, NeedsBigProcessLock::Yes) \ + S(fstatvfs, NeedsBigProcessLock::Yes) \ + S(kill_thread, NeedsBigProcessLock::Yes) namespace Syscall { enum Function { #undef __ENUMERATE_SYSCALL -#define __ENUMERATE_SYSCALL(x) SC_##x, +#define __ENUMERATE_SYSCALL(sys_call, needs_lock) SC_##sys_call, ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL) #undef __ENUMERATE_SYSCALL __Count @@ -196,9 +201,9 @@ constexpr const char* to_string(Function function) { switch (function) { #undef __ENUMERATE_SYSCALL -#define __ENUMERATE_SYSCALL(x) \ - case SC_##x: \ - return #x; +#define __ENUMERATE_SYSCALL(sys_call, needs_lock) \ + case SC_##sys_call: \ + return #sys_call; ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL) #undef __ENUMERATE_SYSCALL default: @@ -522,7 +527,7 @@ inline uintptr_t invoke(Function function, T1 arg1, T2 arg2, T3 arg3) } #undef __ENUMERATE_SYSCALL -#define __ENUMERATE_SYSCALL(x) using Syscall::SC_##x; +#define __ENUMERATE_SYSCALL(sys_call, needs_lock) using Syscall::SC_##sys_call; ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL) #undef __ENUMERATE_SYSCALL diff --git a/Kernel/Process.h b/Kernel/Process.h index dc2bd5aab0..662c46a8c5 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -882,6 +882,12 @@ inline ProcessID Thread::pid() const } while (0) } +#define VERIFY_PROCESS_BIG_LOCK_ACQUIRED(process) \ + VERIFY(process->big_lock().own_lock()); + +#define VERIFY_NO_PROCESS_BIG_LOCK(process) \ + VERIFY(!process->big_lock().own_lock()); + inline static String copy_string_from_user(const Kernel::Syscall::StringArgument& string) { return copy_string_from_user(string.characters, string.length); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 0374823953..4f37b67383 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -90,8 +90,13 @@ UNMAP_AFTER_INIT void initialize() #pragma GCC diagnostic ignored "-Wcast-function-type" typedef KResultOr (Process::*Handler)(FlatPtr, FlatPtr, FlatPtr); typedef KResultOr (Process::*HandlerWithRegisterState)(RegisterState&); -#define __ENUMERATE_SYSCALL(x) reinterpret_cast(&Process::sys$##x), -static const Handler s_syscall_table[] = { +struct HandlerMetadata { + Handler handler; + NeedsBigProcessLock needs_lock; +}; + +#define __ENUMERATE_SYSCALL(sys_call, needs_lock) { reinterpret_cast(&Process::sys$##sys_call), needs_lock }, +static const HandlerMetadata s_syscall_table[] = { ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL) }; #undef __ENUMERATE_SYSCALL @@ -126,7 +131,7 @@ KResultOr handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, F if (function == SC_fork || function == SC_sigreturn) { // These syscalls want the RegisterState& rather than individual parameters. - auto handler = (HandlerWithRegisterState)s_syscall_table[function]; + auto handler = (HandlerWithRegisterState)s_syscall_table[function].handler; return (process.*(handler))(regs); } @@ -135,12 +140,12 @@ KResultOr handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, F return ENOSYS; } - if (s_syscall_table[function] == nullptr) { + if (s_syscall_table[function].handler == nullptr) { dbgln("Null syscall {} requested, you probably need to rebuild this program!", function); return ENOSYS; } - return (process.*(s_syscall_table[function]))(arg1, arg2, arg3); + return (process.*(s_syscall_table[function].handler))(arg1, arg2, arg3); } }