Module Name:    src
Committed By:   riastradh
Date:           Tue Apr 21 03:53:07 UTC 2015

Modified Files:
        src/sys/kern: kern_rndq.c
        src/sys/sys: rndsource.h

Log Message:
Release rnd_global.lock while calling an rndsource's callback.

Obviates the need for obnoxious double-lock dances in hardware RNG
drivers.


To generate a diff of this commit:
cvs rdiff -u -r1.67 -r1.68 src/sys/kern/kern_rndq.c
cvs rdiff -u -r1.2 -r1.3 src/sys/sys/rndsource.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_rndq.c
diff -u src/sys/kern/kern_rndq.c:1.67 src/sys/kern/kern_rndq.c:1.68
--- src/sys/kern/kern_rndq.c:1.67	Tue Apr 21 03:46:46 2015
+++ src/sys/kern/kern_rndq.c	Tue Apr 21 03:53:07 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_rndq.c,v 1.67 2015/04/21 03:46:46 riastradh Exp $	*/
+/*	$NetBSD: kern_rndq.c,v 1.68 2015/04/21 03:53:07 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.67 2015/04/21 03:46:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.68 2015/04/21 03:53:07 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -126,6 +126,7 @@ static struct {
 	kmutex_t		lock;
 	rndpool_t		pool;
 	LIST_HEAD(, krndsource)	sources;
+	kcondvar_t		cv;
 } rnd_global __cacheline_aligned;
 
 /*
@@ -260,15 +261,32 @@ rnd_schedule_wakeup(void)
 void
 rnd_getmore(size_t byteswanted)
 {
-	krndsource_t *rs;
+	krndsource_t *rs, *next;
 
 	mutex_spin_enter(&rnd_global.lock);
-	LIST_FOREACH(rs, &rnd_global.sources, list) {
+	LIST_FOREACH_SAFE(rs, &rnd_global.sources, list, next) {
+		/* Skip if there's no callback.  */
 		if (!ISSET(rs->flags, RND_FLAG_HASCB))
 			continue;
 		KASSERT(rs->get != NULL);
-		KASSERT(rs->getarg != NULL);
+
+		/* Skip if there are too many users right now.  */
+		if (rs->refcnt == UINT_MAX)
+			continue;
+
+		/*
+		 * Hold a reference while we release rnd_global.lock to
+		 * call the callback.  The callback may in turn call
+		 * rnd_add_data, which acquires rnd_global.lock.
+		 */
+		rs->refcnt++;
+		mutex_spin_exit(&rnd_global.lock);
 		rs->get(byteswanted, rs->getarg);
+		mutex_spin_enter(&rnd_global.lock);
+		if (--rs->refcnt == 0)
+			cv_broadcast(&rnd_global.cv);
+
+		/* Dribble some goo to the console.  */
 		rnd_printf_verbose("rnd: entropy estimate %zu bits\n",
 		    rndpool_get_entropy_count(&rnd_global.pool));
 		rnd_printf_verbose("rnd: asking source %s for %zu bytes\n",
@@ -497,6 +515,7 @@ rnd_init(void)
 	mutex_init(&rnd_global.lock, MUTEX_DEFAULT, IPL_VM);
 	rndpool_init(&rnd_global.pool);
 	LIST_INIT(&rnd_global.sources);
+	cv_init(&rnd_global.cv, "rndsrc");
 
 	rnd_mempc = pool_cache_init(sizeof(rnd_sample_t), 0, 0, 0,
 				    "rndsample", NULL, IPL_VM,
@@ -652,6 +671,7 @@ rnd_attach_source(krndsource_t *rs, cons
 
 	rs->type = type;
 	rs->flags = flags;
+	rs->refcnt = 1;
 
 	rs->state = rnd_sample_allocate(rs);
 
@@ -691,6 +711,11 @@ rnd_detach_source(krndsource_t *source)
 
 	mutex_spin_enter(&rnd_global.lock);
 	LIST_REMOVE(source, list);
+	if (0 < --source->refcnt) {
+		do {
+			cv_wait(&rnd_global.cv, &rnd_global.lock);
+		} while (0 < source->refcnt);
+	}
 	mutex_spin_exit(&rnd_global.lock);
 
 	/*

Index: src/sys/sys/rndsource.h
diff -u src/sys/sys/rndsource.h:1.2 src/sys/sys/rndsource.h:1.3
--- src/sys/sys/rndsource.h:1.2	Mon Apr 13 16:02:48 2015
+++ src/sys/sys/rndsource.h	Tue Apr 21 03:53:07 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: rndsource.h,v 1.2 2015/04/13 16:02:48 riastradh Exp $	*/
+/*	$NetBSD: rndsource.h,v 1.3 2015/04/21 03:53:07 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -63,6 +63,7 @@ typedef struct krndsource {
 	void		*getarg;	/* argument to get-function */
 	void		(*enable)(struct krndsource *, bool); /* turn on/off */
 	rngtest_t	*test;		/* test data for RNG type sources */
+	unsigned	refcnt;
 } krndsource_t;
 
 static inline void

Reply via email to