SchOS/kernel/sys/table.inc
Nexoniarz 03cc316001 schfs: the commit barrier, reflink, and attributes with an index over them
The last three phases of the filesystem, which were written together and
touch the same files throughout -- kmount.c, objw.c and vfs.c are each
rewritten by all three -- so they land as one commit rather than three
that could not be built separately.

Durability. A transaction that reaches the platter out of order is worse
than one that never reached it: the uberblock can name a tree whose
blocks are still in the drive's write cache. bdirty/bflush give the
buffer layer an explicit barrier, ideflush issues ATA FLUSH CACHE and
usb_storage_flush the SCSI SYNCHRONIZE CACHE that means the same thing,
and a commit now waits for the data before it writes the root that
points at it. The uberblock groups are read newest-first with fallback,
so a volume whose newest roots are torn mounts at an older one and says
which generations were lost.

Reflink. Extents carry a refcount, so two objects can name the same
blocks and neither frees them while the other holds them. Exposed as
FICLONE -- Linux's ioctl value, so `cp --reflink` works unmodified --
and as cmd/reflink for the case where there is no cp to hand.

Attributes, and the one genuinely new idea here. attr.c stores named
values on an object, reachable through setxattr/getxattr/removexattr at
Linux's syscall numbers. On top of that, schfs_index declares an index
over an attribute name and schfs_query answers "which objects carry this
value" from the B-tree rather than by walking. A query against an
unindexed attribute is refused with an error, never silently answered by
a full scan: a query that quietly becomes a scan is worse than one that
admits it cannot help. cmd/schattr drives both.

Three bugs fixed on the way, each found by the numbers being wrong
rather than by inspection:

  - statfs's f_fsid was declared int64[2]. Linux's fsid_t is two *ints*,
    so every field after it landed one slot late: userland read f_frsize
    out of f_namelen, got 255, and df reported a 32 MB root filesystem
    as 1992 KB. It hid for as long as it did because the fields used to
    be invented constants, so wrong numbers looked like the usual ones.
  - struct inode's nlink was a short against SchFS's uint32, so a file
    past 32767 names came back negative -- and iput frees an object
    whose count reaches zero. It is an int now, signed on purpose, so an
    underflow lands somewhere a check can see rather than wrapping.
  - filewrite split every write to fit v1's log. That limit belongs to
    the journal, not to writing, and SchFS makes one transaction of
    whatever it is handed: a 1 MB write was becoming 170 commits and
    170 flushes for nothing. fs_ops carries max_write now, and SchFS
    sets no limit.

Also here: a real mount table, so `mount -t schfs /dev/hdb /mnt` shows
up in /proc/mounts -- df looks a path up there before it calls statfs at
all, so a mount missing from that list was invisible to it -- several
volumes mounted at once, snapshots mounted by name, and /proc/fsstat
with an rdtsc-based counter, which is the only instrument fine enough to
see inside a single syscall.

Verified: `make schfs-check` passes in full, including the sweep that
crashes the volume at each of 119 points mid-transaction and requires
every one to mount with exactly its committed data, and the case where
both newest uberblocks are rubbish and the volume still comes back. The
headless boot check passes with 27 [ok] and no failures, on a SchFS root.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 16:02:02 +02:00

293 lines
10 KiB
SQL

// Segregated Kernel -- central syscall table. ONE line per syscall.
//
// Format: SYSCALL(nr, linux_nr, name)
// nr SchOS native syscall number
// linux_nr Linux x86_64 syscall number, or NO_LINUX if none
// name implemented as sys_<name>() in kernel/sys/sys_*.c
//
// To add a syscall:
// 1. Add ONE line here.
// 2. Write the body with SYSCALL_DEFINE(<name>) in a kernel/sys/sys_*.c.
//
// Everything else is generated from this file: the SYS_* constants
// (include/syscall.h), the dispatch table (kernel/sys/syscall.c), and the
// Linux ABI translation map (kernel/sys/linux_abi.c). The Linux number used
// to live in a second hand-maintained table in linux_abi.c; it does not any
// more, so a syscall can no longer be half-registered.
//
// A syscall reachable under more than one Linux number (e.g. stat/newstat)
// gets extra SYSCALL_ALIAS(linux_nr, name) lines.
// --- process ---
SYSCALL( 1, 57, fork)
SYSCALL( 2, 60, exit)
SYSCALL( 3, NO_LINUX, wait)
SYSCALL( 6, 62, kill)
SYSCALL( 7, 59, exec)
SYSCALL( 11, 39, getpid)
SYSCALL( 13, NO_LINUX, sleep)
SYSCALL( 14, NO_LINUX, uptime)
SYSCALL( 29, NO_LINUX, waitpid)
SYSCALL( 30, 112, setsid)
SYSCALL( 31, NO_LINUX, reboot)
SYSCALL( 32, NO_LINUX, shutdown)
SYSCALL( 66, 56, clone)
SYSCALL( 67, 231, exit_group)
SYSCALL( 68, 61, wait4)
SYSCALL( 83, 105, setuid)
SYSCALL( 84, 106, setgid)
SYSCALL( 85, 124, getsid)
SYSCALL( 89, 110, getppid)
SYSCALL( 91, 121, getpgid)
SYSCALL( 94, 186, gettid)
SYSCALL( 92, 109, setpgid)
SYSCALL( 93, 111, getpgrp)
// --- identity ---
SYSCALL( 47, 102, getuid)
SYSCALL( 48, 107, geteuid)
SYSCALL( 69, 104, getgid)
SYSCALL( 70, 108, getegid)
SYSCALL( 71, 95, umask)
// --- memory ---
SYSCALL( 12, NO_LINUX, sbrk)
SYSCALL( 35, 9, mmap)
SYSCALL( 36, 11, munmap)
// Shared memory. These carried NO_LINUX while they were ENOSYS stubs, which
// meant a musl-linked program calling shmget() never reached them at all --
// it got "bad syscall" from the ABI translation rather than an answer. Now
// that they do something, they need the numbers programs actually use.
SYSCALL( 37, 29, shmget)
SYSCALL( 38, 30, shmat)
SYSCALL( 39, 67, shmdt)
SYSCALL( 59, 10, mprotect)
SYSCALL( 74, 12, brk)
// --- filesystem ---
SYSCALL( 4, 22, pipe)
SYSCALL( 5, 0, read)
SYSCALL( 8, 5, fstat)
SYSCALL( 9, 80, chdir)
SYSCALL( 10, 32, dup)
SYSCALL( 15, 2, open)
SYSCALL( 16, 1, write)
SYSCALL( 17, 133, mknod)
SYSCALL( 18, 87, unlink)
SYSCALL( 19, 86, link)
SYSCALL( 20, 83, mkdir)
SYSCALL( 21, 3, close)
SYSCALL( 24, 8, lseek)
SYSCALL( 33, 33, dup2)
SYSCALL( 34, 72, fcntl)
// `delete` -- the recycle bin. It hides a file instead of removing it, so the
// blocks are never freed and a program that deletes a temp file gets no space
// back. Inherited from the third-party filesystem in kernel/fs/fs.c and
// orphaned by the decision to keep only Linux syscall numbering, so nothing
// reaches it. Its effect on read and write has been removed; the entry stays
// only because sys_delete() is still compiled, and both die with fs.c.
SYSCALL( 51, NO_LINUX, delete)
SYSCALL( 52, NO_LINUX, show)
SYSCALL( 53, NO_LINUX, showstat)
SYSCALL( 54, 77, ftruncate)
SYSCALL( 55, 76, truncate)
SYSCALL( 56, 82, rename)
SYSCALL( 57, 88, symlink)
SYSCALL( 58, 89, readlink)
SYSCALL( 61, 79, getcwd)
SYSCALL( 73, 19, readv)
SYSCALL( 72, 20, writev)
SYSCALL( 76, 4, stat)
SYSCALL( 77, 6, lstat)
SYSCALL( 78, 21, access)
SYSCALL( 79, 257, openat)
SYSCALL( 80, 81, fchdir)
SYSCALL( 86, 292, dup3)
SYSCALL( 87, 293, pipe2)
// --- device / I/O ---
SYSCALL( 22, NO_LINUX, vga_sync)
SYSCALL( 23, NO_LINUX, getmouse)
SYSCALL( 45, 23, select)
SYSCALL( 46, 7, poll)
SYSCALL( 60, 16, ioctl)
// --- sockets ---
//
// These carried NO_LINUX while they were ENOSYS stubs, which meant a
// musl-linked program calling socket() never reached them at all -- the ABI
// translation answered "bad syscall" before the stub could answer ENOSYS.
// Now that they do something they need the numbers programs actually use.
//
// `shutdown` is deliberately not the name here: SchOS already has a native
// shutdown() that powers the machine off (syscall 32), and two syscalls
// cannot share a sys_ function name. Linux 48 maps to sockshutdown instead.
SYSCALL( 40, 41, socket)
SYSCALL( 41, 49, bind)
SYSCALL( 42, 50, listen)
SYSCALL( 43, 43, accept)
SYSCALL( 44, 42, connect)
SYSCALL(187, 44, sendto)
SYSCALL(188, 45, recvfrom)
SYSCALL(189, 48, sockshutdown)
SYSCALL(190, 53, socketpair)
SYSCALL(191, 54, setsockopt)
SYSCALL(192, 55, getsockopt)
// --- time ---
SYSCALL( 28, 37, alarm)
SYSCALL( 49, 96, gettimeofday)
SYSCALL( 50, 35, nanosleep)
SYSCALL( 88, 228, clock_gettime)
// --- signals ---
SYSCALL( 25, NO_LINUX, sigfillset)
SYSCALL( 26, 14, sigprocmask)
SYSCALL( 27, NO_LINUX, sigwait)
SYSCALL( 90, 13, rt_sigaction)
// --- POSIX / Linux-ABI compat ---
SYSCALL( 62, 158, arch_prctl)
SYSCALL( 95, 63, uname)
SYSCALL( 96, 217, getdents64)
SYSCALL( 63, 218, set_tid_address)
SYSCALL( 64, 273, set_robust_list)
SYSCALL( 65, 202, futex)
SYSCALL( 75, 302, prlimit)
SYSCALL( 81, NO_LINUX, enable_linux_abi)
SYSCALL( 82, 97, getrlimit)
// --- signal extensions ---
SYSCALL( 97, 15, rt_sigreturn)
SYSCALL( 98, 131, sigaltstack)
SYSCALL( 99, 127, rt_sigpending)
SYSCALL(100, 128, rt_sigtimedwait)
SYSCALL(101, 130, rt_sigsuspend)
// --- process extensions ---
SYSCALL(102, 157, prctl)
SYSCALL(103, 234, tgkill)
SYSCALL(104, 200, tkill)
SYSCALL(105, 34, pause)
SYSCALL(106, NO_LINUX, getitimer)
SYSCALL(107, NO_LINUX, setitimer)
SYSCALL(108, 98, getrusage)
SYSCALL(109, 100, times)
SYSCALL(110, 99, sysinfo)
SYSCALL(111, 24, sched_yield)
SYSCALL(112, 204, sched_getaffinity)
SYSCALL(113, 203, sched_setaffinity)
SYSCALL(114, 247, waitid)
// --- identity extensions ---
SYSCALL(115, 113, setreuid)
SYSCALL(116, 114, setregid)
SYSCALL(117, 118, getresuid)
SYSCALL(118, 120, getresgid)
SYSCALL(119, 117, setresuid)
SYSCALL(120, 119, setresgid)
SYSCALL(121, 115, getgroups)
SYSCALL(122, 116, setgroups)
SYSCALL(123, 122, setfsuid)
SYSCALL(124, 123, setfsgid)
// --- filesystem extensions ---
SYSCALL(125, 90, chmod)
SYSCALL(126, 91, fchmod)
SYSCALL(127, 92, chown)
SYSCALL(128, 93, fchown)
SYSCALL(129, 94, lchown)
SYSCALL(130, 84, rmdir)
SYSCALL(131, NO_LINUX, fsync)
SYSCALL(132, NO_LINUX, fdatasync)
SYSCALL(133, 162, sync)
SYSCALL(134, 17, pread)
SYSCALL(135, 18, pwrite)
SYSCALL(148, 132, utime)
SYSCALL(149, 235, utimes)
SYSCALL(150, 261, utimensat)
SYSCALL(151, 187, sendfile)
SYSCALL(152, NO_LINUX, preadv2)
SYSCALL(153, NO_LINUX, pwritev2)
SYSCALL(154, 285, fallocate)
SYSCALL(155, 137, statfs)
SYSCALL(156, 138, fstatfs)
SYSCALL(157, 161, chroot)
// --- attributes, and the index over them (SchFS phase 5) ---
//
// Linux's numbers for the xattr calls, so a program that already knows how to
// set an extended attribute needs no changes. schfs_query has no Linux
// equivalent -- it is the one genuinely new call -- so it is native-only.
SYSCALL(193, 188, setxattr)
SYSCALL(194, 191, getxattr)
SYSCALL(195, 197, removexattr)
SYSCALL(196, NO_LINUX, schfs_index)
SYSCALL(197, NO_LINUX, schfs_query)
// --- memory extensions ---
SYSCALL(136, 28, madvise)
SYSCALL(137, NO_LINUX, mremap)
SYSCALL(138, NO_LINUX, msync)
SYSCALL(139, NO_LINUX, mincore)
SYSCALL(140, 149, mlock)
SYSCALL(141, 150, munlock)
SYSCALL(142, 151, mlockall)
SYSCALL(143, 152, munlockall)
SYSCALL(144, 221, fadvise64)
SYSCALL(145, 160, setrlimit)
SYSCALL(146, NO_LINUX, getpriority)
SYSCALL(147, NO_LINUX, setpriority)
// --- at-syscalls ---
SYSCALL(158, 258, mkdirat)
SYSCALL(159, 259, mknodat)
SYSCALL(160, 263, unlinkat)
SYSCALL(161, 264, renameat)
SYSCALL(162, 265, linkat)
SYSCALL(163, 266, symlinkat)
SYSCALL(164, 267, readlinkat)
SYSCALL(165, 268, fchmodat)
SYSCALL(166, 269, faccessat)
SYSCALL(167, 262, fstatat)
SYSCALL(168, 260, fchownat)
SYSCALL(169, 316, renameat2)
// --- time extensions ---
SYSCALL(170, 201, time)
SYSCALL(171, 229, clock_getres)
SYSCALL(172, 230, clock_nanosleep)
// --- misc ---
SYSCALL(173, 103, syslog)
SYSCALL(174, 318, getrandom)
SYSCALL(175, 270, pselect6)
SYSCALL(176, 271, ppoll)
// --- epoll / eventfd / signalfd / timerfd ---
SYSCALL(177, 291, epoll_create1)
SYSCALL(178, 233, epoll_ctl)
SYSCALL(179, 232, epoll_wait)
SYSCALL(180, 282, signalfd4)
SYSCALL(181, 284, eventfd2)
SYSCALL(182, 283, timerfd_create)
SYSCALL(183, 286, timerfd_settime)
SYSCALL(184, 287, timerfd_gettime)
// --- mounts ---
SYSCALL(185, 165, mount)
SYSCALL(186, 166, umount2)
// --- additional Linux numbers routed to an existing handler ---
SYSCALL_ALIAS( 58, fork)
SYSCALL_ALIAS( 280, utimensat)
SYSCALL_ALIAS( 281, epoll_wait)
SYSCALL_ALIAS( 289, signalfd4)
SYSCALL_ALIAS( 290, eventfd2)
SYSCALL_ALIAS( 295, readv)
SYSCALL_ALIAS( 296, writev)
// accept4() differs from accept() only in a flags argument naming
// SOCK_CLOEXEC/SOCK_NONBLOCK, neither of which is honoured yet.
SYSCALL_ALIAS( 288, accept)