random: add async notification support to /dev/random
authorJeff Dike <jdike@addtoit.com>
Tue, 29 Apr 2008 08:03:08 +0000 (01:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 29 Apr 2008 15:06:25 +0000 (08:06 -0700)
Add async notification support to /dev/random.

A little test case is below.  Without this patch, you get:

$ ./async-random
Drained the pool
Found more randomness

With it, you get:

$ ./async-random
Drained the pool
SIGIO
Found more randomness

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>

static void handler(int sig)
{
        printf("SIGIO\n");
}

int main(int argc, char **argv)
{
        int fd, n, err, flags;

        if(signal(SIGIO, handler) < 0){
                perror("setting SIGIO handler");
                exit(1);
        }

        fd = open("/dev/random", O_RDONLY);
        if(fd < 0){
                perror("open");
                exit(1);
        }

        flags = fcntl(fd, F_GETFL);
        if (flags < 0){
                perror("getting flags");
                exit(1);
        }

        flags |= O_NONBLOCK;
        if (fcntl(fd, F_SETFL, flags) < 0){
                perror("setting flags");
                exit(1);
        }

        while((err = read(fd, &n, sizeof(n))) > 0) ;

        if(err == 0){
                printf("random returned 0\n");
                exit(1);
        }
        else if(errno != EAGAIN){
                perror("read");
                exit(1);
        }

        flags |= O_ASYNC;
        if (fcntl(fd, F_SETFL, flags) < 0){
                perror("setting flags");
                exit(1);
        }

        if (fcntl(fd, F_SETOWN, getpid()) < 0) {
                perror("Setting SIGIO");
                exit(1);
        }

        printf("Drained the pool\n");
        read(fd, &n, sizeof(n));
        printf("Found more randomness\n");

        return(0);
}

Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Matt Mackall <mpm@selenic.com>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/random.c

index 2faeef28c209f99ccd4e1a62aa66563f474911ba..0cf98bd4f2d2438351357890a2cee00062b6c6da 100644 (file)
@@ -370,6 +370,7 @@ static struct poolinfo {
  */
 static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
 static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
+static struct fasync_struct *fasync;
 
 #if 0
 static int debug;
@@ -533,8 +534,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
                r->entropy_count = r->poolinfo->POOLBITS;
 
        /* should we wake readers? */
-       if (r == &input_pool && r->entropy_count >= random_read_wakeup_thresh)
+       if (r == &input_pool &&
+           r->entropy_count >= random_read_wakeup_thresh) {
                wake_up_interruptible(&random_read_wait);
+               kill_fasync(&fasync, SIGIO, POLL_IN);
+       }
 
        spin_unlock_irqrestore(&r->lock, flags);
 }
@@ -742,8 +746,10 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
                else
                        r->entropy_count = reserved;
 
-               if (r->entropy_count < random_write_wakeup_thresh)
+               if (r->entropy_count < random_write_wakeup_thresh) {
                        wake_up_interruptible(&random_write_wait);
+                       kill_fasync(&fasync, SIGIO, POLL_OUT);
+               }
        }
 
        DEBUG_ENT("debiting %d entropy credits from %s%s\n",
@@ -1100,17 +1106,31 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        }
 }
 
+static int random_fasync(int fd, struct file *filp, int on)
+{
+       return fasync_helper(fd, filp, on, &fasync);
+}
+
+static int random_release(struct inode *inode, struct file *filp)
+{
+       return fasync_helper(-1, filp, 0, &fasync);
+}
+
 const struct file_operations random_fops = {
        .read  = random_read,
        .write = random_write,
        .poll  = random_poll,
        .unlocked_ioctl = random_ioctl,
+       .fasync = random_fasync,
+       .release = random_release,
 };
 
 const struct file_operations urandom_fops = {
        .read  = urandom_read,
        .write = random_write,
        .unlocked_ioctl = random_ioctl,
+       .fasync = random_fasync,
+       .release = random_release,
 };
 
 /***************************************************************