summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2004-03-16 06:53:03 +0000
committertruckman <truckman@FreeBSD.org>2004-03-16 06:53:03 +0000
commit3c4fad0869664ea6deed5d1f4e86560376db97da (patch)
treea6e0cbaeb32bc5ac4be7f32b3e010255a6ba46d8 /sys/kern
parent82bae980d54105229d205178fcc40f41b6ca9d6b (diff)
downloadFreeBSD-src-3c4fad0869664ea6deed5d1f4e86560376db97da.zip
FreeBSD-src-3c4fad0869664ea6deed5d1f4e86560376db97da.tar.gz
Rename the wiredlen member of struct sysctl_req to validlen and always
set it to avoid the need for a bunch of code that tests whether or not the lock member is set to REQ_WIRED in order to determine which length member should be used. Fix another bug in the oldlen return value code. Fix a potential wired memory leak if a sysctl handler uses sysctl_wire_old_buffer() and returns an EAGAIN error to trigger a retry.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_sysctl.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index de5152e..59a630f 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -981,6 +981,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
if (oldlenp) {
req.oldlen = *oldlenp;
}
+ req.validlen = req.oldlen;
if (old) {
req.oldptr= old;
@@ -999,8 +1000,8 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
error = sysctl_root(0, name, namelen, &req);
- if (req.lock == REQ_WIRED && req.wiredlen > 0)
- vsunlock(req.oldptr, req.wiredlen);
+ if (req.lock == REQ_WIRED && req.validlen > 0)
+ vsunlock(req.oldptr, req.validlen);
SYSCTL_UNLOCK();
@@ -1008,8 +1009,8 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
return (error);
if (retval) {
- if (req.oldptr && req.oldidx > req.oldlen)
- *retval = req.oldlen;
+ if (req.oldptr && req.oldidx > req.validlen)
+ *retval = req.validlen;
else
*retval = req.oldidx;
}
@@ -1055,7 +1056,7 @@ sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"sysctl_old_user()");
i = l;
- len = (req->lock == REQ_WIRED) ? req->wiredlen : req->oldlen;
+ len = req->validlen;
if (len <= origidx)
i = 0;
else {
@@ -1108,7 +1109,7 @@ sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
return (ret);
}
req->lock = REQ_WIRED;
- req->wiredlen = wiredlen;
+ req->validlen = wiredlen;
}
return (0);
}
@@ -1278,7 +1279,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
{
int error = 0;
- struct sysctl_req req, req2;
+ struct sysctl_req req;
bzero(&req, sizeof req);
@@ -1293,6 +1294,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
return (error);
}
}
+ req.validlen = req.oldlen;
if (old) {
if (!useracc(old, req.oldlen, VM_PROT_WRITE))
@@ -1314,13 +1316,13 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
SYSCTL_LOCK();
do {
- req2 = req;
- error = sysctl_root(0, name, namelen, &req2);
+ req.oldidx = 0;
+ req.newidx = 0;
+ error = sysctl_root(0, name, namelen, &req);
} while (error == EAGAIN);
- req = req2;
- if (req.lock == REQ_WIRED && req.wiredlen > 0)
- vsunlock(req.oldptr, req.wiredlen);
+ if (req.lock == REQ_WIRED && req.validlen > 0)
+ vsunlock(req.oldptr, req.validlen);
SYSCTL_UNLOCK();
@@ -1328,8 +1330,8 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
return (error);
if (retval) {
- if (req.oldptr && req.oldidx > req.oldlen)
- *retval = req.oldlen;
+ if (req.oldptr && req.oldidx > req.validlen)
+ *retval = req.validlen;
else
*retval = req.oldidx;
}
OpenPOWER on IntegriCloud