Fix spurious kassert on interrupted blocking read from /dev/random.

Return EINTR in this case instead.  While here, clarify comment.

Fixes PR kern/48119, simpler than the patch attached there, per
discussion with tls@, who had this right in the earlier version
of rndpseudo.c before I broke it (oops!).
This commit is contained in:
riastradh 2013-09-25 03:14:55 +00:00
parent 72b022939e
commit db4eba3c26
1 changed files with 25 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rndpseudo.c,v 1.16 2013/07/21 22:30:19 riastradh Exp $ */
/* $NetBSD: rndpseudo.c,v 1.17 2013/09/25 03:14:55 riastradh Exp $ */
/*-
* Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.16 2013/07/21 22:30:19 riastradh Exp $");
__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.17 2013/09/25 03:14:55 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@ -389,18 +389,32 @@ rnd_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
goto out;
/*
* Do at most one iteration for /dev/random and return
* a short read without hanging further. Hanging
* breaks applications worse than short reads. Reads
* can't be zero unless nonblocking from /dev/random;
* in that case, ask caller to retry, instead of just
* returning zero bytes, which means EOF.
* For /dev/urandom: Reads always succeed in full, no
* matter how many iterations that takes. (XXX But
* this means the computation can't be interrupted,
* wihch seems suboptimal.)
*
* For /dev/random, nonblocking: Reads succeed with as
* many bytes as a single request can return without
* blocking, or fail with EAGAIN if a request would
* block. (There is no sense in trying multiple
* requests because if the first one didn't fill the
* buffer, the second one would almost certainly
* block.)
*
* For /dev/random, blocking: Reads succeed with as
* many bytes as a single request -- which may block --
* can return if uninterrupted, or fail with EINTR if
* the request is interrupted.
*/
KASSERT((0 < n_read) || (ctx->rc_hard &&
ISSET(fp->f_flag, FNONBLOCK)));
KASSERT((0 < n_read) || ctx->rc_hard);
if (ctx->rc_hard) {
if (n_read == 0)
if (0 < n_read)
error = 0;
else if (ISSET(fp->f_flag, FNONBLOCK))
error = EAGAIN;
else
error = EINTR;
goto out;
}
}