Module Name: src Committed By: riastradh Date: Wed Sep 25 03:14:55 UTC 2013
Modified Files: src/sys/dev: rndpseudo.c Log Message: 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!). To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/sys/dev/rndpseudo.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/rndpseudo.c diff -u src/sys/dev/rndpseudo.c:1.16 src/sys/dev/rndpseudo.c:1.17 --- src/sys/dev/rndpseudo.c:1.16 Sun Jul 21 22:30:19 2013 +++ src/sys/dev/rndpseudo.c Wed Sep 25 03:14:55 2013 @@ -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, s 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; } }