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.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index e23a591..62f87e7 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -980,7 +980,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)
- vsunlock(req.oldptr, req.oldlen);
+ kern_munlock(req.td, (vm_offset_t)req.oldptr,
+ (vm_size_t)req.wiredlen);
SYSCTL_UNLOCK();
@@ -1025,26 +1026,27 @@ static int
sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
{
int error = 0;
- size_t i = 0;
+ size_t i, len, origidx;
- if (req->lock == REQ_LOCKED && req->oldptr)
+ origidx = req->oldidx;
+ req->oldidx += l;
+ if (req->oldptr == NULL)
+ return (0);
+ if (req->lock == REQ_LOCKED)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"sysctl_old_user()");
- if (req->oldptr) {
- i = l;
- if (req->oldlen <= req->oldidx)
- i = 0;
- else
- if (i > req->oldlen - req->oldidx)
- i = req->oldlen - req->oldidx;
- if (i > 0)
- error = copyout(p, (char *)req->oldptr + req->oldidx,
- i);
+ i = l;
+ len = (req->lock == REQ_WIRED) ? req->wiredlen : req->oldlen;
+ if (len <= origidx)
+ i = 0;
+ else {
+ if (i > len - origidx)
+ i = len - origidx;
+ error = copyout(p, (char *)req->oldptr + origidx, i);
}
- req->oldidx += l;
if (error)
return (error);
- if (req->oldptr && i < l)
+ if (i < l)
return (ENOMEM);
return (0);
}
@@ -1071,14 +1073,24 @@ sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
* a place to save it in the sysctl_req structure so that the matching
* amount of memory can be unwired in the sysctl exit code.
*/
-void
+int
sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
{
+ int ret;
+ size_t wiredlen;
+
+ wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen;
+ ret = 0;
if (req->lock == REQ_LOCKED && req->oldptr &&
req->oldfunc == sysctl_old_user) {
- vslock(req->oldptr, req->oldlen);
- req->lock = REQ_WIRED;
+ ret = kern_mlock(req->td, (vm_offset_t)req->oldptr,
+ (vm_size_t)wiredlen);
+ if (ret == 0) {
+ req->lock = REQ_WIRED;
+ req->wiredlen = wiredlen;
+ }
}
+ return (ret);
}
int
@@ -1288,7 +1300,8 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
req = req2;
if (req.lock == REQ_WIRED)
- vsunlock(req.oldptr, req.oldlen);
+ kern_munlock(req.td, (vm_offset_t)req.oldptr,
+ (vm_size_t)req.wiredlen);
SYSCTL_UNLOCK();
OpenPOWER on IntegriCloud