Count number of threads that enter and leave dynamically registered

syscalls. On the dynamic syscall deregistration, wait until all
threads leave the syscall code. This somewhat increases the safety
of the loadable modules unloading.

Reviewed by:	jhb
Tested by:	pho
MFC after:	1 month
This commit is contained in:
Konstantin Belousov 2010-06-28 18:06:46 +00:00
parent dc2db34f42
commit 153ac44cf6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=209579
6 changed files with 101 additions and 29 deletions

View file

@ -386,16 +386,16 @@
;
; The following are reserved for loadable syscalls
;
210 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
211 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
212 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
213 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
214 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
215 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
216 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
217 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
218 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
219 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
;
; The following were introduced with NetBSD/4.4Lite-2

View file

@ -28,12 +28,15 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/sx.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/systm.h>
#include <machine/atomic.h>
/*
* Acts like "nosys" but can be identified in sysent for dynamic call
@ -55,6 +58,51 @@ lkmressys(struct thread *td, struct nosys_args *args)
return (nosys(td, args));
}
static void
syscall_thread_drain(struct sysent *se)
{
u_int32_t cnt, oldcnt;
do {
oldcnt = se->sy_thrcnt;
KASSERT((oldcnt & SY_THR_STATIC) == 0,
("drain on static syscall"));
cnt = oldcnt | SY_THR_DRAINING;
} while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
while (atomic_cmpset_32(&se->sy_thrcnt, SY_THR_DRAINING,
SY_THR_ABSENT) == 0)
pause("scdrn", hz/2);
}
int
syscall_thread_enter(struct thread *td, struct sysent *se)
{
u_int32_t cnt, oldcnt;
do {
oldcnt = se->sy_thrcnt;
if ((oldcnt & SY_THR_STATIC) != 0)
return (0);
if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0)
return (ENOSYS);
cnt = oldcnt + SY_THR_INCR;
} while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
return (0);
}
void
syscall_thread_exit(struct thread *td, struct sysent *se)
{
u_int32_t cnt, oldcnt;
do {
oldcnt = se->sy_thrcnt;
if ((oldcnt & SY_THR_STATIC) != 0)
return;
cnt = oldcnt - SY_THR_INCR;
} while (atomic_cmpset_rel_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
}
int
syscall_register(int *offset, struct sysent *new_sysent,
struct sysent *old_sysent)
@ -74,8 +122,12 @@ syscall_register(int *offset, struct sysent *new_sysent,
sysent[*offset].sy_call != (sy_call_t *)lkmressys)
return (EEXIST);
KASSERT(sysent[*offset].sy_thrcnt == SY_THR_ABSENT,
("dynamic syscall is not protected"));
*old_sysent = sysent[*offset];
new_sysent->sy_thrcnt = SY_THR_ABSENT;
sysent[*offset] = *new_sysent;
atomic_store_rel_32(&sysent[*offset].sy_thrcnt, 0);
return (0);
}
@ -83,8 +135,10 @@ int
syscall_deregister(int *offset, struct sysent *old_sysent)
{
if (*offset)
if (*offset) {
syscall_thread_drain(&sysent[*offset]);
sysent[*offset] = *old_sysent;
}
return (0);
}

View file

@ -253,6 +253,10 @@ s/\$//g
f=4 # toss number, type, audit event
argc= 0;
argssize = "0"
thr_flag = "SY_THR_STATIC"
if (flag("NOTSTATIC")) {
thr_flag = "SY_THR_ABSENT"
}
if ($NF != "}") {
funcalias=$(NF-2)
argalias=$(NF-1)
@ -401,10 +405,10 @@ s/\$//g
printf("\t{ %s, (sy_call_t *)", argssize) > sysent
column = 8 + 2 + length(argssize) + 15
if (flag("NOSTD")) {
printf("%s },", "lkmressys, AUE_NULL, NULL, 0, 0, 0") > sysent
printf("%s },", "lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT") > sysent
column = column + length("lkmressys") + length("AUE_NULL") + 3
} else {
printf("%s, %s, NULL, 0, 0, %s },", funcname, auditev, flags) > sysent
printf("%s, %s, NULL, 0, 0, %s, %s },", funcname, auditev, flags, thr_flag) > sysent
column = column + length(funcname) + length(auditev) + length(flags) + 3
}
align_sysent_comment(column)
@ -472,13 +476,13 @@ s/\$//g
prefix, funcname, auditev) > sysaue
}
if (flag("NOSTD")) {
printf("\t{ %s, (sy_call_t *)%s, %s, NULL, 0, 0, 0 },",
printf("\t{ %s, (sy_call_t *)%s, %s, NULL, 0, 0, 0, SY_THR_ABSENT },",
"0", "lkmressys", "AUE_NULL") > sysent
align_sysent_comment(8 + 2 + length("0") + 15 + \
length("lkmressys") + length("AUE_NULL") + 3)
} else {
printf("\t{ %s(%s,%s), %s, NULL, 0, 0, %s },",
wrap, argssize, funcname, auditev, flags) > sysent
printf("\t{ %s(%s,%s), %s, NULL, 0, 0, %s, %s },",
wrap, argssize, funcname, auditev, flags, thr_flag) > sysent
align_sysent_comment(8 + 9 + length(argssize) + 1 + \
length(funcname) + length(auditev) + \
length(flags) + 4)
@ -498,7 +502,7 @@ s/\$//g
next
}
type("OBSOL") {
printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },") > sysent
printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },") > sysent
align_sysent_comment(34)
printf("/* %d = obsolete %s */\n", syscall, comment) > sysent
printf("\t\"obs_%s\",\t\t\t/* %d = obsolete %s */\n",
@ -509,7 +513,7 @@ s/\$//g
next
}
type("UNIMPL") {
printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0 },\t\t\t/* %d = %s */\n",
printf("\t{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },\t\t\t/* %d = %s */\n",
syscall, comment) > sysent
printf("\t\"#%d\",\t\t\t/* %d = %s */\n",
syscall, syscall, comment) > sysnames

View file

@ -298,6 +298,9 @@ syscallenter(struct thread *td, struct syscall_args *sa)
if (error != 0)
goto retval;
}
error = syscall_thread_enter(td, sa->callp);
if (error != 0)
goto retval;
#ifdef KDTRACE_HOOKS
/*
@ -327,6 +330,7 @@ syscallenter(struct thread *td, struct syscall_args *sa)
(*systrace_probe_func)(sa->callp->sy_return, sa->code,
sa->callp, sa->args);
#endif
syscall_thread_exit(td, sa->callp);
CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx",
p, error, td->td_retval[0], td->td_retval[1]);
}

View file

@ -40,7 +40,7 @@
; NOPROTO same as STD except do not create structure or
; function prototype in sys/sysproto.h. Does add a
; definition to syscall.h besides adding a sysent.
; NONSTATIC syscall is loadable
;
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
@ -403,16 +403,16 @@
;
; The following are reserved for loadable syscalls
;
210 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
211 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
212 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
213 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
214 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
215 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
216 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
217 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
218 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
219 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
210 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
211 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
212 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
213 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
214 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
215 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
216 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
217 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
218 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
219 AUE_NULL NODEF|NOTSTATIC lkmnosys lkmnosys nosys_args int
;
; The following were introduced with NetBSD/4.4Lite-2

View file

@ -61,8 +61,15 @@ struct sysent { /* system call table */
u_int32_t sy_entry; /* DTrace entry 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_thrcnt;
};
#define SY_THR_FLAGMASK 0x7
#define SY_THR_STATIC 0x1
#define SY_THR_DRAINING 0x2
#define SY_THR_ABSENT 0x4
#define SY_THR_INCR 0x8
struct image_params;
struct __sigset;
struct syscall_args;
@ -211,6 +218,9 @@ struct nosys_args;
int lkmnosys(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);
#endif /* _KERNEL */
#endif /* !_SYS_SYSENT_H_ */