summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2009-03-10 18:57:10 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2009-03-10 18:57:10 +0000
commit772cc2acbf3dda4f332de34d7fd26a14bb2821dc (patch)
treefb39df995a4815414e97633e67475be7aefd41fd
parentf68d8092dc0eb994f58ea423c3985551786ba3c2 (diff)
Notes
-rw-r--r--sys/cam/scsi/scsi_cd.c16
-rw-r--r--sys/cam/scsi/scsi_da.c8
-rw-r--r--sys/ia64/ia64/mca.c70
-rw-r--r--sys/ia64/include/mca.h1
-rw-r--r--sys/kern/kern_linker.c8
-rw-r--r--sys/kern/kern_sysctl.c124
-rw-r--r--sys/kern/vfs_init.c3
-rw-r--r--sys/sys/sysctl.h2
8 files changed, 166 insertions, 66 deletions
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 8eb353753aa8..a095d8225d1c 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -401,11 +401,6 @@ cdcleanup(struct cam_periph *periph)
xpt_print(periph->path, "removing device entry\n");
- if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
- && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
- xpt_print(periph->path, "can't remove sysctl context\n");
- }
-
/*
* In the queued, non-active case, the device in question
* has already been removed from the changer run queue. Since this
@@ -474,9 +469,14 @@ cdcleanup(struct cam_periph *periph)
free(softc->changer, M_DEVBUF);
}
cam_periph_unlock(periph);
+ if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
+ && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
+ xpt_print(periph->path, "can't remove sysctl context\n");
+ }
+
disk_destroy(softc->disk);
- cam_periph_lock(periph);
free(softc, M_DEVBUF);
+ cam_periph_lock(periph);
}
static void
@@ -555,8 +555,6 @@ cdsysctlinit(void *context, int pending)
snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
- mtx_lock(&Giant);
-
sysctl_ctx_init(&softc->sysctl_ctx);
softc->flags |= CD_FLAG_SCTX_INIT;
softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
@@ -565,7 +563,6 @@ cdsysctlinit(void *context, int pending)
if (softc->sysctl_tree == NULL) {
printf("cdsysctlinit: unable to allocate sysctl tree\n");
- mtx_unlock(&Giant);
cam_periph_release(periph);
return;
}
@@ -579,7 +576,6 @@ cdsysctlinit(void *context, int pending)
&softc->minimum_command_size, 0, cdcmdsizesysctl, "I",
"Minimum CDB size");
- mtx_unlock(&Giant);
cam_periph_release(periph);
}
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 7fa62189ba76..81391542d53e 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -987,6 +987,8 @@ dacleanup(struct cam_periph *periph)
softc = (struct da_softc *)periph->softc;
xpt_print(periph->path, "removing device entry\n");
+ cam_periph_unlock(periph);
+
/*
* If we can't free the sysctl tree, oh well...
*/
@@ -995,11 +997,10 @@ dacleanup(struct cam_periph *periph)
xpt_print(periph->path, "can't remove sysctl context\n");
}
- cam_periph_unlock(periph);
disk_destroy(softc->disk);
callout_drain(&softc->sendordered_c);
- cam_periph_lock(periph);
free(softc, M_DEVBUF);
+ cam_periph_lock(periph);
}
static void
@@ -1078,7 +1079,6 @@ dasysctlinit(void *context, int pending)
snprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number);
snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
- mtx_lock(&Giant);
sysctl_ctx_init(&softc->sysctl_ctx);
softc->flags |= DA_FLAG_SCTX_INIT;
softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
@@ -1086,7 +1086,6 @@ dasysctlinit(void *context, int pending)
CTLFLAG_RD, 0, tmpstr);
if (softc->sysctl_tree == NULL) {
printf("dasysctlinit: unable to allocate sysctl tree\n");
- mtx_unlock(&Giant);
cam_periph_release(periph);
return;
}
@@ -1100,7 +1099,6 @@ dasysctlinit(void *context, int pending)
&softc->minimum_cmd_size, 0, dacmdsizesysctl, "I",
"Minimum CDB size");
- mtx_unlock(&Giant);
cam_periph_release(periph);
}
diff --git a/sys/ia64/ia64/mca.c b/sys/ia64/ia64/mca.c
index bba0bfbe7e1d..e25031dec73f 100644
--- a/sys/ia64/ia64/mca.c
+++ b/sys/ia64/ia64/mca.c
@@ -42,6 +42,16 @@
MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture");
+struct mca_info {
+ STAILQ_ENTRY(mca_info) mi_link;
+ char mi_name[32];
+ size_t mi_recsz;
+ char mi_record[0];
+};
+
+static STAILQ_HEAD(, mca_info) mca_records =
+ STAILQ_HEAD_INITIALIZER(mca_records);
+
int64_t mca_info_size[SAL_INFO_TYPES];
vm_offset_t mca_info_block;
struct mtx mca_info_block_lock;
@@ -76,14 +86,32 @@ mca_sysctl_handler(SYSCTL_HANDLER_ARGS)
}
void
+ia64_mca_populate(void)
+{
+ struct mca_info *rec;
+
+ mtx_lock_spin(&mca_info_block_lock);
+ while (!STAILQ_EMPTY(&mca_records)) {
+ rec = STAILQ_FIRST(&mca_records);
+ STAILQ_REMOVE_HEAD(&mca_records, mi_link);
+ mtx_unlock_spin(&mca_info_block_lock);
+ (void)SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca),
+ OID_AUTO, rec->mi_name, CTLTYPE_OPAQUE | CTLFLAG_RD,
+ rec->mi_record, rec->mi_recsz, mca_sysctl_handler, "S,MCA",
+ "Error record");
+ mtx_lock_spin(&mca_info_block_lock);
+ }
+ mtx_unlock_spin(&mca_info_block_lock);
+}
+
+void
ia64_mca_save_state(int type)
{
struct ia64_sal_result result;
struct mca_record_header *hdr;
- struct sysctl_oid *oidp;
- char *name, *state;
+ struct mca_info *rec;
uint64_t seqnr;
- size_t recsz, totsz;
+ size_t recsz;
/*
* Don't try to get the state if we couldn't get the size of
@@ -95,9 +123,8 @@ ia64_mca_save_state(int type)
if (mca_info_block == 0)
return;
+ mtx_lock_spin(&mca_info_block_lock);
while (1) {
- mtx_lock_spin(&mca_info_block_lock);
-
result = ia64_sal_entry(SAL_GET_STATE_INFO, type, 0,
mca_info_block, 0, 0, 0, 0);
if (result.sal_status < 0) {
@@ -111,11 +138,13 @@ ia64_mca_save_state(int type)
mtx_unlock_spin(&mca_info_block_lock);
- totsz = sizeof(struct sysctl_oid) + recsz + 32;
- oidp = malloc(totsz, M_MCA, M_NOWAIT|M_ZERO);
- state = (char*)(oidp + 1);
- name = state + recsz;
- sprintf(name, "%lld", (long long)seqnr);
+ rec = malloc(sizeof(struct mca_info) + recsz, M_MCA,
+ M_NOWAIT | M_ZERO);
+ if (rec == NULL)
+ /* XXX: Not sure what to do. */
+ return;
+
+ sprintf(rec->mi_name, "%lld", (long long)seqnr);
mtx_lock_spin(&mca_info_block_lock);
@@ -133,24 +162,14 @@ ia64_mca_save_state(int type)
mca_info_block, 0, 0, 0, 0);
if (seqnr != hdr->rh_seqnr) {
mtx_unlock_spin(&mca_info_block_lock);
- free(oidp, M_MCA);
+ free(rec, M_MCA);
+ mtx_lock_spin(&mca_info_block_lock);
continue;
}
}
- bcopy((char*)mca_info_block, state, recsz);
-
- oidp->oid_parent = &sysctl__hw_mca_children;
- oidp->oid_number = OID_AUTO;
- oidp->oid_kind = CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_DYN;
- oidp->oid_arg1 = state;
- oidp->oid_arg2 = recsz;
- oidp->oid_name = name;
- oidp->oid_handler = mca_sysctl_handler;
- oidp->oid_fmt = "S,MCA";
- oidp->oid_descr = "Error record";
-
- sysctl_register_oid(oidp);
+ rec->mi_recsz = recsz;
+ bcopy((char*)mca_info_block, rec->mi_record, recsz);
if (mca_count > 0) {
if (seqnr < mca_first)
@@ -161,6 +180,7 @@ ia64_mca_save_state(int type)
mca_first = mca_last = seqnr;
mca_count++;
+ STAILQ_INSERT_TAIL(&mca_records, rec, mi_link);
/*
* Clear the state so that we get any other records when
@@ -168,8 +188,6 @@ ia64_mca_save_state(int type)
*/
result = ia64_sal_entry(SAL_CLEAR_STATE_INFO, type, 0, 0, 0,
0, 0, 0);
-
- mtx_unlock_spin(&mca_info_block_lock);
}
}
diff --git a/sys/ia64/include/mca.h b/sys/ia64/include/mca.h
index 997c2212bd9d..75831c76ceb3 100644
--- a/sys/ia64/include/mca.h
+++ b/sys/ia64/include/mca.h
@@ -239,6 +239,7 @@ struct mca_pcidev_reg {
#ifdef _KERNEL
void ia64_mca_init(void);
+void ia64_mca_populate(void);
void ia64_mca_save_state(int);
#endif /* _KERNEL */
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index b846c539dd6d..37d2a6d6e36e 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -292,10 +292,10 @@ linker_file_register_sysctls(linker_file_t lf)
if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
return;
- mtx_lock(&Giant);
+ sysctl_lock();
for (oidp = start; oidp < stop; oidp++)
sysctl_register_oid(*oidp);
- mtx_unlock(&Giant);
+ sysctl_unlock();
}
static void
@@ -309,10 +309,10 @@ linker_file_unregister_sysctls(linker_file_t lf)
if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
return;
- mtx_lock(&Giant);
+ sysctl_lock();
for (oidp = start; oidp < stop; oidp++)
sysctl_unregister_oid(*oidp);
- mtx_unlock(&Giant);
+ sysctl_unlock();
}
static int
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index c981135c1c58..51b976255423 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -64,24 +64,41 @@ static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
/*
- * Locking - this locks the sysctl tree in memory.
+ * 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_lock() and sysctl_unlock() 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.
+ *
+ * This lock is also used to serialize userland sysctl requests. Some
+ * sysctls wire user memory, and serializing the requests limits the
+ * amount of wired user memory in use.
*/
static struct sx sysctllock;
-#define SYSCTL_LOCK() sx_xlock(&sysctllock)
-#define SYSCTL_UNLOCK() sx_xunlock(&sysctllock)
-#define SYSCTL_LOCK_ASSERT() sx_assert(&sysctllock, SX_XLOCKED)
+#define SYSCTL_SLOCK() sx_slock(&sysctllock)
+#define SYSCTL_SUNLOCK() sx_sunlock(&sysctllock)
+#define SYSCTL_XLOCK() sx_xlock(&sysctllock)
+#define SYSCTL_XUNLOCK() sx_xunlock(&sysctllock)
+#define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
+#define SYSCTL_ASSERT_LOCKED() sx_assert(&sysctllock, SA_LOCKED)
#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock")
static int sysctl_root(SYSCTL_HANDLER_ARGS);
struct sysctl_oid_list sysctl__children; /* root list */
+static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
+ int recurse);
+
static struct sysctl_oid *
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
{
struct sysctl_oid *oidp;
+ SYSCTL_ASSERT_LOCKED();
SLIST_FOREACH(oidp, list, oid_link) {
if (strcmp(oidp->oid_name, name) == 0) {
return (oidp);
@@ -95,6 +112,19 @@ sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
*
* Order by number in each list.
*/
+void
+sysctl_lock(void)
+{
+
+ SYSCTL_XLOCK();
+}
+
+void
+sysctl_unlock(void)
+{
+
+ SYSCTL_XUNLOCK();
+}
void
sysctl_register_oid(struct sysctl_oid *oidp)
@@ -107,6 +137,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_XLOCKED();
p = sysctl_find_oidname(oidp->oid_name, parent);
if (p != NULL) {
if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
@@ -159,6 +190,7 @@ sysctl_unregister_oid(struct sysctl_oid *oidp)
struct sysctl_oid *p;
int error;
+ SYSCTL_ASSERT_XLOCKED();
error = ENOENT;
if (oidp->oid_number == OID_AUTO) {
error = EINVAL;
@@ -190,6 +222,12 @@ sysctl_ctx_init(struct sysctl_ctx_list *c)
if (c == NULL) {
return (EINVAL);
}
+
+ /*
+ * No locking here, the caller is responsible for not adding
+ * new nodes to a context until after this function has
+ * returned.
+ */
TAILQ_INIT(c);
return (0);
}
@@ -208,8 +246,9 @@ 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_XLOCK();
TAILQ_FOREACH(e, clist, link) {
- error = sysctl_remove_oid(e->entry, 0, 0);
+ error = sysctl_remove_oid_locked(e->entry, 0, 0);
if (error)
break;
}
@@ -226,19 +265,22 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
sysctl_register_oid(e1->entry);
e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
}
- if (error)
+ if (error) {
+ SYSCTL_XUNLOCK();
return(EBUSY);
+ }
/* Now really delete the entries */
e = TAILQ_FIRST(clist);
while (e != NULL) {
e1 = TAILQ_NEXT(e, link);
- error = sysctl_remove_oid(e->entry, 1, 0);
+ error = sysctl_remove_oid_locked(e->entry, 1, 0);
if (error)
panic("sysctl_remove_oid: corrupt tree, entry: %s",
e->entry->oid_name);
free(e, M_SYSCTLOID);
e = e1;
}
+ SYSCTL_XUNLOCK();
return (error);
}
@@ -248,6 +290,7 @@ sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
{
struct sysctl_ctx_entry *e;
+ SYSCTL_ASSERT_XLOCKED();
if (clist == NULL || oidp == NULL)
return(NULL);
e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
@@ -262,6 +305,7 @@ sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
{
struct sysctl_ctx_entry *e;
+ SYSCTL_ASSERT_LOCKED();
if (clist == NULL || oidp == NULL)
return(NULL);
TAILQ_FOREACH(e, clist, link) {
@@ -283,13 +327,17 @@ sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
if (clist == NULL || oidp == NULL)
return (EINVAL);
+ SYSCTL_XLOCK();
e = sysctl_ctx_entry_find(clist, oidp);
if (e != NULL) {
TAILQ_REMOVE(clist, e, link);
+ SYSCTL_XUNLOCK();
free(e, M_SYSCTLOID);
return (0);
- } else
+ } else {
+ SYSCTL_XUNLOCK();
return (ENOENT);
+ }
}
/*
@@ -301,9 +349,21 @@ sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
int
sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
{
+ int error;
+
+ SYSCTL_XLOCK();
+ error = sysctl_remove_oid_locked(oidp, del, recurse);
+ SYSCTL_XUNLOCK();
+ return (error);
+}
+
+static int
+sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
+{
struct sysctl_oid *p;
int error;
+ SYSCTL_ASSERT_XLOCKED();
if (oidp == NULL)
return(EINVAL);
if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
@@ -322,7 +382,8 @@ sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
if (!recurse)
return (ENOTEMPTY);
- error = sysctl_remove_oid(p, del, recurse);
+ error = sysctl_remove_oid_locked(p, del,
+ recurse);
if (error)
return (error);
}
@@ -367,6 +428,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_XLOCK();
oidp = sysctl_find_oidname(name, parent);
if (oidp != NULL) {
if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
@@ -374,8 +436,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_XUNLOCK();
return (oidp);
} else {
+ SYSCTL_XUNLOCK();
printf("can't re-use a leaf (%s)!\n", name);
return (NULL);
}
@@ -413,6 +477,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_XUNLOCK();
return (oidp);
}
@@ -426,12 +491,14 @@ sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
char *newname;
void *oldname;
- oldname = (void *)(uintptr_t)(const void *)oidp->oid_name;
len = strlen(name);
newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
bcopy(name, newname, len + 1);
newname[len] = '\0';
+ SYSCTL_XLOCK();
+ oldname = (void *)(uintptr_t)(const void *)oidp->oid_name;
oidp->oid_name = newname;
+ SYSCTL_XUNLOCK();
free(oldname, M_SYSCTLOID);
}
@@ -443,15 +510,21 @@ sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
{
struct sysctl_oid *oidp;
- if (oid->oid_parent == parent)
+ SYSCTL_XLOCK();
+ if (oid->oid_parent == parent) {
+ SYSCTL_XUNLOCK();
return (0);
+ }
oidp = sysctl_find_oidname(oid->oid_name, parent);
- if (oidp != NULL)
+ if (oidp != NULL) {
+ SYSCTL_XUNLOCK();
return (EEXIST);
+ }
sysctl_unregister_oid(oid);
oid->oid_parent = parent;
oid->oid_number = OID_AUTO;
sysctl_register_oid(oid);
+ SYSCTL_XUNLOCK();
return (0);
}
@@ -466,8 +539,10 @@ sysctl_register_all(void *arg)
struct sysctl_oid **oidp;
SYSCTL_INIT();
+ SYSCTL_XLOCK();
SET_FOREACH(oidp, sysctl_set)
sysctl_register_oid(*oidp);
+ SYSCTL_XUNLOCK();
}
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
@@ -497,6 +572,7 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
int k;
struct sysctl_oid *oidp;
+ SYSCTL_ASSERT_LOCKED();
SLIST_FOREACH(oidp, l, oid_link) {
for (k=0; k<i; k++)
@@ -555,6 +631,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
char buf[10];
+ SYSCTL_ASSERT_LOCKED();
while (namelen) {
if (!lsp) {
snprintf(buf,sizeof(buf),"%d",*name);
@@ -606,6 +683,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
{
struct sysctl_oid *oidp;
+ SYSCTL_ASSERT_LOCKED();
*len = level;
SLIST_FOREACH(oidp, lsp, oid_link) {
*next = oidp->oid_number;
@@ -686,7 +764,7 @@ name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
struct sysctl_oid_list *lsp = &sysctl__children;
char *p;
- SYSCTL_LOCK_ASSERT();
+ SYSCTL_ASSERT_LOCKED();
if (!*name)
return (ENOENT);
@@ -744,7 +822,7 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
int error, oid[CTL_MAXNAME], len;
struct sysctl_oid *op = 0;
- SYSCTL_LOCK_ASSERT();
+ SYSCTL_ASSERT_LOCKED();
if (!req->newlen)
return (ENOENT);
@@ -1089,9 +1167,9 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
req.newfunc = sysctl_new_kernel;
req.lock = REQ_LOCKED;
- SYSCTL_LOCK();
+ SYSCTL_SLOCK();
error = sysctl_root(0, name, namelen, &req);
- SYSCTL_UNLOCK();
+ SYSCTL_SUNLOCK();
if (req.lock == REQ_WIRED && req.validlen > 0)
vsunlock(req.oldptr, req.validlen);
@@ -1123,6 +1201,9 @@ kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
/*
* XXX: Prone to a possible race condition between lookup and
* execution? Maybe put locking around it?
+ *
+ * Userland is just as racy, so I think the current implementation
+ * is fine.
*/
error = kernel_sysctl(td, oid, 2, oid, &oidlen,
@@ -1234,6 +1315,7 @@ sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
struct sysctl_oid *oid;
int indx;
+ SYSCTL_ASSERT_LOCKED();
oid = SLIST_FIRST(&sysctl__children);
indx = 0;
while (oid && indx < CTL_MAXNAME) {
@@ -1277,7 +1359,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
struct sysctl_oid *oid;
int error, indx, lvl;
- SYSCTL_LOCK_ASSERT();
+ SYSCTL_ASSERT_LOCKED();
error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
if (error)
@@ -1355,7 +1437,7 @@ struct sysctl_args {
int
__sysctl(struct thread *td, struct sysctl_args *uap)
{
- int error, name[CTL_MAXNAME];
+ int error, i, name[CTL_MAXNAME];
size_t j;
if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
@@ -1371,7 +1453,7 @@ __sysctl(struct thread *td, struct sysctl_args *uap)
if (error && error != ENOMEM)
return (error);
if (uap->oldlenp) {
- int i = copyout(&j, uap->oldlenp, sizeof(j));
+ i = copyout(&j, uap->oldlenp, sizeof(j));
if (i)
return (i);
}
@@ -1423,7 +1505,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
req.newfunc = sysctl_new_user;
req.lock = REQ_LOCKED;
- SYSCTL_LOCK();
+ SYSCTL_XLOCK();
for (;;) {
req.oldidx = 0;
@@ -1434,7 +1516,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
uio_yield();
}
- SYSCTL_UNLOCK();
+ SYSCTL_XUNLOCK();
if (req.lock == REQ_WIRED && req.validlen > 0)
vsunlock(req.oldptr, req.validlen);
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index 3ce65ed900de..4367b8c8096b 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -165,12 +165,15 @@ vfs_register(struct vfsconf *vfc)
* preserved by re-registering the oid after modifying its
* number.
*/
+ sysctl_lock();
SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
sysctl_unregister_oid(oidp);
oidp->oid_number = vfc->vfc_typenum;
sysctl_register_oid(oidp);
+ break;
}
+ sysctl_unlock();
/*
* Initialise unused ``struct vfsops'' fields, to use
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index f1ccd2073e84..cde7d8076f2f 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -685,6 +685,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_lock(void);
+void sysctl_unlock(void);
int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);
#else /* !_KERNEL */