diff options
author | Don Lewis <truckman@FreeBSD.org> | 2004-03-16 06:53:03 +0000 |
---|---|---|
committer | Don Lewis <truckman@FreeBSD.org> | 2004-03-16 06:53:03 +0000 |
commit | a961520c13749c4029f0b4f4863a3bc425b388fe (patch) | |
tree | a6e0cbaeb32bc5ac4be7f32b3e010255a6ba46d8 /sys/kern/kern_sysctl.c | |
parent | 9c0ab25d6e9810db9edf7f25cad52c5acd78f0fa (diff) | |
download | src-a961520c13749c4029f0b4f4863a3bc425b388fe.tar.gz src-a961520c13749c4029f0b4f4863a3bc425b388fe.zip |
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.
Notes
Notes:
svn path=/head/; revision=127052
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r-- | sys/kern/kern_sysctl.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index de5152e78d42..59a630f97a2b 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; } |