summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_loginclass.c
diff options
context:
space:
mode:
authormjg <mjg@FreeBSD.org>2014-10-28 04:33:57 +0000
committermjg <mjg@FreeBSD.org>2014-10-28 04:33:57 +0000
commit37841a11a2012b9696170e9eef78eef341e74dcf (patch)
treec2382f99cbdaa38c99fc8be72b1d52b26abc3d10 /sys/kern/kern_loginclass.c
parent91121d26d0529d089c68daeaa29f49ad8d895e08 (diff)
downloadFreeBSD-src-37841a11a2012b9696170e9eef78eef341e74dcf.zip
FreeBSD-src-37841a11a2012b9696170e9eef78eef341e74dcf.tar.gz
Change loginclass mutex to an rwlock.
While here reduce nesting in loginclass_free. Submitted by: Tiwei Bie <btw mail.ustc.edu.cn> X-Additional: JuniorJobs project MFC after: 2 weeks
Diffstat (limited to 'sys/kern/kern_loginclass.c')
-rw-r--r--sys/kern/kern_loginclass.c94
1 files changed, 60 insertions, 34 deletions
diff --git a/sys/kern/kern_loginclass.c b/sys/kern/kern_loginclass.c
index b20f60b..92eb3cf 100644
--- a/sys/kern/kern_loginclass.c
+++ b/sys/kern/kern_loginclass.c
@@ -51,13 +51,13 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/loginclass.h>
#include <sys/malloc.h>
-#include <sys/mutex.h>
#include <sys/types.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/racct.h>
#include <sys/refcount.h>
+#include <sys/rwlock.h>
#include <sys/sysproto.h>
#include <sys/systm.h>
@@ -68,8 +68,8 @@ LIST_HEAD(, loginclass) loginclasses;
/*
* Lock protecting loginclasses list.
*/
-static struct mtx loginclasses_lock;
-MTX_SYSINIT(loginclasses_init, &loginclasses_lock, "loginclasses lock", MTX_DEF);
+static struct rwlock loginclasses_lock;
+RW_SYSINIT(loginclasses_init, &loginclasses_lock, "loginclasses lock");
void
loginclass_hold(struct loginclass *lc)
@@ -87,16 +87,37 @@ loginclass_free(struct loginclass *lc)
if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1))
return;
- mtx_lock(&loginclasses_lock);
- if (refcount_release(&lc->lc_refcount)) {
- racct_destroy(&lc->lc_racct);
- LIST_REMOVE(lc, lc_next);
- mtx_unlock(&loginclasses_lock);
- free(lc, M_LOGINCLASS);
-
+ rw_wlock(&loginclasses_lock);
+ if (!refcount_release(&lc->lc_refcount)) {
+ rw_wunlock(&loginclasses_lock);
return;
}
- mtx_unlock(&loginclasses_lock);
+
+ racct_destroy(&lc->lc_racct);
+ LIST_REMOVE(lc, lc_next);
+ rw_wunlock(&loginclasses_lock);
+
+ free(lc, M_LOGINCLASS);
+}
+
+/*
+ * Look up a loginclass struct for the parameter name.
+ * loginclasses_lock must be locked.
+ * Increase refcount on loginclass struct returned.
+ */
+static struct loginclass *
+loginclass_lookup(const char *name)
+{
+ struct loginclass *lc;
+
+ rw_assert(&loginclasses_lock, RA_LOCKED);
+ LIST_FOREACH(lc, &loginclasses, lc_next)
+ if (strcmp(name, lc->lc_name) == 0) {
+ loginclass_hold(lc);
+ break;
+ }
+
+ return (lc);
}
/*
@@ -109,34 +130,39 @@ loginclass_free(struct loginclass *lc)
struct loginclass *
loginclass_find(const char *name)
{
- struct loginclass *lc, *newlc;
+ struct loginclass *lc, *new_lc;
if (name[0] == '\0' || strlen(name) >= MAXLOGNAME)
return (NULL);
- newlc = malloc(sizeof(*newlc), M_LOGINCLASS, M_ZERO | M_WAITOK);
- racct_create(&newlc->lc_racct);
-
- mtx_lock(&loginclasses_lock);
- LIST_FOREACH(lc, &loginclasses, lc_next) {
- if (strcmp(name, lc->lc_name) != 0)
- continue;
-
- /* Found loginclass with a matching name? */
- loginclass_hold(lc);
- mtx_unlock(&loginclasses_lock);
- racct_destroy(&newlc->lc_racct);
- free(newlc, M_LOGINCLASS);
+ rw_rlock(&loginclasses_lock);
+ lc = loginclass_lookup(name);
+ rw_runlock(&loginclasses_lock);
+ if (lc != NULL)
return (lc);
- }
- /* Add new loginclass. */
- strcpy(newlc->lc_name, name);
- refcount_init(&newlc->lc_refcount, 1);
- LIST_INSERT_HEAD(&loginclasses, newlc, lc_next);
- mtx_unlock(&loginclasses_lock);
+ new_lc = malloc(sizeof(*new_lc), M_LOGINCLASS, M_ZERO | M_WAITOK);
+ racct_create(&new_lc->lc_racct);
+ refcount_init(&new_lc->lc_refcount, 1);
+ strcpy(new_lc->lc_name, name);
+
+ rw_wlock(&loginclasses_lock);
+ /*
+ * There's a chance someone created our loginclass while we
+ * were in malloc and not holding the lock, so we have to
+ * make sure we don't insert a duplicate loginclass.
+ */
+ if ((lc = loginclass_lookup(name)) == NULL) {
+ LIST_INSERT_HEAD(&loginclasses, new_lc, lc_next);
+ rw_wunlock(&loginclasses_lock);
+ lc = new_lc;
+ } else {
+ rw_wunlock(&loginclasses_lock);
+ racct_destroy(&new_lc->lc_racct);
+ free(new_lc, M_LOGINCLASS);
+ }
- return (newlc);
+ return (lc);
}
/*
@@ -222,8 +248,8 @@ loginclass_racct_foreach(void (*callback)(struct racct *racct,
{
struct loginclass *lc;
- mtx_lock(&loginclasses_lock);
+ rw_rlock(&loginclasses_lock);
LIST_FOREACH(lc, &loginclasses, lc_next)
(callback)(lc->lc_racct, arg2, arg3);
- mtx_unlock(&loginclasses_lock);
+ rw_runlock(&loginclasses_lock);
}
OpenPOWER on IntegriCloud