svn commit: r308880 - projects/ipsec/sys/netipsec

Andrey V. Elsukov ae at FreeBSD.org
Sun Nov 20 11:12:43 UTC 2016


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;
 	}
 }
 


More information about the svn-src-projects mailing list