2008-05-13 05:01:59 +08:00
|
|
|
/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
|
|
|
|
|
2005-05-29 06:51:58 +08:00
|
|
|
/* Much of this ripped from drivers/char/hw_random.c, see there for other
|
|
|
|
* copyright.
|
|
|
|
*
|
|
|
|
* This software may be used and distributed according to the terms
|
|
|
|
* of the GNU General Public License, incorporated herein by reference.
|
|
|
|
*/
|
uml: header untangling
Untangle UML headers somewhat and add some includes where they were
needed explicitly, but gotten accidentally via some other header.
arch/um/include/um_uaccess.h loses asm/fixmap.h because it uses no
fixmap stuff and gains elf.h, because it needs FIXADDR_USER_*, and
archsetjmp.h, because it needs jmp_buf.
pmd_alloc_one is uninlined because it needs mm_struct, and that's
inconvenient to provide in asm-um/pgtable-3level.h.
elf_core_copy_fpregs is also uninlined from elf-i386.h and
elf-x86_64.h, which duplicated the code anyway, to
arch/um/kernel/process.c, so that the reference to current_thread
doesn't pull sched.h or anything related into asm/elf.h.
arch/um/sys-i386/ldt.c, arch/um/kernel/tlb.c and
arch/um/kernel/skas/uaccess.c got sched.h because they dereference
task_structs. Its includes of linux and asm headers got turned from
"" to <>.
arch/um/sys-i386/bug.c gets asm/errno.h because it needs errno
constants.
asm/elf-i386 gets asm/user.h because it needs user_regs_struct.
asm/fixmap.h gets page.h because it needs PAGE_SIZE and PAGE_MASK and
system.h for BUG_ON.
asm/pgtable doesn't need sched.h.
asm/processor-generic.h defined mm_segment_t, but didn't use it. So,
that definition is moved to uaccess.h, which defines a bunch of
mm_segment_t-related stuff. thread_info.h uses mm_segment_t, and
includes uaccess.h, which causes a recursion. So, the definition is
placed above the include of thread_info. in uaccess.h. thread_info.h
also gets page.h because it needs PAGE_SIZE.
ObCheckpatchViolationJustification - I'm not adding a typedef; I'm
moving mm_segment_t from one place to another.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-05 14:30:53 +08:00
|
|
|
#include <linux/sched.h>
|
2008-05-21 01:16:57 +08:00
|
|
|
#include <linux/smp_lock.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/fs.h>
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
#include <linux/interrupt.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/miscdevice.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <asm/uaccess.h>
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
#include "irq_kern.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
#include "os.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* core module and version information
|
|
|
|
*/
|
|
|
|
#define RNG_VERSION "1.0.0"
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
#define RNG_MODULE_NAME "hw_random"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#define RNG_MISCDEV_MINOR 183 /* official */
|
|
|
|
|
2006-09-29 16:58:50 +08:00
|
|
|
/* Changed at init time, in the non-modular case, and at module load
|
|
|
|
* time, in the module case. Presumably, the module subsystem
|
|
|
|
* protects against a module being loaded twice at the same time.
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
static int random_fd = -1;
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(host_read_wait);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
static int rng_dev_open (struct inode *inode, struct file *filp)
|
|
|
|
{
|
2008-05-21 01:16:57 +08:00
|
|
|
cycle_kernel_lock();
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* enforce read-only access to this chrdev */
|
|
|
|
if ((filp->f_mode & FMODE_READ) == 0)
|
|
|
|
return -EINVAL;
|
2008-05-13 05:01:59 +08:00
|
|
|
if ((filp->f_mode & FMODE_WRITE) != 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
static atomic_t host_sleep_count = ATOMIC_INIT(0);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
|
2008-05-13 05:01:59 +08:00
|
|
|
loff_t *offp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-05-13 05:01:59 +08:00
|
|
|
u32 data;
|
|
|
|
int n, ret = 0, have_data;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
n = os_read_file(random_fd, &data, sizeof(data));
|
|
|
|
if (n > 0) {
|
|
|
|
have_data = n;
|
|
|
|
while (have_data && size) {
|
|
|
|
if (put_user((u8) data, buf++)) {
|
|
|
|
ret = ret ? : -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
size--;
|
|
|
|
ret++;
|
|
|
|
have_data--;
|
|
|
|
data >>= 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (n == -EAGAIN) {
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
|
2008-05-13 05:01:59 +08:00
|
|
|
if (filp->f_flags & O_NONBLOCK)
|
|
|
|
return ret ? : -EAGAIN;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
atomic_inc(&host_sleep_count);
|
|
|
|
reactivate_fd(random_fd, RANDOM_IRQ);
|
|
|
|
add_sigio_fd(random_fd);
|
|
|
|
|
|
|
|
add_wait_queue(&host_read_wait, &wait);
|
|
|
|
set_task_state(current, TASK_INTERRUPTIBLE);
|
|
|
|
|
|
|
|
schedule();
|
|
|
|
set_task_state(current, TASK_RUNNING);
|
|
|
|
remove_wait_queue(&host_read_wait, &wait);
|
|
|
|
|
|
|
|
if (atomic_dec_and_test(&host_sleep_count)) {
|
|
|
|
ignore_sigio_fd(random_fd);
|
|
|
|
deactivate_fd(random_fd, RANDOM_IRQ);
|
|
|
|
}
|
2008-05-13 05:01:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return n;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (signal_pending (current))
|
|
|
|
return ret ? : -ERESTARTSYS;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-09-27 16:50:33 +08:00
|
|
|
static const struct file_operations rng_chrdev_ops = {
|
2005-04-17 06:20:36 +08:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.open = rng_dev_open,
|
|
|
|
.read = rng_dev_read,
|
|
|
|
};
|
|
|
|
|
2007-02-10 17:44:05 +08:00
|
|
|
/* rng_init shouldn't be called more than once at boot time */
|
2005-04-17 06:20:36 +08:00
|
|
|
static struct miscdevice rng_miscdev = {
|
|
|
|
RNG_MISCDEV_MINOR,
|
|
|
|
RNG_MODULE_NAME,
|
|
|
|
&rng_chrdev_ops,
|
|
|
|
};
|
|
|
|
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
static irqreturn_t random_interrupt(int irq, void *data)
|
|
|
|
{
|
|
|
|
wake_up(&host_read_wait);
|
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* rng_init - initialize RNG module
|
|
|
|
*/
|
|
|
|
static int __init rng_init (void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2008-05-13 05:01:59 +08:00
|
|
|
err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
|
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-05-13 05:01:59 +08:00
|
|
|
random_fd = err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
|
|
|
|
IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "random",
|
|
|
|
NULL);
|
2008-05-13 05:01:59 +08:00
|
|
|
if (err)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_out_cleanup_hw;
|
|
|
|
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
sigio_broken(random_fd, 1);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
err = misc_register (&rng_miscdev);
|
|
|
|
if (err) {
|
2008-05-13 05:01:59 +08:00
|
|
|
printk (KERN_ERR RNG_MODULE_NAME ": misc device register "
|
|
|
|
"failed\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_out_cleanup_hw;
|
|
|
|
}
|
2008-05-13 05:01:59 +08:00
|
|
|
out:
|
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-05-13 05:01:59 +08:00
|
|
|
err_out_cleanup_hw:
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
os_close_file(random_fd);
|
2008-05-13 05:01:59 +08:00
|
|
|
random_fd = -1;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* rng_cleanup - shutdown RNG module
|
|
|
|
*/
|
|
|
|
static void __exit rng_cleanup (void)
|
|
|
|
{
|
uml: random driver fixes
The random driver would essentially hang if the host's /dev/random returned
-EAGAIN. There was a test of need_resched followed by a schedule inside the
loop, but that didn't help and it's the wrong way to work anyway.
The right way is to ask for an interrupt when there is input available from
the host and handle it then rather than polling.
Now, when the host's /dev/random returns -EAGAIN, the driver asks for a wakeup
when there's randomness available again and sleeps. The interrupt routine
just wakes up whatever processes are sleeping on host_read_wait.
There is an atomic_t, host_sleep_count, which counts the number of processes
waiting for randomness. When this reaches zero, the interrupt is disabled.
An added complication is that async I/O notification was only recently added
to /dev/random (by me), so essentially all hosts will lack it. So, we use the
sigio workaround here, which is to have a separate thread poll on the
descriptor and send an interrupt when there is input on it. This mechanism is
activated when a process gets -EAGAIN (activating this multiple times is
harmless, if a bit wasteful) and deactivated by the last process still
waiting.
The module name was changed from "random" to "hw_random" in order for udev to
recognize it.
The sigio workaround needed some changes. sigio_broken was added for cases
when we know that async notification doesn't work. This is now called from
maybe_sigio_broken, which deals with pts devices.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-05-13 05:01:58 +08:00
|
|
|
os_close_file(random_fd);
|
2005-04-17 06:20:36 +08:00
|
|
|
misc_deregister (&rng_miscdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init (rng_init);
|
|
|
|
module_exit (rng_cleanup);
|
2005-05-29 06:51:58 +08:00
|
|
|
|
|
|
|
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
|
|
|
|
MODULE_LICENSE("GPL");
|