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
This commit is contained in:
Mateusz Guzik 2014-10-28 04:33:57 +00:00
parent b8ded963c9
commit b720dc9749

View File

@ -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);
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);
}
/* 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);
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);
}