Commit 9a6f70bb authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

random: add async notification support to /dev/random

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: default avatarJeff Dike <jdike@linux.intel.com>
Signed-off-by: default avatarMatt Mackall <mpm@selenic.com>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent adc782da
...@@ -370,6 +370,7 @@ static struct poolinfo { ...@@ -370,6 +370,7 @@ static struct poolinfo {
*/ */
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
static struct fasync_struct *fasync;
#if 0 #if 0
static int debug; static int debug;
...@@ -533,8 +534,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) ...@@ -533,8 +534,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
r->entropy_count = r->poolinfo->POOLBITS; r->entropy_count = r->poolinfo->POOLBITS;
/* should we wake readers? */ /* 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); wake_up_interruptible(&random_read_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&r->lock, flags); spin_unlock_irqrestore(&r->lock, flags);
} }
...@@ -742,8 +746,10 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, ...@@ -742,8 +746,10 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
else else
r->entropy_count = reserved; 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); wake_up_interruptible(&random_write_wait);
kill_fasync(&fasync, SIGIO, POLL_OUT);
}
} }
DEBUG_ENT("debiting %d entropy credits from %s%s\n", 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) ...@@ -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 = { const struct file_operations random_fops = {
.read = random_read, .read = random_read,
.write = random_write, .write = random_write,
.poll = random_poll, .poll = random_poll,
.unlocked_ioctl = random_ioctl, .unlocked_ioctl = random_ioctl,
.fasync = random_fasync,
.release = random_release,
}; };
const struct file_operations urandom_fops = { const struct file_operations urandom_fops = {
.read = urandom_read, .read = urandom_read,
.write = random_write, .write = random_write,
.unlocked_ioctl = random_ioctl, .unlocked_ioctl = random_ioctl,
.fasync = random_fasync,
.release = random_release,
}; };
/*************************************************************** /***************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment