示例#1
0
static int
makeprng(void)
{

	/* can't create in cprng_init(), too early */
	sysctl_prng = cprng_strong_create("sysctl", IPL_NONE,
					  CPRNG_INIT_ANY|CPRNG_REKEY_ANY);
	return 0;
}
/*
 * Fetch a per-CPU CPRNG, or create and save one if necessary.
 */
static struct cprng_strong *
rnd_percpu_cprng(void)
{
	struct cprng_strong **cprngp, *cprng, *tmp = NULL;

	/* Fast path: if there already is a CPRNG for this CPU, use it.  */
	cprngp = percpu_getref(percpu_urandom_cprng);
	cprng = *cprngp;
	if (__predict_true(cprng != NULL))
		goto out;
	percpu_putref(percpu_urandom_cprng);

	/*
	 * Slow path: create a CPRNG named by this CPU.
	 *
	 * XXX The CPU of the name may be different from the CPU to
	 * which it is assigned, because we need to choose a name and
	 * allocate a cprng while preemption is enabled.  This could be
	 * fixed by changing the cprng_strong API (e.g., by adding a
	 * cprng_strong_setname or by separating allocation from
	 * initialization), but it's not clear that's worth the
	 * trouble.
	 */
	char name[32];
	(void)snprintf(name, sizeof(name), "urandom%u", cpu_index(curcpu()));
	tmp = cprng_strong_create(name, IPL_NONE,
	    (CPRNG_INIT_ANY | CPRNG_REKEY_ANY));

	/* Try again, but we may have been preempted and lost a race.  */
	cprngp = percpu_getref(percpu_urandom_cprng);
	cprng = *cprngp;
	if (__predict_false(cprng != NULL))
		goto out;

	/* Commit the CPRNG we just created.  */
	cprng = tmp;
	tmp = NULL;
	*cprngp = cprng;

out:	percpu_putref(percpu_urandom_cprng);
	if (tmp != NULL)
		cprng_strong_destroy(tmp);
	KASSERT(cprng != NULL);
	return cprng;
}
/*
 * Fetch a /dev/u?random context's CPRNG, or create and save one if
 * necessary.
 */
static struct cprng_strong *
rnd_ctx_cprng(struct rnd_ctx *ctx)
{
	struct cprng_strong *cprng, *tmp = NULL;

	/* Fast path: if someone has already allocated a CPRNG, use it.  */
	cprng = ctx->rc_cprng;
	if (__predict_true(cprng != NULL)) {
		/* Make sure the CPU hasn't prefetched cprng's guts.  */
		membar_consumer();
		goto out;
	}

	/* Slow path: create a CPRNG.  Allocate before taking locks.  */
	char name[64];
	struct lwp *const l = curlwp;
	(void)snprintf(name, sizeof(name), "%d %"PRIu64" %u",
	    (int)l->l_proc->p_pid, l->l_ncsw, l->l_cpticks);
	const int flags = (ctx->rc_hard? (CPRNG_USE_CV | CPRNG_HARD) :
	    (CPRNG_INIT_ANY | CPRNG_REKEY_ANY));
	tmp = cprng_strong_create(name, IPL_NONE, flags);

	/* Publish cprng's guts before the pointer to them.  */
	membar_producer();

	/* Attempt to publish tmp, unless someone beat us.  */
	cprng = atomic_cas_ptr(&ctx->rc_cprng, NULL, tmp);
	if (__predict_false(cprng != NULL)) {
		/* Make sure the CPU hasn't prefetched cprng's guts.  */
		membar_consumer();
		goto out;
	}

	/* Published.  Commit tmp.  */
	cprng = tmp;
	tmp = NULL;

out:	if (tmp != NULL)
		cprng_strong_destroy(tmp);
	KASSERT(cprng != NULL);
	return cprng;
}