svn commit: r186564 - in head/sys: compat/freebsd32 compat/linux i386/ibcs2 kern

Ed Schouten ed at FreeBSD.org
Mon Dec 29 12:58:46 UTC 2008


Author: ed
Date: Mon Dec 29 12:58:45 2008
New Revision: 186564
URL: http://svn.freebsd.org/changeset/base/186564

Log:
  Push down Giant inside sysctl. Also add some more assertions to the code.
  
  In the existing code we didn't really enforce that callers hold Giant
  before calling userland_sysctl(), even though there is no guarantee it
  is safe. Fix this by just placing Giant locks around the call to the oid
  handler. This also means we only pick up Giant for a very short period
  of time. Maybe we should add MPSAFE flags to sysctl or phase it out all
  together.
  
  I've also added SYSCTL_LOCK_ASSERT(). We have to make sure sysctl_root()
  and name2oid() are called with the sysctl lock held.
  
  Reviewed by:	Jille Timmermans <jille quis cx>

Modified:
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/compat/linux/linux_misc.c
  head/sys/i386/ibcs2/ibcs2_sysi86.c
  head/sys/kern/kern_sysctl.c
  head/sys/kern/kern_xxx.c

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Mon Dec 29 12:45:11 2008	(r186563)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Mon Dec 29 12:58:45 2008	(r186564)
@@ -2019,7 +2019,6 @@ freebsd32_sysctl(struct thread *td, stru
  	error = copyin(uap->name, name, uap->namelen * sizeof(int));
  	if (error)
 		return (error);
-	mtx_lock(&Giant);
 	if (uap->oldlenp)
 		oldlen = fuword32(uap->oldlenp);
 	else
@@ -2028,12 +2027,10 @@ freebsd32_sysctl(struct thread *td, stru
 		uap->old, &oldlen, 1,
 		uap->new, uap->newlen, &j, SCTL_MASK32);
 	if (error && error != ENOMEM)
-		goto done2;
+		return (error);
 	if (uap->oldlenp)
 		suword32(uap->oldlenp, j);
-done2:
-	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 int

Modified: head/sys/compat/linux/linux_misc.c
==============================================================================
--- head/sys/compat/linux/linux_misc.c	Mon Dec 29 12:45:11 2008	(r186563)
+++ head/sys/compat/linux/linux_misc.c	Mon Dec 29 12:58:45 2008	(r186564)
@@ -1682,7 +1682,6 @@ int
 linux_sethostname(struct thread *td, struct linux_sethostname_args *args)
 {
 	int name[2];
-	int error;
 
 #ifdef DEBUG
 	if (ldebug(sethostname))
@@ -1691,18 +1690,14 @@ linux_sethostname(struct thread *td, str
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_HOSTNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
-	    args->len, 0, 0);
-	mtx_unlock(&Giant);
-	return (error);
+	return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
+	    args->len, 0, 0));
 }
 
 int
 linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
 {
 	int name[2];
-	int error;
 
 #ifdef DEBUG
 	if (ldebug(setdomainname))
@@ -1711,11 +1706,8 @@ linux_setdomainname(struct thread *td, s
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_NISDOMAINNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, 0, 0, 0, args->name,
-	    args->len, 0, 0);
-	mtx_unlock(&Giant);
-	return (error);
+	return (userland_sysctl(td, name, 2, 0, 0, 0, args->name,
+	    args->len, 0, 0));
 }
 
 int

Modified: head/sys/i386/ibcs2/ibcs2_sysi86.c
==============================================================================
--- head/sys/i386/ibcs2/ibcs2_sysi86.c	Mon Dec 29 12:45:11 2008	(r186563)
+++ head/sys/i386/ibcs2/ibcs2_sysi86.c	Mon Dec 29 12:58:45 2008	(r186564)
@@ -74,15 +74,11 @@ ibcs2_sysi86(struct thread *td, struct i
 
 	case SETNAME:  {  /* set hostname given string w/ len <= 7 chars */
 	        int name[2];
-	        int error;
 
 		name[0] = CTL_KERN;
 		name[1] = KERN_HOSTNAME;
-		mtx_lock(&Giant);
-		error = userland_sysctl(td, name, 2, 0, 0, 0, 
-		    args->arg, 7, 0, 0);
-		mtx_unlock(&Giant);
-		return (error);
+		return (userland_sysctl(td, name, 2, 0, 0, 0, 
+		    args->arg, 7, 0, 0));
 	}
 
 	case SI86_MEM:	/* size of physical memory */

Modified: head/sys/kern/kern_sysctl.c
==============================================================================
--- head/sys/kern/kern_sysctl.c	Mon Dec 29 12:45:11 2008	(r186563)
+++ head/sys/kern/kern_sysctl.c	Mon Dec 29 12:58:45 2008	(r186564)
@@ -71,6 +71,7 @@ static struct sx sysctllock;
 
 #define	SYSCTL_LOCK()		sx_xlock(&sysctllock)
 #define	SYSCTL_UNLOCK()		sx_xunlock(&sysctllock)
+#define	SYSCTL_LOCK_ASSERT()	sx_assert(&sysctllock, SX_XLOCKED)
 #define	SYSCTL_INIT()		sx_init(&sysctllock, "sysctl lock")
 
 static int sysctl_root(SYSCTL_HANDLER_ARGS);
@@ -686,6 +687,8 @@ name2oid (char *name, int *oid, int *len
 	struct sysctl_oid_list *lsp = &sysctl__children;
 	char *p;
 
+	SYSCTL_LOCK_ASSERT();
+
 	if (!*name)
 		return (ENOENT);
 
@@ -742,6 +745,8 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_AR
 	int error, oid[CTL_MAXNAME], len;
 	struct sysctl_oid *op = 0;
 
+	SYSCTL_LOCK_ASSERT();
+
 	if (!req->newlen) 
 		return (ENOENT);
 	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
@@ -1086,14 +1091,12 @@ kernel_sysctl(struct thread *td, int *na
 	req.lock = REQ_LOCKED;
 
 	SYSCTL_LOCK();
-
 	error = sysctl_root(0, name, namelen, &req);
+	SYSCTL_UNLOCK();
 
 	if (req.lock == REQ_WIRED && req.validlen > 0)
 		vsunlock(req.oldptr, req.validlen);
 
-	SYSCTL_UNLOCK();
-
 	if (error && error != ENOMEM)
 		return (error);
 
@@ -1118,6 +1121,11 @@ kernel_sysctlbyname(struct thread *td, c
 	oid[1] = 3;		/* name2oid */
 	oidlen = sizeof(oid);
 
+	/*
+	 * XXX: Prone to a possible race condition between lookup and
+	 * execution? Maybe put locking around it?
+	 */
+
 	error = kernel_sysctl(td, oid, 2, oid, &oidlen,
 	    (void *)name, strlen(name), &plen, flags);
 	if (error)
@@ -1270,6 +1278,8 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
 	struct sysctl_oid *oid;
 	int error, indx, lvl;
 
+	SYSCTL_LOCK_ASSERT();
+
 	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
 	if (error)
 		return (error);
@@ -1324,7 +1334,11 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
 	if (error != 0)
 		return (error);
 #endif
+
+	/* XXX: Handlers are not guaranteed to be Giant safe! */
+	mtx_lock(&Giant);
 	error = oid->oid_handler(oid, arg1, arg2, req);
+	mtx_unlock(&Giant);
 
 	return (error);
 }
@@ -1352,20 +1366,13 @@ __sysctl(struct thread *td, struct sysct
  	if (error)
 		return (error);
 
-	mtx_lock(&Giant);
-
 	error = userland_sysctl(td, name, uap->namelen,
 		uap->old, uap->oldlenp, 0,
 		uap->new, uap->newlen, &j, 0);
 	if (error && error != ENOMEM)
-		goto done2;
-	if (uap->oldlenp) {
-		int i = copyout(&j, uap->oldlenp, sizeof(j));
-		if (i)
-			error = i;
-	}
-done2:
-	mtx_unlock(&Giant);
+		return (error);
+	if (uap->oldlenp)
+		error = copyout(&j, uap->oldlenp, sizeof(j));
 	return (error);
 }
 
@@ -1426,12 +1433,12 @@ userland_sysctl(struct thread *td, int *
 		uio_yield();
 	}
 
-	if (req.lock == REQ_WIRED && req.validlen > 0)
-		vsunlock(req.oldptr, req.validlen);
-
 	CURVNET_RESTORE();
 	SYSCTL_UNLOCK();
 
+	if (req.lock == REQ_WIRED && req.validlen > 0)
+		vsunlock(req.oldptr, req.validlen);
+
 	if (error && error != ENOMEM)
 		return (error);
 
@@ -1519,8 +1526,6 @@ ogetkerninfo(struct thread *td, struct g
 	size_t size;
 	u_int needed = 0;
 
-	mtx_lock(&Giant);
-
 	switch (uap->op & 0xff00) {
 
 	case KINFO_RT:
@@ -1653,7 +1658,6 @@ ogetkerninfo(struct thread *td, struct g
 			error = copyout(&size, uap->size, sizeof(size));
 		}
 	}
-	mtx_unlock(&Giant);
 	return (error);
 }
 #endif /* COMPAT_43 */

Modified: head/sys/kern/kern_xxx.c
==============================================================================
--- head/sys/kern/kern_xxx.c	Mon Dec 29 12:45:11 2008	(r186563)
+++ head/sys/kern/kern_xxx.c	Mon Dec 29 12:58:45 2008	(r186564)
@@ -62,16 +62,12 @@ ogethostname(td, uap)
 	struct gethostname_args *uap;
 {
 	int name[2];
-	int error;
 	size_t len = uap->len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_HOSTNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, uap->hostname, &len,
-	    1, 0, 0, 0, 0);
-	mtx_unlock(&Giant);
-	return(error);
+	return (userland_sysctl(td, name, 2, uap->hostname, &len,
+	    1, 0, 0, 0, 0));
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -91,11 +87,8 @@ osethostname(td, uap)
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_HOSTNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, 0, 0, 0, uap->hostname,
-	    uap->len, 0, 0);
-	mtx_unlock(&Giant);
-	return (error);
+	return (userland_sysctl(td, name, 2, 0, 0, 0, uap->hostname,
+	    uap->len, 0, 0));
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -173,11 +166,10 @@ freebsd4_uname(struct thread *td, struct
 	name[0] = CTL_KERN;
 	name[1] = KERN_OSTYPE;
 	len = sizeof (uap->name->sysname);
-	mtx_lock(&Giant);
 	error = userland_sysctl(td, name, 2, uap->name->sysname, &len, 
 		1, 0, 0, 0, 0);
 	if (error)
-		goto done2;
+		return (error);
 	subyte( uap->name->sysname + sizeof(uap->name->sysname) - 1, 0);
 
 	name[1] = KERN_HOSTNAME;
@@ -185,7 +177,7 @@ freebsd4_uname(struct thread *td, struct
 	error = userland_sysctl(td, name, 2, uap->name->nodename, &len, 
 		1, 0, 0, 0, 0);
 	if (error)
-		goto done2;
+		return (error);
 	subyte( uap->name->nodename + sizeof(uap->name->nodename) - 1, 0);
 
 	name[1] = KERN_OSRELEASE;
@@ -193,7 +185,7 @@ freebsd4_uname(struct thread *td, struct
 	error = userland_sysctl(td, name, 2, uap->name->release, &len, 
 		1, 0, 0, 0, 0);
 	if (error)
-		goto done2;
+		return (error);
 	subyte( uap->name->release + sizeof(uap->name->release) - 1, 0);
 
 /*
@@ -202,7 +194,7 @@ freebsd4_uname(struct thread *td, struct
 	error = userland_sysctl(td, name, 2, uap->name->version, &len, 
 		1, 0, 0, 0, 0);
 	if (error)
-		goto done2;
+		return (error);
 	subyte( uap->name->version + sizeof(uap->name->version) - 1, 0);
 */
 
@@ -214,11 +206,11 @@ freebsd4_uname(struct thread *td, struct
 	for(us = uap->name->version; *s && *s != ':'; s++) {
 		error = subyte( us++, *s);
 		if (error)
-			goto done2;
+			return (error);
 	}
 	error = subyte( us++, 0);
 	if (error)
-		goto done2;
+		return (error);
 
 	name[0] = CTL_HW;
 	name[1] = HW_MACHINE;
@@ -226,11 +218,9 @@ freebsd4_uname(struct thread *td, struct
 	error = userland_sysctl(td, name, 2, uap->name->machine, &len, 
 		1, 0, 0, 0, 0);
 	if (error)
-		goto done2;
+		return (error);
 	subyte( uap->name->machine + sizeof(uap->name->machine) - 1, 0);
-done2:
-	mtx_unlock(&Giant);
-	return (error);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -245,16 +235,12 @@ freebsd4_getdomainname(struct thread *td
     struct freebsd4_getdomainname_args *uap)
 {
 	int name[2];
-	int error;
 	size_t len = uap->len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_NISDOMAINNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, uap->domainname, &len,
-	    1, 0, 0, 0, 0);
-	mtx_unlock(&Giant);
-	return(error);
+	return (userland_sysctl(td, name, 2, uap->domainname, &len,
+	    1, 0, 0, 0, 0));
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -269,14 +255,10 @@ freebsd4_setdomainname(struct thread *td
     struct freebsd4_setdomainname_args *uap)
 {
 	int name[2];
-	int error;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_NISDOMAINNAME;
-	mtx_lock(&Giant);
-	error = userland_sysctl(td, name, 2, 0, 0, 0, uap->domainname,
-	    uap->len, 0, 0);
-	mtx_unlock(&Giant);
-	return (error);
+	return (userland_sysctl(td, name, 2, 0, 0, 0, uap->domainname,
+	    uap->len, 0, 0));
 }
 #endif /* COMPAT_FREEBSD4 */


More information about the svn-src-head mailing list