Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Oct 2014 19:05:45 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r273401 - head/sys/kern
Message-ID:  <201410211905.s9LJ5jDb032492@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201410211905.s9LJ5jDb032492>