aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_sysctl.c
diff options
context:
space:
mode:
authorGlen Barber <gjb@FreeBSD.org>2014-06-27 22:05:21 +0000
committerGlen Barber <gjb@FreeBSD.org>2014-06-27 22:05:21 +0000
commit37a107a407cdb47ee0f4c4337e369e9973b34076 (patch)
treefce5301b062a855bc68b9cb76c6b5966c5a2acbe /sys/kern/kern_sysctl.c
parentd2f1b8f4d2975ca1ec3e7519f9d755af40f357e0 (diff)
downloadsrc-37a107a407cdb47ee0f4c4337e369e9973b34076.tar.gz
src-37a107a407cdb47ee0f4c4337e369e9973b34076.zip
Revert r267961, r267973:
These changes prevent sysctl(8) from returning proper output, such as: 1) no output from sysctl(8) 2) erroneously returning ENOMEM with tools like truss(1) or uname(1) truss: can not get etype: Cannot allocate memory
Notes
Notes: svn path=/head/; revision=267985
Diffstat (limited to 'sys/kern/kern_sysctl.c')
-rw-r--r--sys/kern/kern_sysctl.c193
1 files changed, 44 insertions, 149 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index cb5a266e4e21..fec4aeabe1f5 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -98,13 +98,10 @@ static struct sx sysctlmemlock;
static int sysctl_root(SYSCTL_HANDLER_ARGS);
-/* Root list */
-struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children);
+struct sysctl_oid_list sysctl__children; /* root list */
static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
int recurse);
-static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
-static int sysctl_new_kernel(struct sysctl_req *, void *, size_t);
static struct sysctl_oid *
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
@@ -139,118 +136,6 @@ sysctl_unlock(void)
SYSCTL_XUNLOCK();
}
-static int
-sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2,
- struct sysctl_req *req)
-{
- int error;
-
- oid->oid_running++;
- SYSCTL_XUNLOCK();
-
- if (!(oid->oid_kind & CTLFLAG_MPSAFE))
- mtx_lock(&Giant);
- error = oid->oid_handler(oid, arg1, arg2, req);
- if (!(oid->oid_kind & CTLFLAG_MPSAFE))
- mtx_unlock(&Giant);
-
- SYSCTL_XLOCK();
- oid->oid_running--;
- if (oid->oid_running == 0 && (oid->oid_kind & CTLFLAG_DYING) != 0)
- wakeup(&oid->oid_running);
-
- return (error);
-}
-
-static void
-sysctl_load_tunable_by_oid_locked(struct sysctl_oid *oidp)
-{
- struct sysctl_req req;
- struct sysctl_oid *curr;
- char *penv;
- char path[64];
- ssize_t rem = sizeof(path);
- ssize_t len;
- int val_int;
- long val_long;
- int64_t val_64;
- int error;
-
- path[--rem] = 0;
-
- for (curr = oidp; curr != NULL; curr = SYSCTL_PARENT(curr)) {
- len = strlen(curr->oid_name);
- rem -= len;
- if (curr != oidp)
- rem -= 1;
- if (rem < 0) {
- printf("OID path exceeds %d bytes\n", (int)sizeof(path));
- return;
- }
- memcpy(path + rem, curr->oid_name, len);
- if (curr != oidp)
- path[rem + len] = '.';
- }
-
- penv = getenv(path + rem);
- if (penv == NULL)
- return;
-
- memset(&req, 0, sizeof(req));
-
- req.td = curthread;
- req.oldfunc = sysctl_old_kernel;
- req.newfunc = sysctl_new_kernel;
- req.lock = REQ_UNWIRED;
-
- switch (oidp->oid_kind & CTLTYPE) {
- case CTLTYPE_INT:
- val_int = strtoq(penv, NULL, 0);
- req.newlen = sizeof(val_int);
- req.newptr = &val_int;
- break;
- case CTLTYPE_UINT:
- val_int = strtouq(penv, NULL, 0);
- req.newlen = sizeof(val_int);
- req.newptr = &val_int;
- break;
- case CTLTYPE_LONG:
- val_long = strtoq(penv, NULL, 0);
- req.newlen = sizeof(val_long);
- req.newptr = &val_long;
- break;
- case CTLTYPE_ULONG:
- val_long = strtouq(penv, NULL, 0);
- req.newlen = sizeof(val_long);
- req.newptr = &val_long;
- break;
- case CTLTYPE_S64:
- val_64 = strtoq(penv, NULL, 0);
- req.newlen = sizeof(val_64);
- req.newptr = &val_64;
- break;
- case CTLTYPE_U64:
- val_64 = strtouq(penv, NULL, 0);
- req.newlen = sizeof(val_64);
- req.newptr = &val_64;
- break;
- case CTLTYPE_STRING:
- req.newlen = strlen(penv);
- req.newptr = penv;
- break;
- default:
- freeenv(penv);
- return;
- }
- error = sysctl_root_handler_locked(oidp, oidp->oid_arg1,
- oidp->oid_arg2, &req);
- if (error != 0) {
- printf("Setting sysctl '%s' to '%s' failed: %d\n",
- path, penv, error);
- }
- freeenv(penv);
-}
-
void
sysctl_register_oid(struct sysctl_oid *oidp)
{
@@ -307,15 +192,6 @@ sysctl_register_oid(struct sysctl_oid *oidp)
SLIST_INSERT_AFTER(q, oidp, oid_link);
else
SLIST_INSERT_HEAD(parent, oidp, oid_link);
-
- if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE &&
-#ifdef VIMAGE
- (oidp->oid_kind & CTLFLAG_VNET) == 0 &&
-#endif
- (oidp->oid_kind & CTLFLAG_TUN) != 0 &&
- (oidp->oid_kind & CTLFLAG_NOFETCH) == 0) {
- sysctl_load_tunable_by_oid_locked(oidp);
- }
}
void
@@ -547,6 +423,8 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
if (error)
return (error);
}
+ if (del)
+ free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
}
}
if (oidp->oid_refcnt > 1 ) {
@@ -611,16 +489,24 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
}
oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
oidp->oid_parent = parent;
- SLIST_INIT(&oidp->oid_children);
+ SLIST_NEXT(oidp, oid_link) = NULL;
oidp->oid_number = number;
oidp->oid_refcnt = 1;
oidp->oid_name = strdup(name, M_SYSCTLOID);
oidp->oid_handler = handler;
oidp->oid_kind = CTLFLAG_DYN | kind;
- oidp->oid_arg1 = arg1;
- oidp->oid_arg2 = arg2;
+ if ((kind & CTLTYPE) == CTLTYPE_NODE) {
+ /* Allocate space for children */
+ SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list),
+ M_SYSCTLOID, M_WAITOK));
+ SLIST_INIT(SYSCTL_CHILDREN(oidp));
+ oidp->oid_arg2 = arg2;
+ } else {
+ oidp->oid_arg1 = arg1;
+ oidp->oid_arg2 = arg2;
+ }
oidp->oid_fmt = fmt;
- if (descr != NULL)
+ if (descr)
oidp->oid_descr = strdup(descr, M_SYSCTLOID);
/* Update the context, if used */
if (clist != NULL)
@@ -691,7 +577,7 @@ sysctl_register_all(void *arg)
sysctl_register_oid(*oidp);
SYSCTL_XUNLOCK();
}
-SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, 0);
+SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
/*
* "Staff-functions"
@@ -739,7 +625,7 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
printf(" Node\n");
if (!oidp->oid_handler) {
sysctl_sysctl_debug_dump_node(
- SYSCTL_CHILDREN(oidp), i + 2);
+ oidp->oid_arg1, i+2);
}
break;
case CTLTYPE_INT: printf(" Int\n"); break;
@@ -1207,28 +1093,26 @@ sysctl_handle_64(SYSCTL_HANDLER_ARGS)
int
sysctl_handle_string(SYSCTL_HANDLER_ARGS)
{
+ int error=0;
+ char *tmparg;
size_t outlen;
- int error = 0;
- /* check for zero-length buffer */
- if (arg2 == 0)
- return (ENOMEM);
-
- if (req->oldptr != NULL) {
- char *tmparg;
-
- /* try to make a coherent snapshot of the string */
- tmparg = malloc(arg2, M_SYSCTLTMP, M_WAITOK);
- memcpy(tmparg, arg1, arg2);
-
- outlen = strnlen(tmparg, arg2 - 1) + 1;
- error = SYSCTL_OUT(req, tmparg, outlen);
+ /*
+ * Attempt to get a coherent snapshot by copying to a
+ * temporary kernel buffer.
+ */
+retry:
+ outlen = strlen((char *)arg1)+1;
+ tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
+ if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
free(tmparg, M_SYSCTLTMP);
- } else {
- outlen = strnlen((char *)arg1, arg2 - 1) + 1;
- error = SYSCTL_OUT(req, NULL, outlen);
+ goto retry;
}
+
+ error = SYSCTL_OUT(req, tmparg, outlen);
+ free(tmparg, M_SYSCTLTMP);
+
if (error || !req->newptr)
return (error);
@@ -1239,6 +1123,7 @@ sysctl_handle_string(SYSCTL_HANDLER_ARGS)
error = SYSCTL_IN(req, arg1, arg2);
((char *)arg1)[arg2] = '\0';
}
+
return (error);
}
@@ -1604,14 +1489,24 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
if (error != 0)
return (error);
#endif
+ oid->oid_running++;
+ SYSCTL_XUNLOCK();
#ifdef VIMAGE
if ((oid->oid_kind & CTLFLAG_VNET) && arg1 != NULL)
arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
#endif
- error = sysctl_root_handler_locked(oid, arg1, arg2, req);
+ if (!(oid->oid_kind & CTLFLAG_MPSAFE))
+ mtx_lock(&Giant);
+ error = oid->oid_handler(oid, arg1, arg2, req);
+ if (!(oid->oid_kind & CTLFLAG_MPSAFE))
+ mtx_unlock(&Giant);
KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error);
+ SYSCTL_XLOCK();
+ oid->oid_running--;
+ if (oid->oid_running == 0 && (oid->oid_kind & CTLFLAG_DYING) != 0)
+ wakeup(&oid->oid_running);
return (error);
}