Atomic insertion/removal of groups of system call vectors at runtime with
a basic facility for rollback. Proposed on tech-kern@.
This commit is contained in:
parent
307004b54f
commit
119366618e
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_stub.c,v 1.11 2008/10/15 16:03:29 wrstuden Exp $ */
|
||||
/* $NetBSD: kern_stub.c,v 1.12 2008/11/12 14:29:31 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -62,7 +62,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.11 2008/10/15 16:03:29 wrstuden Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.12 2008/11/12 14:29:31 ad Exp $");
|
||||
|
||||
#include "opt_ptrace.h"
|
||||
#include "opt_ktrace.h"
|
||||
|
@ -72,10 +72,13 @@ __KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.11 2008/10/15 16:03:29 wrstuden Exp
|
|||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/syscallargs.h>
|
||||
#include <sys/syscallvar.h>
|
||||
#include <sys/ktrace.h>
|
||||
#include <sys/intr.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
/*
|
||||
* Nonexistent system call-- signal process (may want to handle it). Flag
|
||||
|
@ -160,7 +163,6 @@ cpu_kpreempt_disabled(void)
|
|||
# endif
|
||||
#endif /* !__HAVE_PREEMPTION */
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
sys_nosys(struct lwp *l, const void *v, register_t *retval)
|
||||
{
|
||||
|
@ -171,6 +173,65 @@ sys_nosys(struct lwp *l, const void *v, register_t *retval)
|
|||
return ENOSYS;
|
||||
}
|
||||
|
||||
int
|
||||
sys_nomodule(struct lwp *l, const void *v, register_t *retval)
|
||||
{
|
||||
#ifdef MODULAR
|
||||
static struct {
|
||||
u_int al_code;
|
||||
const char *al_module;
|
||||
} const autoload[] = {
|
||||
{ SYS__ksem_init, "ksem" },
|
||||
{ SYS__ksem_open, "ksem" },
|
||||
{ SYS__ksem_unlink, "ksem" },
|
||||
{ SYS__ksem_close, "ksem" },
|
||||
{ SYS__ksem_post, "ksem" },
|
||||
{ SYS__ksem_wait, "ksem" },
|
||||
{ SYS__ksem_trywait, "ksem" },
|
||||
{ SYS__ksem_getvalue, "ksem" },
|
||||
{ SYS__ksem_destroy, "ksem" },
|
||||
};
|
||||
const struct sysent *sy;
|
||||
const struct emul *em;
|
||||
int code, i;
|
||||
|
||||
/*
|
||||
* Restart the syscall if we interrupted a module unload that
|
||||
* failed. Acquiring module_lock delays us until any unload
|
||||
* has been completed or rolled back.
|
||||
*/
|
||||
mutex_enter(&module_lock);
|
||||
sy = l->l_sysent;
|
||||
if (sy->sy_call != sys_nomodule) {
|
||||
mutex_exit(&module_lock);
|
||||
return ERESTART;
|
||||
}
|
||||
/*
|
||||
* Try to autoload a module to satisfy the request. If it
|
||||
* works, retry the request.
|
||||
*/
|
||||
em = l->l_proc->p_emul;
|
||||
if (em == &emul_netbsd) {
|
||||
code = sy - em->e_sysent;
|
||||
for (i = 0; i < __arraycount(autoload); i++) {
|
||||
if (autoload[i].al_code != code) {
|
||||
continue;
|
||||
}
|
||||
if (module_autoload(autoload[i].al_module,
|
||||
MODULE_CLASS_ANY) != 0 ||
|
||||
sy->sy_call == sys_nomodule) {
|
||||
break;
|
||||
}
|
||||
mutex_exit(&module_lock);
|
||||
return ERESTART;
|
||||
}
|
||||
}
|
||||
mutex_exit(&module_lock);
|
||||
#endif /* MODULAR */
|
||||
|
||||
return sys_nosys(l, v, retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unsupported device function (e.g. writing to read-only device).
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_subr.c,v 1.193 2008/11/11 06:46:44 dyoung Exp $ */
|
||||
/* $NetBSD: kern_subr.c,v 1.194 2008/11/12 14:29:31 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -79,7 +79,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.193 2008/11/11 06:46:44 dyoung Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.194 2008/11/12 14:29:31 ad Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_md.h"
|
||||
|
@ -105,6 +105,9 @@ __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.193 2008/11/11 06:46:44 dyoung Exp $
|
|||
#include <sys/fcntl.h>
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/syscallvar.h>
|
||||
#include <sys/xcall.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
|
@ -1330,3 +1333,98 @@ trace_exit(register_t code, register_t rval[], int error)
|
|||
process_stoptrace();
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
syscall_establish(const struct emul *em, const struct syscall_package *sp)
|
||||
{
|
||||
struct sysent *sy;
|
||||
int i;
|
||||
|
||||
KASSERT(mutex_owned(&module_lock));
|
||||
|
||||
if (em == NULL) {
|
||||
em = &emul_netbsd;
|
||||
}
|
||||
sy = em->e_sysent;
|
||||
|
||||
/*
|
||||
* Ensure that all preconditions are valid, since this is
|
||||
* an all or nothing deal. Once a system call is entered,
|
||||
* it can become busy and we could be unable to remove it
|
||||
* on error.
|
||||
*/
|
||||
for (i = 0; sp[i].sp_call != NULL; i++) {
|
||||
if (sy[sp[i].sp_code].sy_call != sys_nomodule) {
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
/* Everything looks good, patch them in. */
|
||||
for (i = 0; sp[i].sp_call != NULL; i++) {
|
||||
sy[sp[i].sp_code].sy_call = sp[i].sp_call;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
syscall_disestablish(const struct emul *em, const struct syscall_package *sp)
|
||||
{
|
||||
struct sysent *sy;
|
||||
uint64_t where;
|
||||
lwp_t *l;
|
||||
int i;
|
||||
|
||||
KASSERT(mutex_owned(&module_lock));
|
||||
|
||||
if (em == NULL) {
|
||||
em = &emul_netbsd;
|
||||
}
|
||||
sy = em->e_sysent;
|
||||
|
||||
/*
|
||||
* First, patch the system calls to sys_nomodule to gate further
|
||||
* activity.
|
||||
*/
|
||||
for (i = 0; sp[i].sp_call != NULL; i++) {
|
||||
KASSERT(sy[sp[i].sp_code].sy_call == sp[i].sp_call);
|
||||
sy[sp[i].sp_code].sy_call = sys_nomodule;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run a cross call to cycle through all CPUs. This does two
|
||||
* things: lock activity provides a barrier and makes our update
|
||||
* of sy_call visible to all CPUs, and upon return we can be sure
|
||||
* that we see pertinent values of l_sysent posted by remote CPUs.
|
||||
*/
|
||||
where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
|
||||
xc_wait(where);
|
||||
|
||||
/*
|
||||
* Now it's safe to check l_sysent. Run through all LWPs and see
|
||||
* if anyone is still using the system call.
|
||||
*/
|
||||
for (i = 0; sp[i].sp_call != NULL; i++) {
|
||||
mutex_enter(proc_lock);
|
||||
LIST_FOREACH(l, &alllwp, l_list) {
|
||||
if (l->l_sysent == &sy[sp[i].sp_code]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_exit(proc_lock);
|
||||
if (l == NULL) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* We lose: one or more calls are still in use. Put back
|
||||
* the old entrypoints and act like nothing happened.
|
||||
* When we drop module_lock, any system calls held in
|
||||
* sys_nomodule() will be restarted.
|
||||
*/
|
||||
for (i = 0; sp[i].sp_call != NULL; i++) {
|
||||
sy[sp[i].sp_code].sy_call = sp[i].sp_call;
|
||||
}
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#! /bin/sh -
|
||||
# $NetBSD: makesyscalls.sh,v 1.73 2008/10/13 18:16:33 pooka Exp $
|
||||
# $NetBSD: makesyscalls.sh,v 1.74 2008/11/12 14:29:31 ad Exp $
|
||||
#
|
||||
# Copyright (c) 1994, 1996, 2000 Christopher G. Demetriou
|
||||
# All rights reserved.
|
||||
|
@ -345,6 +345,12 @@ function parseline() {
|
|||
sycall_flags = "SYCALL_INDIRECT | " sycall_flags
|
||||
f++
|
||||
}
|
||||
if ($f == "MODULAR") { # registered at runtime
|
||||
modular = 1
|
||||
f++
|
||||
} else {
|
||||
modular = 0;
|
||||
}
|
||||
if ($f == "RUMP") {
|
||||
rumpable = 1
|
||||
f++
|
||||
|
@ -497,7 +503,9 @@ function putent(type, compatwrap) {
|
|||
} else {
|
||||
printf("ns(struct %s%s_args), ", compatwrap_, funcname) > sysent
|
||||
}
|
||||
if (compatwrap == "")
|
||||
if (modular)
|
||||
wfn = "(sy_call_t *)sys_nomodule";
|
||||
else if (compatwrap == "")
|
||||
wfn = "(sy_call_t *)" funcname;
|
||||
else
|
||||
wfn = "(sy_call_t *)" compatwrap "(" funcname ")";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: syscallvar.h,v 1.2 2008/10/21 12:22:00 ad Exp $ */
|
||||
/* $NetBSD: syscallvar.h,v 1.3 2008/11/12 14:29:31 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -39,6 +39,18 @@
|
|||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
extern const struct emul emul_netbsd;
|
||||
|
||||
struct syscall_package {
|
||||
u_short sp_code;
|
||||
u_short sp_flags;
|
||||
sy_call_t *sp_call;
|
||||
};
|
||||
|
||||
void syscall_init(void);
|
||||
int syscall_establish(const struct emul *, const struct syscall_package *);
|
||||
int syscall_disestablish(const struct emul *, const struct syscall_package *);
|
||||
|
||||
static inline int
|
||||
sy_call(const struct sysent *sy, struct lwp *l, const void *uap,
|
||||
register_t *rval)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: systm.h,v 1.229 2008/11/12 12:36:28 ad Exp $ */
|
||||
/* $NetBSD: systm.h,v 1.230 2008/11/12 14:29:31 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1988, 1991, 1993
|
||||
|
@ -157,6 +157,7 @@ void *hashinit(u_int, enum hashtype, bool, u_long *);
|
|||
void hashdone(void *, enum hashtype, u_long);
|
||||
int seltrue(dev_t, int, struct lwp *);
|
||||
int sys_nosys(struct lwp *, const void *, register_t *);
|
||||
int sys_nomodule(struct lwp *, const void *, register_t *);
|
||||
|
||||
void aprint_normal(const char *, ...)
|
||||
__attribute__((__format__(__printf__,1,2)));
|
||||
|
|
Loading…
Reference in New Issue