Changeset View
Standalone View
sys/sys/sysent.h
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | typedef void (*systrace_probe_func_t)(struct syscall_args *, | ||||
enum systrace_probe_t, int); | enum systrace_probe_t, int); | ||||
typedef void (*systrace_args_func_t)(int, void *, uint64_t *, int *); | typedef void (*systrace_args_func_t)(int, void *, uint64_t *, int *); | ||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
extern bool systrace_enabled; | extern bool systrace_enabled; | ||||
#endif | #endif | ||||
extern systrace_probe_func_t systrace_probe_func; | extern systrace_probe_func_t systrace_probe_func; | ||||
/* | |||||
* Make sure to update syscall_sysent_replace when modifying this structure. | |||||
*/ | |||||
struct sysent { /* system call table */ | struct sysent { /* system call table */ | ||||
int sy_narg; /* number of arguments */ | int sy_narg; /* number of arguments */ | ||||
sy_call_t *sy_call; /* implementing function */ | sy_call_t *sy_call; /* implementing function */ | ||||
au_event_t sy_auevent; /* audit event associated with syscall */ | au_event_t sy_auevent; /* audit event associated with syscall */ | ||||
systrace_args_func_t sy_systrace_args_func; | systrace_args_func_t sy_systrace_args_func; | ||||
/* optional argument conversion function. */ | /* optional argument conversion function. */ | ||||
u_int32_t sy_entry; /* DTrace entry ID for systrace. */ | u_int32_t sy_entry; /* DTrace entry ID for systrace. */ | ||||
u_int32_t sy_return; /* DTrace return ID for systrace. */ | u_int32_t sy_return; /* DTrace return ID for systrace. */ | ||||
u_int32_t sy_flags; /* General flags for system calls. */ | u_int32_t sy_flags; /* General flags for system calls. */ | ||||
u_int32_t sy_thrcnt; | u_int32_t sy_thrflags; | ||||
}; | }; | ||||
/* | /* | ||||
* A system call is permitted in capability mode. | * A system call is permitted in capability mode. | ||||
*/ | */ | ||||
#define SYF_CAPENABLED 0x00000001 | #define SYF_CAPENABLED 0x00000001 | ||||
#define SY_THR_FLAGMASK 0x7 | #define SY_THR_FLAGMASK 0x3 | ||||
#define SY_THR_STATIC 0x1 | #define SY_THR_STATIC 0x1 | ||||
#define SY_THR_DRAINING 0x2 | #define SY_THR_ABSENT 0x2 | ||||
#define SY_THR_ABSENT 0x4 | |||||
#define SY_THR_INCR 0x8 | |||||
#ifdef KLD_MODULE | #ifdef KLD_MODULE | ||||
#define SY_THR_STATIC_KLD 0 | #define SY_THR_STATIC_KLD 0 | ||||
#else | #else | ||||
#define SY_THR_STATIC_KLD SY_THR_STATIC | #define SY_THR_STATIC_KLD SY_THR_STATIC | ||||
#endif | #endif | ||||
struct image_params; | struct image_params; | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | #define SYSENT_INIT_VALS(_syscallname) { \ | ||||
.sy_narg = (sizeof(struct _syscallname ## _args ) \ | .sy_narg = (sizeof(struct _syscallname ## _args ) \ | ||||
/ sizeof(register_t)), \ | / sizeof(register_t)), \ | ||||
.sy_call = (sy_call_t *)&sys_##_syscallname, \ | .sy_call = (sy_call_t *)&sys_##_syscallname, \ | ||||
.sy_auevent = SYS_AUE_##_syscallname, \ | .sy_auevent = SYS_AUE_##_syscallname, \ | ||||
.sy_systrace_args_func = NULL, \ | .sy_systrace_args_func = NULL, \ | ||||
.sy_entry = 0, \ | .sy_entry = 0, \ | ||||
.sy_return = 0, \ | .sy_return = 0, \ | ||||
.sy_flags = 0, \ | .sy_flags = 0, \ | ||||
.sy_thrcnt = 0 \ | .sy_thrflags = 0 \ | ||||
} | } | ||||
#define MAKE_SYSENT(syscallname) \ | #define MAKE_SYSENT(syscallname) \ | ||||
static struct sysent syscallname##_sysent = SYSENT_INIT_VALS(syscallname); | static struct sysent syscallname##_sysent = SYSENT_INIT_VALS(syscallname); | ||||
#define MAKE_SYSENT_COMPAT(syscallname) \ | #define MAKE_SYSENT_COMPAT(syscallname) \ | ||||
static struct sysent syscallname##_sysent = { \ | static struct sysent syscallname##_sysent = { \ | ||||
(sizeof(struct syscallname ## _args ) \ | (sizeof(struct syscallname ## _args ) \ | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
const char *syscallname(struct proc *p, u_int code); | const char *syscallname(struct proc *p, u_int code); | ||||
/* Special purpose system call functions. */ | /* Special purpose system call functions. */ | ||||
struct nosys_args; | struct nosys_args; | ||||
int lkmnosys(struct thread *, struct nosys_args *); | int lkmnosys(struct thread *, struct nosys_args *); | ||||
int lkmressys(struct thread *, struct nosys_args *); | int lkmressys(struct thread *, struct nosys_args *); | ||||
int _syscall_thread_enter(struct thread *td, struct sysent *se); | /* | ||||
void _syscall_thread_exit(struct thread *td, struct sysent *se); | * See syscall_drain(). | ||||
*/ | |||||
static inline int | #define syscall_read_barrier() __compiler_membar() | ||||
syscall_thread_enter(struct thread *td, struct sysent *se) | #define syscall_exit(td) do { (td)->td_sa.callp = NULL; } while (0) | ||||
kib: I do think that syscall_read_barrier() should be replaced by the store to sa.callp with acquire… | |||||
mjgAuthorUnsubmitted Done Inline ActionsThis callp thing was a brainfart from the previous iteration of the patch (where I used D23582 to wait for everyone to leave cpu_fetch_syscall_args). I think testing for td_sa.code + the seq_cst fence injected with the IPI are sufficient. syscall_read_barrier + cpu_fence_seq_cst after setting td_sa.code means if we observe it, the target thread may be on the way to use the old (or new) sysent state, both of which are fine. We only care to observe that it switches td_sa.code /at some point/ to something else. Even if it switches back to the waited for syscall number we are fine since by that time the to be unloaded syscall is guaranteed to not be seen by this particular thread. If we observe anything but passed code, the thread is either executing something else or about to resolve this very syscall, but thanks to the fence it will read the new content. Note that cpu_fence_seq_cst injects a fence for everyone, including the current cpu. mjg: This callp thing was a brainfart from the previous iteration of the patch (where I used D23582… | |||||
{ | |||||
if (__predict_true((se->sy_thrcnt & SY_THR_STATIC) != 0)) | |||||
return (0); | |||||
return (_syscall_thread_enter(td, se)); | |||||
} | |||||
static inline void | |||||
syscall_thread_exit(struct thread *td, struct sysent *se) | |||||
{ | |||||
if (__predict_true((se->sy_thrcnt & SY_THR_STATIC) != 0)) | |||||
return; | |||||
_syscall_thread_exit(td, se); | |||||
} | |||||
int shared_page_alloc(int size, int align); | int shared_page_alloc(int size, int align); | ||||
int shared_page_fill(int size, int align, const void *data); | int shared_page_fill(int size, int align, const void *data); | ||||
void shared_page_write(int base, int size, const void *data); | void shared_page_write(int base, int size, const void *data); | ||||
void exec_sysvec_init(void *param); | void exec_sysvec_init(void *param); | ||||
void exec_inittk(void); | void exec_inittk(void); | ||||
#define INIT_SYSENTVEC(name, sv) \ | #define INIT_SYSENTVEC(name, sv) \ | ||||
SYSINIT(name, SI_SUB_EXEC, SI_ORDER_ANY, \ | SYSINIT(name, SI_SUB_EXEC, SI_ORDER_ANY, \ | ||||
(sysinit_cfunc_t)exec_sysvec_init, sv); | (sysinit_cfunc_t)exec_sysvec_init, sv); | ||||
#endif /* _KERNEL */ | #endif /* _KERNEL */ | ||||
#endif /* !_SYS_SYSENT_H_ */ | #endif /* !_SYS_SYSENT_H_ */ |
I do think that syscall_read_barrier() should be replaced by the store to sa.callp with acquire semantic, to sync/with the release in the syscall_sysent_replace, to see previous writes from _replace.
Next, _exit should be a release store, so that accesses to the dynamic syscall' sysent cannot be reordered after the exit is observed by the waiter.