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.
|
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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_ptrace.h"
|
||||||
#include "opt_ktrace.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/kernel.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
#include <sys/signalvar.h>
|
#include <sys/signalvar.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include <sys/syscallargs.h>
|
#include <sys/syscallargs.h>
|
||||||
|
#include <sys/syscallvar.h>
|
||||||
#include <sys/ktrace.h>
|
#include <sys/ktrace.h>
|
||||||
#include <sys/intr.h>
|
#include <sys/intr.h>
|
||||||
#include <sys/cpu.h>
|
#include <sys/cpu.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nonexistent system call-- signal process (may want to handle it). Flag
|
* Nonexistent system call-- signal process (may want to handle it). Flag
|
||||||
|
@ -160,7 +163,6 @@ cpu_kpreempt_disabled(void)
|
||||||
# endif
|
# endif
|
||||||
#endif /* !__HAVE_PREEMPTION */
|
#endif /* !__HAVE_PREEMPTION */
|
||||||
|
|
||||||
/* ARGSUSED */
|
|
||||||
int
|
int
|
||||||
sys_nosys(struct lwp *l, const void *v, register_t *retval)
|
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;
|
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).
|
* 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.
|
* Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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_ddb.h"
|
||||||
#include "opt_md.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/fcntl.h>
|
||||||
#include <sys/kauth.h>
|
#include <sys/kauth.h>
|
||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/syscallvar.h>
|
||||||
|
#include <sys/xcall.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
|
||||||
#include <uvm/uvm_extern.h>
|
#include <uvm/uvm_extern.h>
|
||||||
|
|
||||||
|
@ -1330,3 +1333,98 @@ trace_exit(register_t code, register_t rval[], int error)
|
||||||
process_stoptrace();
|
process_stoptrace();
|
||||||
#endif
|
#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 -
|
#! /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
|
# Copyright (c) 1994, 1996, 2000 Christopher G. Demetriou
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
@ -345,6 +345,12 @@ function parseline() {
|
||||||
sycall_flags = "SYCALL_INDIRECT | " sycall_flags
|
sycall_flags = "SYCALL_INDIRECT | " sycall_flags
|
||||||
f++
|
f++
|
||||||
}
|
}
|
||||||
|
if ($f == "MODULAR") { # registered at runtime
|
||||||
|
modular = 1
|
||||||
|
f++
|
||||||
|
} else {
|
||||||
|
modular = 0;
|
||||||
|
}
|
||||||
if ($f == "RUMP") {
|
if ($f == "RUMP") {
|
||||||
rumpable = 1
|
rumpable = 1
|
||||||
f++
|
f++
|
||||||
|
@ -497,7 +503,9 @@ function putent(type, compatwrap) {
|
||||||
} else {
|
} else {
|
||||||
printf("ns(struct %s%s_args), ", compatwrap_, funcname) > sysent
|
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;
|
wfn = "(sy_call_t *)" funcname;
|
||||||
else
|
else
|
||||||
wfn = "(sy_call_t *)" compatwrap "(" funcname ")";
|
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.
|
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||||
|
@ -39,6 +39,18 @@
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/proc.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
|
static inline int
|
||||||
sy_call(const struct sysent *sy, struct lwp *l, const void *uap,
|
sy_call(const struct sysent *sy, struct lwp *l, const void *uap,
|
||||||
register_t *rval)
|
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
|
* 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);
|
void hashdone(void *, enum hashtype, u_long);
|
||||||
int seltrue(dev_t, int, struct lwp *);
|
int seltrue(dev_t, int, struct lwp *);
|
||||||
int sys_nosys(struct lwp *, const void *, register_t *);
|
int sys_nosys(struct lwp *, const void *, register_t *);
|
||||||
|
int sys_nomodule(struct lwp *, const void *, register_t *);
|
||||||
|
|
||||||
void aprint_normal(const char *, ...)
|
void aprint_normal(const char *, ...)
|
||||||
__attribute__((__format__(__printf__,1,2)));
|
__attribute__((__format__(__printf__,1,2)));
|
||||||
|
|
Loading…
Reference in New Issue