From owner-svn-src-projects@freebsd.org Sun Nov 20 11:12:43 2016 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A9449C4B31F for ; Sun, 20 Nov 2016 11:12:43 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::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 5DBACF30; Sun, 20 Nov 2016 11:12:43 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAKBCgiu026498; Sun, 20 Nov 2016 11:12:42 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAKBCg8r026497; Sun, 20 Nov 2016 11:12:42 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201611201112.uAKBCg8r026497@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Sun, 20 Nov 2016 11:12:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r308880 - projects/ipsec/sys/netipsec X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Nov 2016 11:12:43 -0000 Author: ae Date: Sun Nov 20 11:12:42 2016 New Revision: 308880 URL: https://svnweb.freebsd.org/changeset/base/308880 Log: Change locking used by key_flush_spd(). First of we acquire SPTREE_RLOCK() and check all security policies for expiration. If expired SP isn't found, just release the lock and return. When expired SP is found, we acquire extra reference for this SP and link it into drainq using special drainq LIST_ENTRY in struct secpolicy. When all expired SPs will be linked, we acquire SPTREE_WLOCK() and unlink all SPs from ths SPDB and idhash. If SP has spstate != IPSEC_SPSTATE_ALIVE, we skip such SP, since it can be already unlinked (before we acquired wlock). Then we release SPTREE_WLOCK and call key_spdexpire() for each SP. Now we can release extra reference and last reference for each SP. Modified: projects/ipsec/sys/netipsec/key.c Modified: projects/ipsec/sys/netipsec/key.c ============================================================================== --- projects/ipsec/sys/netipsec/key.c Sun Nov 20 10:54:18 2016 (r308879) +++ projects/ipsec/sys/netipsec/key.c Sun Nov 20 11:12:42 2016 (r308880) @@ -4304,13 +4304,13 @@ static void key_flush_spd(time_t now) { SPTREE_RLOCK_TRACKER; - struct secpolicy *sp; + struct secpolicy_list drainq; + struct secpolicy *sp, *nextsp; u_int dir; - /* SPD */ + LIST_INIT(&drainq); + SPTREE_RLOCK(); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { -restart: - SPTREE_RLOCK(); TAILQ_FOREACH(sp, &V_sptree[dir], chain) { if (sp->lifetime == 0 && sp->validtime == 0) continue; @@ -4318,15 +4318,42 @@ restart: now - sp->created > sp->lifetime) || (sp->validtime && now - sp->lastused > sp->validtime)) { + /* Hold extra reference to send SPDEXPIRE */ SP_ADDREF(sp); - SPTREE_RUNLOCK(); - key_spdexpire(sp); - key_unlink(sp); - KEY_FREESP(&sp); - goto restart; + LIST_INSERT_HEAD(&drainq, sp, drainq); } } - SPTREE_RUNLOCK(); + } + SPTREE_RUNLOCK(); + if (LIST_EMPTY(&drainq)) + return; + + SPTREE_WLOCK(); + sp = LIST_FIRST(&drainq); + while (sp != NULL) { + nextsp = LIST_NEXT(sp, drainq); + /* Check that SP is still linked */ + if (sp->state != IPSEC_SPSTATE_ALIVE) { + LIST_REMOVE(sp, drainq); + key_freesp(&sp); /* release extra reference */ + sp = nextsp; + continue; + } + TAILQ_REMOVE(&V_sptree[sp->spidx.dir], sp, chain); + LIST_REMOVE(sp, idhash); + sp->state = IPSEC_SPSTATE_DEAD; + sp = nextsp; + } + V_sp_genid++; + SPTREE_WUNLOCK(); + + sp = LIST_FIRST(&drainq); + while (sp != NULL) { + nextsp = LIST_NEXT(sp, drainq); + key_spdexpire(sp); + key_freesp(&sp); /* release extra reference */ + key_freesp(&sp); /* release last reference */ + sp = nextsp; } }