Revert r285125 until rmlocks get fixed.
Right now there is a chance that sysctl unregister will cause reader to block on the sx lock associated with sysctl rmlock, in which case kernels with debug enabled will panic.
This commit is contained in:
parent
4ed2d460bd
commit
4ae1e3c752
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=286094
@ -292,10 +292,10 @@ linker_file_register_sysctls(linker_file_t lf)
|
||||
return;
|
||||
|
||||
sx_xunlock(&kld_sx);
|
||||
sysctl_wlock();
|
||||
sysctl_xlock();
|
||||
for (oidp = start; oidp < stop; oidp++)
|
||||
sysctl_register_oid(*oidp);
|
||||
sysctl_wunlock();
|
||||
sysctl_xunlock();
|
||||
sx_xlock(&kld_sx);
|
||||
}
|
||||
|
||||
@ -313,10 +313,10 @@ linker_file_unregister_sysctls(linker_file_t lf)
|
||||
return;
|
||||
|
||||
sx_xunlock(&kld_sx);
|
||||
sysctl_wlock();
|
||||
sysctl_xlock();
|
||||
for (oidp = start; oidp < stop; oidp++)
|
||||
sysctl_unregister_oid(*oidp);
|
||||
sysctl_wunlock();
|
||||
sysctl_xunlock();
|
||||
sx_xlock(&kld_sx);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/jail.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rmlock.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysproto.h>
|
||||
@ -78,7 +77,7 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
|
||||
* The sysctllock protects the MIB tree. It also protects sysctl
|
||||
* contexts used with dynamic sysctls. The sysctl_register_oid() and
|
||||
* sysctl_unregister_oid() routines require the sysctllock to already
|
||||
* be held, so the sysctl_wlock() and sysctl_wunlock() routines are
|
||||
* be held, so the sysctl_xlock() and sysctl_xunlock() routines are
|
||||
* provided for the few places in the kernel which need to use that
|
||||
* API rather than using the dynamic API. Use of the dynamic API is
|
||||
* strongly encouraged for most code.
|
||||
@ -87,21 +86,20 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
|
||||
* sysctl requests. This is implemented by serializing any userland
|
||||
* sysctl requests larger than a single page via an exclusive lock.
|
||||
*/
|
||||
static struct rmlock sysctllock;
|
||||
static struct sx sysctllock;
|
||||
static struct sx sysctlmemlock;
|
||||
|
||||
#define SYSCTL_WLOCK() rm_wlock(&sysctllock)
|
||||
#define SYSCTL_WUNLOCK() rm_wunlock(&sysctllock)
|
||||
#define SYSCTL_RLOCK(tracker) rm_rlock(&sysctllock, (tracker))
|
||||
#define SYSCTL_RUNLOCK(tracker) rm_runlock(&sysctllock, (tracker))
|
||||
#define SYSCTL_WLOCKED() rm_wowned(&sysctllock)
|
||||
#define SYSCTL_ASSERT_LOCKED() rm_assert(&sysctllock, RA_LOCKED)
|
||||
#define SYSCTL_ASSERT_WLOCKED() rm_assert(&sysctllock, RA_WLOCKED)
|
||||
#define SYSCTL_ASSERT_RLOCKED() rm_assert(&sysctllock, RA_RLOCKED)
|
||||
#define SYSCTL_INIT() rm_init_flags(&sysctllock, "sysctl lock", \
|
||||
RM_SLEEPABLE)
|
||||
#define SYSCTL_XLOCK() sx_xlock(&sysctllock)
|
||||
#define SYSCTL_XUNLOCK() sx_xunlock(&sysctllock)
|
||||
#define SYSCTL_SLOCK() sx_slock(&sysctllock)
|
||||
#define SYSCTL_SUNLOCK() sx_sunlock(&sysctllock)
|
||||
#define SYSCTL_XLOCKED() sx_xlocked(&sysctllock)
|
||||
#define SYSCTL_ASSERT_LOCKED() sx_assert(&sysctllock, SA_LOCKED)
|
||||
#define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
|
||||
#define SYSCTL_ASSERT_SLOCKED() sx_assert(&sysctllock, SA_SLOCKED)
|
||||
#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock")
|
||||
#define SYSCTL_SLEEP(ch, wmesg, timo) \
|
||||
rm_sleep(ch, &sysctllock, 0, wmesg, timo)
|
||||
sx_sleep(ch, &sysctllock, 0, wmesg, timo)
|
||||
|
||||
static int sysctl_root(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
@ -113,6 +111,29 @@ static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
|
||||
static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
|
||||
static int sysctl_new_kernel(struct sysctl_req *, void *, size_t);
|
||||
|
||||
static void
|
||||
sysctl_lock(bool xlock)
|
||||
{
|
||||
|
||||
if (xlock)
|
||||
SYSCTL_XLOCK();
|
||||
else
|
||||
SYSCTL_SLOCK();
|
||||
}
|
||||
|
||||
static bool
|
||||
sysctl_unlock(void)
|
||||
{
|
||||
bool xlocked;
|
||||
|
||||
xlocked = SYSCTL_XLOCKED();
|
||||
if (xlocked)
|
||||
SYSCTL_XUNLOCK();
|
||||
else
|
||||
SYSCTL_SUNLOCK();
|
||||
return (xlocked);
|
||||
}
|
||||
|
||||
static struct sysctl_oid *
|
||||
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
|
||||
{
|
||||
@ -133,32 +154,29 @@ sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
|
||||
* Order by number in each list.
|
||||
*/
|
||||
void
|
||||
sysctl_wlock(void)
|
||||
sysctl_xlock(void)
|
||||
{
|
||||
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
}
|
||||
|
||||
void
|
||||
sysctl_wunlock(void)
|
||||
sysctl_xunlock(void)
|
||||
{
|
||||
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2,
|
||||
struct sysctl_req *req, struct rm_priotracker *tracker)
|
||||
struct sysctl_req *req)
|
||||
{
|
||||
int error;
|
||||
bool xlocked;
|
||||
|
||||
if (oid->oid_kind & CTLFLAG_DYN)
|
||||
atomic_add_int(&oid->oid_running, 1);
|
||||
|
||||
if (tracker != NULL)
|
||||
SYSCTL_RUNLOCK(tracker);
|
||||
else
|
||||
SYSCTL_WUNLOCK();
|
||||
xlocked = sysctl_unlock();
|
||||
|
||||
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
|
||||
mtx_lock(&Giant);
|
||||
@ -166,11 +184,7 @@ sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2,
|
||||
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
if (tracker != NULL)
|
||||
SYSCTL_RLOCK(tracker);
|
||||
else
|
||||
SYSCTL_WLOCK();
|
||||
|
||||
sysctl_lock(xlocked);
|
||||
if (oid->oid_kind & CTLFLAG_DYN) {
|
||||
if (atomic_fetchadd_int(&oid->oid_running, -1) == 1 &&
|
||||
(oid->oid_kind & CTLFLAG_DYING) != 0)
|
||||
@ -269,7 +283,7 @@ sysctl_load_tunable_by_oid_locked(struct sysctl_oid *oidp)
|
||||
return;
|
||||
}
|
||||
error = sysctl_root_handler_locked(oidp, oidp->oid_arg1,
|
||||
oidp->oid_arg2, &req, NULL);
|
||||
oidp->oid_arg2, &req);
|
||||
if (error != 0)
|
||||
printf("Setting sysctl %s failed: %d\n", path + rem, error);
|
||||
if (penv != NULL)
|
||||
@ -289,7 +303,7 @@ sysctl_register_oid(struct sysctl_oid *oidp)
|
||||
* First check if another oid with the same name already
|
||||
* exists in the parent's list.
|
||||
*/
|
||||
SYSCTL_ASSERT_WLOCKED();
|
||||
SYSCTL_ASSERT_XLOCKED();
|
||||
p = sysctl_find_oidname(oidp->oid_name, parent);
|
||||
if (p != NULL) {
|
||||
if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
|
||||
@ -383,7 +397,7 @@ sysctl_unregister_oid(struct sysctl_oid *oidp)
|
||||
struct sysctl_oid *p;
|
||||
int error;
|
||||
|
||||
SYSCTL_ASSERT_WLOCKED();
|
||||
SYSCTL_ASSERT_XLOCKED();
|
||||
error = ENOENT;
|
||||
if (oidp->oid_number == OID_AUTO) {
|
||||
error = EINVAL;
|
||||
@ -439,7 +453,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
|
||||
* XXX This algorithm is a hack. But I don't know any
|
||||
* XXX better solution for now...
|
||||
*/
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
TAILQ_FOREACH(e, clist, link) {
|
||||
error = sysctl_remove_oid_locked(e->entry, 0, 0);
|
||||
if (error)
|
||||
@ -459,7 +473,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
|
||||
e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
|
||||
}
|
||||
if (error) {
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return(EBUSY);
|
||||
}
|
||||
/* Now really delete the entries */
|
||||
@ -473,7 +487,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
|
||||
free(e, M_SYSCTLOID);
|
||||
e = e1;
|
||||
}
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -483,7 +497,7 @@ sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
|
||||
{
|
||||
struct sysctl_ctx_entry *e;
|
||||
|
||||
SYSCTL_ASSERT_WLOCKED();
|
||||
SYSCTL_ASSERT_XLOCKED();
|
||||
if (clist == NULL || oidp == NULL)
|
||||
return(NULL);
|
||||
e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
|
||||
@ -498,7 +512,7 @@ sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
|
||||
{
|
||||
struct sysctl_ctx_entry *e;
|
||||
|
||||
SYSCTL_ASSERT_WLOCKED();
|
||||
SYSCTL_ASSERT_XLOCKED();
|
||||
if (clist == NULL || oidp == NULL)
|
||||
return(NULL);
|
||||
TAILQ_FOREACH(e, clist, link) {
|
||||
@ -520,15 +534,15 @@ sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
|
||||
|
||||
if (clist == NULL || oidp == NULL)
|
||||
return (EINVAL);
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
e = sysctl_ctx_entry_find(clist, oidp);
|
||||
if (e != NULL) {
|
||||
TAILQ_REMOVE(clist, e, link);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
free(e, M_SYSCTLOID);
|
||||
return (0);
|
||||
} else {
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (ENOENT);
|
||||
}
|
||||
}
|
||||
@ -544,9 +558,9 @@ sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
|
||||
{
|
||||
int error;
|
||||
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
error = sysctl_remove_oid_locked(oidp, del, recurse);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -558,14 +572,14 @@ sysctl_remove_name(struct sysctl_oid *parent, const char *name,
|
||||
int error;
|
||||
|
||||
error = ENOENT;
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
SLIST_FOREACH_SAFE(p, SYSCTL_CHILDREN(parent), oid_link, tmp) {
|
||||
if (strcmp(p->oid_name, name) == 0) {
|
||||
error = sysctl_remove_oid_locked(p, del, recurse);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -577,7 +591,7 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
|
||||
struct sysctl_oid *p, *tmp;
|
||||
int error;
|
||||
|
||||
SYSCTL_ASSERT_WLOCKED();
|
||||
SYSCTL_ASSERT_XLOCKED();
|
||||
if (oidp == NULL)
|
||||
return(EINVAL);
|
||||
if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
|
||||
@ -652,7 +666,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
|
||||
if (parent == NULL)
|
||||
return(NULL);
|
||||
/* Check if the node already exists, otherwise create it */
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
oidp = sysctl_find_oidname(name, parent);
|
||||
if (oidp != NULL) {
|
||||
if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
|
||||
@ -660,10 +674,10 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
|
||||
/* Update the context */
|
||||
if (clist != NULL)
|
||||
sysctl_ctx_entry_add(clist, oidp);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (oidp);
|
||||
} else {
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
printf("can't re-use a leaf (%s)!\n", name);
|
||||
return (NULL);
|
||||
}
|
||||
@ -686,7 +700,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
|
||||
sysctl_ctx_entry_add(clist, oidp);
|
||||
/* Register this oid */
|
||||
sysctl_register_oid(oidp);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (oidp);
|
||||
}
|
||||
|
||||
@ -700,10 +714,10 @@ sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
|
||||
char *oldname;
|
||||
|
||||
newname = strdup(name, M_SYSCTLOID);
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
oldname = __DECONST(char *, oidp->oid_name);
|
||||
oidp->oid_name = newname;
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
free(oldname, M_SYSCTLOID);
|
||||
}
|
||||
|
||||
@ -715,21 +729,21 @@ sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
|
||||
{
|
||||
struct sysctl_oid *oidp;
|
||||
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
if (oid->oid_parent == parent) {
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
oidp = sysctl_find_oidname(oid->oid_name, parent);
|
||||
if (oidp != NULL) {
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (EEXIST);
|
||||
}
|
||||
sysctl_unregister_oid(oid);
|
||||
oid->oid_parent = parent;
|
||||
oid->oid_number = OID_AUTO;
|
||||
sysctl_register_oid(oid);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -745,10 +759,10 @@ sysctl_register_all(void *arg)
|
||||
|
||||
sx_init(&sysctlmemlock, "sysctl mem");
|
||||
SYSCTL_INIT();
|
||||
SYSCTL_WLOCK();
|
||||
SYSCTL_XLOCK();
|
||||
SET_FOREACH(oidp, sysctl_set)
|
||||
sysctl_register_oid(*oidp);
|
||||
SYSCTL_WUNLOCK();
|
||||
SYSCTL_XUNLOCK();
|
||||
}
|
||||
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, 0);
|
||||
|
||||
@ -818,15 +832,14 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
|
||||
static int
|
||||
sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct rm_priotracker tracker;
|
||||
int error;
|
||||
|
||||
error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
|
||||
if (error)
|
||||
return (error);
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
@ -842,10 +855,9 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
|
||||
int error = 0;
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
|
||||
struct rm_priotracker tracker;
|
||||
char buf[10];
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
while (namelen) {
|
||||
if (!lsp) {
|
||||
snprintf(buf,sizeof(buf),"%d",*name);
|
||||
@ -888,7 +900,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
error = SYSCTL_OUT(req, "", 1);
|
||||
out:
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -967,12 +979,11 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
|
||||
int i, j, error;
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid_list *lsp = &sysctl__children;
|
||||
struct rm_priotracker tracker;
|
||||
int newoid[CTL_MAXNAME];
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
if (i)
|
||||
return (ENOENT);
|
||||
error = SYSCTL_OUT(req, newoid, j * sizeof (int));
|
||||
@ -1031,7 +1042,6 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
|
||||
char *p;
|
||||
int error, oid[CTL_MAXNAME], len = 0;
|
||||
struct sysctl_oid *op = 0;
|
||||
struct rm_priotracker tracker;
|
||||
|
||||
if (!req->newlen)
|
||||
return (ENOENT);
|
||||
@ -1048,9 +1058,9 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
p [req->newlen] = '\0';
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
error = name2oid(p, oid, &len, &op);
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
|
||||
free(p, M_SYSCTL);
|
||||
|
||||
@ -1073,10 +1083,9 @@ static int
|
||||
sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct sysctl_oid *oid;
|
||||
struct rm_priotracker tracker;
|
||||
int error;
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
|
||||
if (error)
|
||||
goto out;
|
||||
@ -1090,7 +1099,7 @@ sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
|
||||
goto out;
|
||||
error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
|
||||
out:
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1102,10 +1111,9 @@ static int
|
||||
sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct sysctl_oid *oid;
|
||||
struct rm_priotracker tracker;
|
||||
int error;
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_SLOCK();
|
||||
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
|
||||
if (error)
|
||||
goto out;
|
||||
@ -1116,7 +1124,7 @@ sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
|
||||
out:
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
SYSCTL_SUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1421,7 +1429,9 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
req.newfunc = sysctl_new_kernel;
|
||||
req.lock = REQ_UNWIRED;
|
||||
|
||||
SYSCTL_SLOCK();
|
||||
error = sysctl_root(0, name, namelen, &req);
|
||||
SYSCTL_SUNLOCK();
|
||||
|
||||
if (req.lock == REQ_WIRED && req.validlen > 0)
|
||||
vsunlock(req.oldptr, req.validlen);
|
||||
@ -1598,14 +1608,13 @@ static int
|
||||
sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct sysctl_oid *oid;
|
||||
struct rm_priotracker tracker;
|
||||
int error, indx, lvl;
|
||||
|
||||
SYSCTL_RLOCK(&tracker);
|
||||
SYSCTL_ASSERT_SLOCKED();
|
||||
|
||||
error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
|
||||
if (error)
|
||||
goto out;
|
||||
return (error);
|
||||
|
||||
if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
|
||||
/*
|
||||
@ -1613,17 +1622,13 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
* no handler. Inform the user that it's a node.
|
||||
* The indx may or may not be the same as namelen.
|
||||
*/
|
||||
if (oid->oid_handler == NULL) {
|
||||
error = EISDIR;
|
||||
goto out;
|
||||
}
|
||||
if (oid->oid_handler == NULL)
|
||||
return (EISDIR);
|
||||
}
|
||||
|
||||
/* Is this sysctl writable? */
|
||||
if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) {
|
||||
error = EPERM;
|
||||
goto out;
|
||||
}
|
||||
if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
|
||||
return (EPERM);
|
||||
|
||||
KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
|
||||
|
||||
@ -1633,11 +1638,10 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
* writing unless specifically granted for the node.
|
||||
*/
|
||||
if (IN_CAPABILITY_MODE(req->td)) {
|
||||
if ((req->oldptr && !(oid->oid_kind & CTLFLAG_CAPRD)) ||
|
||||
(req->newptr && !(oid->oid_kind & CTLFLAG_CAPWR))) {
|
||||
error = EPERM;
|
||||
goto out;
|
||||
}
|
||||
if (req->oldptr && !(oid->oid_kind & CTLFLAG_CAPRD))
|
||||
return (EPERM);
|
||||
if (req->newptr && !(oid->oid_kind & CTLFLAG_CAPWR))
|
||||
return (EPERM);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1646,7 +1650,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
|
||||
error = securelevel_gt(req->td->td_ucred, lvl);
|
||||
if (error)
|
||||
goto out;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Is this sysctl writable by only privileged users? */
|
||||
@ -1664,13 +1668,11 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
priv = PRIV_SYSCTL_WRITE;
|
||||
error = priv_check(req->td, priv);
|
||||
if (error)
|
||||
goto out;
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (!oid->oid_handler) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!oid->oid_handler)
|
||||
return (EINVAL);
|
||||
|
||||
if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
|
||||
arg1 = (int *)arg1 + indx;
|
||||
@ -1683,18 +1685,16 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
|
||||
error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2,
|
||||
req);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
return (error);
|
||||
#endif
|
||||
#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, &tracker);
|
||||
error = sysctl_root_handler_locked(oid, arg1, arg2, req);
|
||||
|
||||
KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error);
|
||||
|
||||
out:
|
||||
SYSCTL_RUNLOCK(&tracker);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -1794,7 +1794,9 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
for (;;) {
|
||||
req.oldidx = 0;
|
||||
req.newidx = 0;
|
||||
SYSCTL_SLOCK();
|
||||
error = sysctl_root(0, name, namelen, &req);
|
||||
SYSCTL_SUNLOCK();
|
||||
if (error != EAGAIN)
|
||||
break;
|
||||
kern_yield(PRI_USER);
|
||||
|
@ -291,7 +291,7 @@ vfs_register(struct vfsconf *vfc)
|
||||
* preserved by re-registering the oid after modifying its
|
||||
* number.
|
||||
*/
|
||||
sysctl_wlock();
|
||||
sysctl_xlock();
|
||||
SLIST_FOREACH(oidp, SYSCTL_CHILDREN(&sysctl___vfs), oid_link) {
|
||||
if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
|
||||
sysctl_unregister_oid(oidp);
|
||||
@ -300,7 +300,7 @@ vfs_register(struct vfsconf *vfc)
|
||||
break;
|
||||
}
|
||||
}
|
||||
sysctl_wunlock();
|
||||
sysctl_xunlock();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -807,8 +807,8 @@ int userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
size_t *retval, int flags);
|
||||
int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
|
||||
int *nindx, struct sysctl_req *req);
|
||||
void sysctl_wlock(void);
|
||||
void sysctl_wunlock(void);
|
||||
void sysctl_xlock(void);
|
||||
void sysctl_xunlock(void);
|
||||
int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);
|
||||
|
||||
struct sbuf;
|
||||
|
Loading…
Reference in New Issue
Block a user