From d19a162142eef526ef1ad29b8939ef0b7a92d04c Mon Sep 17 00:00:00 2001 From: kib Date: Fri, 19 Mar 2010 10:56:30 +0000 Subject: Introduce SYSCALL_INIT_HELPER and SYSCALL32_INIT_HELPER macros and neccessary support functions to allow registering dynamically loaded syscalls from the MOD_LOAD handlers. Helpers handle registration failures semi-automatically. Reviewed by: jhb MFC after: 2 weeks --- sys/compat/freebsd32/freebsd32_misc.c | 30 ++++++++++++++++++++++++++++++ sys/compat/freebsd32/freebsd32_util.h | 11 +++++++++++ sys/kern/kern_syscalls.c | 30 ++++++++++++++++++++++++++++++ sys/sys/sysent.h | 24 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 56bd02a..7a7dc2e 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -3084,6 +3084,36 @@ syscall32_module_handler(struct module *mod, int what, void *arg) } } +int +syscall32_helper_register(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + int error; + + for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { + error = syscall32_register(&sd1->syscall_no, &sd1->new_sysent, + &sd1->old_sysent); + if (error != 0) { + syscall32_helper_unregister(sd); + return (error); + } + sd1->registered = 1; + } + return (0); +} + +int +syscall32_helper_unregister(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + + for (sd1 = sd; sd1->registered != 0; sd1++) { + syscall32_deregister(&sd1->syscall_no, &sd1->old_sysent); + sd1->registered = 0; + } + return (0); +} + register_t * freebsd32_copyout_strings(struct image_params *imgp) { diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h index 8f94612..f5ccbf1 100644 --- a/sys/compat/freebsd32/freebsd32_util.h +++ b/sys/compat/freebsd32/freebsd32_util.h @@ -78,10 +78,21 @@ SYSCALL32_MODULE(syscallname, \ & syscallname##_syscall32, & syscallname##_sysent32,\ NULL, NULL); +#define SYSCALL32_INIT_HELPER(syscallname) { \ + .new_sysent = { \ + .sy_narg = (sizeof(struct syscallname ## _args ) \ + / sizeof(register_t)), \ + .sy_call = (sy_call_t *)& syscallname, \ + }, \ + .syscall_no = FREEBSD32_SYS_##syscallname \ +} + int syscall32_register(int *offset, struct sysent *new_sysent, struct sysent *old_sysent); int syscall32_deregister(int *offset, struct sysent *old_sysent); int syscall32_module_handler(struct module *mod, int what, void *arg); +int syscall32_helper_register(struct syscall_helper_data *sd); +int syscall32_helper_unregister(struct syscall_helper_data *sd); register_t *freebsd32_copyout_strings(struct image_params *imgp); struct iovec32; diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c index 077aedc..9cb7b68 100644 --- a/sys/kern/kern_syscalls.c +++ b/sys/kern/kern_syscalls.c @@ -135,3 +135,33 @@ syscall_module_handler(struct module *mod, int what, void *arg) else return (0); } + +int +syscall_helper_register(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + int error; + + for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { + error = syscall_register(&sd1->syscall_no, &sd1->new_sysent, + &sd1->old_sysent); + if (error != 0) { + syscall_helper_unregister(sd); + return (error); + } + sd1->registered = 1; + } + return (0); +} + +int +syscall_helper_unregister(struct syscall_helper_data *sd) +{ + struct syscall_helper_data *sd1; + + for (sd1 = sd; sd1->registered != 0; sd1++) { + syscall_deregister(&sd1->syscall_no, &sd1->old_sysent); + sd1->registered = 0; + } + return (0); +} diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 76cd5bd..707c00b 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -166,10 +166,34 @@ SYSCALL_MODULE(syscallname, \ (sysent[SYS_##syscallname].sy_call != (sy_call_t *)lkmnosys && \ sysent[SYS_##syscallname].sy_call != (sy_call_t *)lkmressys) +/* + * Syscall registration helpers with resource allocation handling. + */ +struct syscall_helper_data { + struct sysent new_sysent; + struct sysent old_sysent; + int syscall_no; + int registered; +}; +#define SYSCALL_INIT_HELPER(syscallname) { \ + .new_sysent = { \ + .sy_narg = (sizeof(struct syscallname ## _args ) \ + / sizeof(register_t)), \ + .sy_call = (sy_call_t *)& syscallname, \ + .sy_auevent = SYS_AUE_##syscallname \ + }, \ + .syscall_no = SYS_##syscallname \ +} +#define SYSCALL_INIT_LAST { \ + .syscall_no = NO_SYSCALL \ +} + int syscall_register(int *offset, struct sysent *new_sysent, struct sysent *old_sysent); int syscall_deregister(int *offset, struct sysent *old_sysent); int syscall_module_handler(struct module *mod, int what, void *arg); +int syscall_helper_register(struct syscall_helper_data *sd); +int syscall_helper_unregister(struct syscall_helper_data *sd); /* Special purpose system call functions. */ struct nosys_args; -- cgit v1.1