diff options
author | Jeff Dike <jdike@addtoit.com> | 2008-04-29 04:03:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:25 -0400 |
commit | 9a6f70bbed4e8b72dd340812d7c606bfd5e00b47 (patch) | |
tree | 55158b087275b1848b5f0ad4e58eb2a2d47016c8 /drivers/char | |
parent | adc782dae6c4c0f6fb679a48a544cfbcd79ae3dc (diff) |
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: 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>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/random.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 2faeef28c209..0cf98bd4f2d2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -370,6 +370,7 @@ static struct poolinfo { | |||
370 | */ | 370 | */ |
371 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); | 371 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); |
372 | static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); | 372 | static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); |
373 | static struct fasync_struct *fasync; | ||
373 | 374 | ||
374 | #if 0 | 375 | #if 0 |
375 | static int debug; | 376 | static int debug; |
@@ -533,8 +534,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) | |||
533 | r->entropy_count = r->poolinfo->POOLBITS; | 534 | r->entropy_count = r->poolinfo->POOLBITS; |
534 | 535 | ||
535 | /* should we wake readers? */ | 536 | /* should we wake readers? */ |
536 | if (r == &input_pool && r->entropy_count >= random_read_wakeup_thresh) | 537 | if (r == &input_pool && |
538 | r->entropy_count >= random_read_wakeup_thresh) { | ||
537 | wake_up_interruptible(&random_read_wait); | 539 | wake_up_interruptible(&random_read_wait); |
540 | kill_fasync(&fasync, SIGIO, POLL_IN); | ||
541 | } | ||
538 | 542 | ||
539 | spin_unlock_irqrestore(&r->lock, flags); | 543 | spin_unlock_irqrestore(&r->lock, flags); |
540 | } | 544 | } |
@@ -742,8 +746,10 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, | |||
742 | else | 746 | else |
743 | r->entropy_count = reserved; | 747 | r->entropy_count = reserved; |
744 | 748 | ||
745 | if (r->entropy_count < random_write_wakeup_thresh) | 749 | if (r->entropy_count < random_write_wakeup_thresh) { |
746 | wake_up_interruptible(&random_write_wait); | 750 | wake_up_interruptible(&random_write_wait); |
751 | kill_fasync(&fasync, SIGIO, POLL_OUT); | ||
752 | } | ||
747 | } | 753 | } |
748 | 754 | ||
749 | DEBUG_ENT("debiting %d entropy credits from %s%s\n", | 755 | 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 | } | 1106 | } |
1101 | } | 1107 | } |
1102 | 1108 | ||
1109 | static int random_fasync(int fd, struct file *filp, int on) | ||
1110 | { | ||
1111 | return fasync_helper(fd, filp, on, &fasync); | ||
1112 | } | ||
1113 | |||
1114 | static int random_release(struct inode *inode, struct file *filp) | ||
1115 | { | ||
1116 | return fasync_helper(-1, filp, 0, &fasync); | ||
1117 | } | ||
1118 | |||
1103 | const struct file_operations random_fops = { | 1119 | const struct file_operations random_fops = { |
1104 | .read = random_read, | 1120 | .read = random_read, |
1105 | .write = random_write, | 1121 | .write = random_write, |
1106 | .poll = random_poll, | 1122 | .poll = random_poll, |
1107 | .unlocked_ioctl = random_ioctl, | 1123 | .unlocked_ioctl = random_ioctl, |
1124 | .fasync = random_fasync, | ||
1125 | .release = random_release, | ||
1108 | }; | 1126 | }; |
1109 | 1127 | ||
1110 | const struct file_operations urandom_fops = { | 1128 | const struct file_operations urandom_fops = { |
1111 | .read = urandom_read, | 1129 | .read = urandom_read, |
1112 | .write = random_write, | 1130 | .write = random_write, |
1113 | .unlocked_ioctl = random_ioctl, | 1131 | .unlocked_ioctl = random_ioctl, |
1132 | .fasync = random_fasync, | ||
1133 | .release = random_release, | ||
1114 | }; | 1134 | }; |
1115 | 1135 | ||
1116 | /*************************************************************** | 1136 | /*************************************************************** |