Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Nov 2016 11:12:42 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r308880 - projects/ipsec/sys/netipsec
Message-ID:  <201611201112.uAKBCg8r026497@repo.freebsd.org>

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



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