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.c32
1 files changed, 14 insertions, 18 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 07624e6..e26dbc7 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -881,28 +881,24 @@ retry:
int
sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
{
- int error;
- void *tmparg;
+ int error, tries;
+ u_int generation;
/*
- * Attempt to get a coherent snapshot, either by wiring the
- * user space buffer or copying to a temporary kernel buffer
- * depending on the size of the data.
+ * Attempt to get a coherent snapshot, by using the thread
+ * pre-emption counter updated from within mi_switch() to
+ * determine if we were pre-empted during a bcopy() or
+ * copyout(). Make 3 attempts at doing this before giving up.
+ * If we encounter an error, stop immediately.
*/
- if (arg2 > PAGE_SIZE) {
-#if 0
- sysctl_wire_old_buffer(req, arg2);
-#endif
+ tries = 0;
+ do {
+ generation = curthread->td_generation;
error = SYSCTL_OUT(req, arg1, arg2);
- } else {
- tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK);
- bcopy(arg1, tmparg, arg2);
- error = SYSCTL_OUT(req, tmparg, arg2);
- free(tmparg, M_SYSCTLTMP);
- }
-
- if (error || !req->newptr)
- return (error);
+ if (error)
+ return (error);
+ tries++;
+ } while (generation != curthread->td_generation && tries < 3);
error = SYSCTL_IN(req, arg1, arg2);
OpenPOWER on IntegriCloud