svn commit: r209579 - in head/sys: compat/freebsd32 kern sys

Konstantin Belousov kib at FreeBSD.org
Mon Jun 28 18:06:47 UTC 2010


Author: kib
Date: Mon Jun 28 18:06:46 2010
New Revision: 209579
URL: http://svn.freebsd.org/changeset/base/209579

Log:
  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

Modified:
  head/sys/compat/freebsd32/syscalls.master
  head/sys/kern/kern_syscalls.c
  head/sys/kern/makesyscalls.sh
  head/sys/kern/subr_trap.c
  head/sys/kern/syscalls.master
  head/sys/sys/sysent.h

Modified: head/sys/compat/freebsd32/syscalls.master
==============================================================================
--- head/sys/compat/freebsd32/syscalls.master	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/compat/freebsd32/syscalls.master	Mon Jun 28 18:06:46 2010	(r209579)
@@ -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

Modified: head/sys/kern/kern_syscalls.c
==============================================================================
--- head/sys/kern/kern_syscalls.c	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/kern/kern_syscalls.c	Mon Jun 28 18:06:46 2010	(r209579)
@@ -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 nosy
 	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 sys
 	    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);
 }
 

Modified: head/sys/kern/makesyscalls.sh
==============================================================================
--- head/sys/kern/makesyscalls.sh	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/kern/makesyscalls.sh	Mon Jun 28 18:06:46 2010	(r209579)
@@ -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

Modified: head/sys/kern/subr_trap.c
==============================================================================
--- head/sys/kern/subr_trap.c	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/kern/subr_trap.c	Mon Jun 28 18:06:46 2010	(r209579)
@@ -298,6 +298,9 @@ syscallenter(struct thread *td, struct s
 			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 s
 			(*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]);
 	}

Modified: head/sys/kern/syscalls.master
==============================================================================
--- head/sys/kern/syscalls.master	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/kern/syscalls.master	Mon Jun 28 18:06:46 2010	(r209579)
@@ -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

Modified: head/sys/sys/sysent.h
==============================================================================
--- head/sys/sys/sysent.h	Mon Jun 28 17:59:45 2010	(r209578)
+++ head/sys/sys/sysent.h	Mon Jun 28 18:06:46 2010	(r209579)
@@ -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_ */


More information about the svn-src-all mailing list