Author: mjg
Date: Tue Oct 21 19:05:44 2014
New Revision: 273401
URL: https://svnweb.freebsd.org/changeset/base/273401

Log:
  Implement shared locking for sysctl.

Modified:
  head/sys/kern/kern_sysctl.c

Modified: head/sys/kern/kern_sysctl.c
==============================================================================
--- head/sys/kern/kern_sysctl.c Tue Oct 21 19:02:26 2014        (r273400)
+++ head/sys/kern/kern_sysctl.c Tue Oct 21 19:05:44 2014        (r273401)
@@ -91,6 +91,10 @@ static struct sx sysctlmemlock;
 
 #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_INIT()           sx_init(&sysctllock, "sysctl lock")
 #define        SYSCTL_SLEEP(ch, wmesg, timo)                                   
\
@@ -106,12 +110,35 @@ static int        sysctl_remove_oid_locked(stru
 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)
 {
        struct sysctl_oid *oidp;
 
-       SYSCTL_ASSERT_XLOCKED();
+       SYSCTL_ASSERT_LOCKED();
        SLIST_FOREACH(oidp, list, oid_link) {
                if (strcmp(oidp->oid_name, name) == 0) {
                        return (oidp);
@@ -144,9 +171,10 @@ sysctl_root_handler_locked(struct sysctl
     struct sysctl_req *req)
 {
        int error;
+       bool xlocked;
 
-       oid->oid_running++;
-       SYSCTL_XUNLOCK();
+       atomic_add_int(&oid->oid_running, 1);
+       xlocked = sysctl_unlock();
 
        if (!(oid->oid_kind & CTLFLAG_MPSAFE))
                mtx_lock(&Giant);
@@ -154,9 +182,9 @@ sysctl_root_handler_locked(struct sysctl
        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)
+       sysctl_lock(xlocked);
+       if (atomic_fetchadd_int(&oid->oid_running, -1) == 1 &&
+           (oid->oid_kind & CTLFLAG_DYING) != 0)
                wakeup(&oid->oid_running);
 
        return (error);
@@ -852,7 +880,7 @@ sysctl_sysctl_next_ls(struct sysctl_oid_
 {
        struct sysctl_oid *oidp;
 
-       SYSCTL_ASSERT_XLOCKED();
+       SYSCTL_ASSERT_LOCKED();
        *len = level;
        SLIST_FOREACH(oidp, lsp, oid_link) {
                *next = oidp->oid_number;
@@ -939,7 +967,7 @@ name2oid(char *name, int *oid, int *len,
        struct sysctl_oid_list *lsp = &sysctl__children;
        char *p;
 
-       SYSCTL_ASSERT_XLOCKED();
+       SYSCTL_ASSERT_LOCKED();
 
        for (*len = 0; *len < CTL_MAXNAME;) {
                p = strsep(&name, ".");
@@ -1364,9 +1392,9 @@ kernel_sysctl(struct thread *td, int *na
        req.newfunc = sysctl_new_kernel;
        req.lock = REQ_UNWIRED;
 
-       SYSCTL_XLOCK();
+       SYSCTL_SLOCK();
        error = sysctl_root(0, name, namelen, &req);
-       SYSCTL_XUNLOCK();
+       SYSCTL_SUNLOCK();
 
        if (req.lock == REQ_WIRED && req.validlen > 0)
                vsunlock(req.oldptr, req.validlen);
@@ -1498,7 +1526,7 @@ sysctl_find_oid(int *name, u_int namelen
        struct sysctl_oid *oid;
        int indx;
 
-       SYSCTL_ASSERT_XLOCKED();
+       SYSCTL_ASSERT_LOCKED();
        lsp = &sysctl__children;
        indx = 0;
        while (indx < CTL_MAXNAME) {
@@ -1545,7 +1573,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
        struct sysctl_oid *oid;
        int error, indx, lvl;
 
-       SYSCTL_ASSERT_XLOCKED();
+       SYSCTL_ASSERT_LOCKED();
 
        error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
        if (error)
@@ -1729,9 +1757,9 @@ userland_sysctl(struct thread *td, int *
        for (;;) {
                req.oldidx = 0;
                req.newidx = 0;
-               SYSCTL_XLOCK();
+               SYSCTL_SLOCK();
                error = sysctl_root(0, name, namelen, &req);
-               SYSCTL_XUNLOCK();
+               SYSCTL_SUNLOCK();
                if (error != EAGAIN)
                        break;
                kern_yield(PRI_USER);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to