[PATCH] /dev/random and nonblocking I/O bug

Natapov Gleb (gnatapov@qualcomm.com)
Thu, 14 Oct 1999 08:34:21 +0200


Hi. I've already posted this, but I haven't got any response.

It seems that read from /dev/random can block even if the device was
opened with O_NONBLOCK flag.

I wrote the following program:
=================================================================
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

void main()
{
int randfd;
char c;
if( (randfd = open("/dev/random", O_RDONLY | O_NONBLOCK)) >= 0){
while(1){
if(read(randfd, &c, 1) != 1){
if( errno != EWOULDBLOCK && errno != 0 )
fprintf(stderr, "read error form random device");
break;
}
fprintf(stderr,".");
}
}
}
=====================================================================
If you'll run this program when there are many bytes available in random
pool you'll see that at some point program stops to print dots until
some event, that adds data to random pool (mouse movement, keyboard
stroke), will happen.

The problem is in random_read() (linux/drivers/char/random.c).
The task puts itself in random_read_wait queue and change state to
TASK_INTERRUPTIBLE.

If the random pool is empty and O_NONBLOCK is set it returns EAGAIN (as
we are expecting) else it calls extract_entropy().

current->state == TASK_INTERRUPTIBLE at this point.

extract_entropy() fills the user's buffer with random data and if
current->need_resched is not zero it calls resched(). The task goes to
sleep in state TASK_INTERRUPTIBLE until somebody will write new random
data into the pool and call wake_up_interruptible(&random_read_wait);
It's exactly what we don't want - go to sleep while in nonblocking
syscall.

The following patch solves this problem for me(2.2.10, 2.2.12):
===================================================================
--- random.c.org Tue Oct 12 10:49:13 1999
+++ random.c Tue Oct 12 14:20:44 1999
@@ -1328,6 +1328,7 @@
schedule();
continue;
}
+ current->state = TASK_RUNNING;
n = extract_entropy(&random_state, buf, n, 1);
if (n < 0) {
retval = n;
====================================================================

But may be there is a better solution.

(I've looked at sources of 2.3.21 and, as far as I can see, it has the
same problem).

Gleb.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/