summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r--sys/kern/kern_sysctl.c42
1 files changed, 23 insertions, 19 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index a094d42..82d3a7c 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -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 **oidpp)
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_ARGS)
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 *name, u_int namelen, void *old,
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, char *name, void *old, size_t *oldlenp,
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 sysctl_args *uap)
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 *name, u_int namelen, void *old,
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 getkerninfo_args *uap)
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 getkerninfo_args *uap)
error = copyout(&size, uap->size, sizeof(size));
}
}
- mtx_unlock(&Giant);
return (error);
}
#endif /* COMPAT_43 */
OpenPOWER on IntegriCloud