From owner-svn-src-head@FreeBSD.ORG Tue Oct 28 04:33:58 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 7874CF94; Tue, 28 Oct 2014 04:33:58 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 64861AE1; Tue, 28 Oct 2014 04:33:58 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s9S4XwZK003260; Tue, 28 Oct 2014 04:33:58 GMT (envelope-from mjg@FreeBSD.org) Received: (from mjg@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s9S4XwnT003259; Tue, 28 Oct 2014 04:33:58 GMT (envelope-from mjg@FreeBSD.org) Message-Id: <201410280433.s9S4XwnT003259@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: mjg set sender to mjg@FreeBSD.org using -f From: Mateusz Guzik Date: Tue, 28 Oct 2014 04:33:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r273763 - head/sys/kern X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Oct 2014 04:33:58 -0000 Author: mjg Date: Tue Oct 28 04:33:57 2014 New Revision: 273763 URL: https://svnweb.freebsd.org/changeset/base/273763 Log: Change loginclass mutex to an rwlock. While here reduce nesting in loginclass_free. Submitted by: Tiwei Bie X-Additional: JuniorJobs project MFC after: 2 weeks Modified: head/sys/kern/kern_loginclass.c Modified: head/sys/kern/kern_loginclass.c ============================================================================== --- head/sys/kern/kern_loginclass.c Tue Oct 28 04:18:09 2014 (r273762) +++ head/sys/kern/kern_loginclass.c Tue Oct 28 04:33:57 2014 (r273763) @@ -51,13 +51,13 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -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 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); }