VERSIONINGSYSCALLS(9) | Kernel Developer's Manual | VERSIONINGSYSCALLS(9) |
versioningsyscalls
—
In the kernel, a new syscall is added with a new ABI, and the old
syscall is retained and moved to a new location that holds the compatibility
syscalls (src/sys/compat). Kernels can be compiled
with or without backwards compatibility syscalls. See the
COMPAT_
XX options in
options(4).
In userland, the original syscall stub is moved into src/lib/libc/compat retaining the same symbol name and ABI. The new stub is added to libc, and in the header file the syscall symbol is made to point to the new name with the new ABI.
This is done via symbol renaming instead of ELF versioned symbols for historical reasons. NetBSD has retained binary compatibility with most syscalls since NetBSD 0.9 with the exception of Scheduler Activation syscalls which are not being emulated because of the cost and safety of doing so.
To avoid confusion, the following words are used to disambiguate which version of the system call is being described.
Additionally, CNUM always represents the
last NetBSD release where the current version of the
system call is the default, multiplied by ten and retaining a leading zero.
For example NetBSD 0.9 has
COMPAT_09
whereas NetBSD
10.0 has COMPAT_100
.
my_syscall
(struct my_struct *ms)
and that my_struct will be versioned. If not versioning
a struct, passages that mention my_struct can be
ignored.
The syscall version suffix VNUM
indicates
the first release of NetBSD the system call will
appear in. The compat version CNUM
is the last
version of NetBSD the old system call was used.
Typically VNUM = CNUM + 1 .
For example if you are versioning
getcontext(2) just after
NetBSD 11 was released, and the original system call
was called getcontext
(), the system call will become
__getcontext12
() and the compat entry point will
become compat_11_getcontext
().
Next time
getcontext(2) needs
versioning, for example just after NetBSD 15 was
released, it will become __getcontext16
() and the
compat entry will become
compat_15___getcontext12
().
Please note that the historical practice up to NetBSD 11 has been that the syscall suffix matched the version when the syscall was last used.
__my_syscallVNUM
(), and will have entry point
sys___my_syscallVNUM
().
compat_CNUM
in the
compatopts variable.
my_syscall
() as the name, and set the
(optional) compat field of the declaration to CNUM.
Next, modify the current version of the syscall, and replace the
type field (usually just STD
) with
COMPAT_CNUM MODULAR compat_CNUM
.
The keyword MODULAR
indicates that the
system call can be part of a kernel module. Even if the system call was not
part of a module before, now it will be part of the
COMPAT_CNUM
module.
Finally, if applicable, replace the types of the current and old versions of the syscall with the compat type.
Overall, the final diff should look like
- 123 STD { int|sys||my_syscall(struct my_struct *ms); } + 123 COMPAT_CNUM MODULAR compat_CNUM { int|sys||my_syscall(struct my_structCNUM *ms); } ... + 456 STD { int|sys|VNUM|my_syscall(struct my_struct *ms); }
RUMP_NBCOMPAT
variable.
The uncompattypes map is used in rump(7) system call table generation, to map from the versioned types to the original names since rump(7) wants to have a non-versioned copy of the system call table.
Then regenerate the syscall tables in the usual way, first by running sys/kern/makesyscalls.sh, then if the system call is rump, doing a build in sys/rump and then running sys/rump/makerumpsyscalls.sh passing it the path to the result of the build you just did as its first argument.
sys_my_syscall
() and lives inside
sys/kern/my_file.c.
compat_CNUM_sys_my_syscall
(), and should be
implemented in sys/compat/common/my_file_CNUM.c with
the same semantics as the current syscall. Often this involves translating the
arguments to the next syscall, and then calling that syscall's entry point.
Additionally,
sys/compat/common/my_file_CNUM.c must contain two
functions, my_file_CNUM_init
() and
my_file_CNUM_fini
() that are used to
initialize/clean up anything related to this syscall. At the minimum they
must make calls to syscall_establish
() and
syscall_disestablish
() respectively, adding and
removing the syscalls. The stubs for these functions should be located in
sys/compat/common/compat_mod.h.
Overall, sys/compat/common/my_file_CNUM.c must at the minimum contain
static const struct syscall_package my_file_CNUM_syscalls[] = { { SYS_compat_CNUM_my_syscall, 0, (sy_call_t *)compat_CNUM_sys_my_syscall }, { 0, 0, NULL }, }; int compat_CNUM_my_syscall(...) { /* Compat implementation goes here. */ } int my_file_CNUM_init(void) { return syscall_establish(NULL, my_file_CNUM_syscalls); } int my_file_CNUM_fini(void) { return syscall_disestablish(NULL, my_file_CNUM_syscalls); }
Finally,
sys/compat/common/compat_CNUM_mod.c needs to be
modified to have its compat_CNUM_init
() and
compat_CNUM_fini
() functions call
my_file_CNUM_init
() and
my_file_CNUM_fini
() respectively.
#define
.
my_syscall
(struct my_struct *ms)
in sys/sys/my_header.h, an implementation of
my_syscall
() must be written in
lib/libc/compat/sys/compat_my_syscall.c.
Additionally, a call to
__warn_references
() must be added in
lib/libc/compat/sys/compat_my_syscall.c to warn of
any uses of the compat syscall and mention how to use the next version of
the syscall. In almost all cases the instructions on how to use the next
version of the syscall will be “include <sys/my_header.h> to
generate correct reference”.
Overall, lib/libc/compat/sys/compat_my_syscall.c must at the minimum include
#include <sys/compat/my_header.h> __warn_references(my_syscall, "warning: reference to compatibility my_syscall();" " message on how to use the next my_syscall()"); int my_syscall() { /* Compat implementation goes here. */ }
May 20, 2024 | NetBSD 10.1 |