diff -urpNX dontdiff linux-2.5.50/drivers/char/random.c linux-2.5.50-random/drivers/char/random.c
--- linux-2.5.50/drivers/char/random.c  2002-11-17 23:29:22.000000000 -0500
+++ linux-2.5.50-random/drivers/char/random.c   2002-11-29 17:03:10.000000000 -0500
@@ -240,25 +240,25 @@
 * Eastlake, Steve Crocker, and Jeff Schiller.
 */

-#include <linux/utsname.h>
#include <linux/config.h>
-#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/utsname.h>
+#include <linux/wait.h>
#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/workqueue.h>
-#include <linux/genhd.h>

#include <asm/processor.h>
#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/io.h>

/*
 * Configuration information
@@ -341,7 +341,7 @@ static struct poolinfo {
 * (See M. Matsumoto & Y. Kurita, 1992.  Twisted GFSR generators.  ACM
 * Transactions on Modeling and Computer Simulation 2(3):179-194.
 * Also see M. Matsumoto & Y. Kurita, 1994.  Twisted GFSR generators
- * II.  ACM Transactions on Mdeling and Computer Simulation 4:254-266)
+ * II.  ACM Transactions on Modeling and Computer Simulation 4:254-266)
 *
 * Thanks to Colin Plumb for suggesting this.
 *
@@ -625,23 +625,43 @@ static __u32      *batch_entropy_pool;
static int     *batch_entropy_credit;
static int     batch_max;
static int     batch_head, batch_tail;
-static void batch_entropy_process(void *private_);
-static DECLARE_WORK(batch_work, batch_entropy_process, NULL);
+
+/*
+ * entropy_lock protects these 5 variables and the data they point to.
+ * Is acquired in interrupt context so must be acquired in process or BH
+ * context with interrupts disabled.
+ */
+static spinlock_t entropy_lock = SPIN_LOCK_UNLOCKED;
+
+static void batch_entropy_process(unsigned long private_);
+static DECLARE_TASKLET(batch_work, batch_entropy_process, 0);
+struct entropy_data {
+       __u32   entropy[2];
+       int     credit;
+};

/* note: the size must be a power of 2 */
static int __init batch_entropy_init(int size, struct entropy_store *r)
{
-       batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL);
-       if (!batch_entropy_pool)
+       void *pool, *credit;
+
+       pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL);
+       if (!pool)
               return -1;
-       batch_entropy_credit =kmalloc(size*sizeof(int), GFP_KERNEL);
-       if (!batch_entropy_credit) {
-               kfree(batch_entropy_pool);
+       credit = kmalloc(size*sizeof(int), GFP_KERNEL);
+       if (!credit) {
+               kfree(pool);
               return -1;
       }
+
+       spin_lock_irq(&entropy_lock);
+       batch_entropy_pool = pool;
+       batch_entropy_credit = credit;
       batch_head = batch_tail = 0;
       batch_max = size;
-       batch_work.data = r;
+       batch_work.data = (unsigned long)r;
+       spin_unlock_irq(&entropy_lock);
+
       return 0;
}

@@ -649,15 +669,21 @@ static int __init batch_entropy_init(int
 * Changes to the entropy data is put into a queue rather than being added to
 * the entropy counts directly.  This is presumably to avoid doing heavy
 * hashing calculations during an interrupt in add_timer_randomness().
- * Instead, the entropy is only added to the pool by keventd.
+ * Instead, the entropy is added to the pool next time we run the tasklets.
 */
void batch_entropy_store(u32 a, u32 b, int num)
{
       int     new;
+       unsigned long flags;

       if (!batch_max)
               return;
-
+
+       /*
+        * This function is _probably_ only called in irq context, but
+        * better safe than sorry.
+        */
+       spin_lock_irqsave(&entropy_lock, flags);
       batch_entropy_pool[2*batch_head] = a;
       batch_entropy_pool[(2*batch_head) + 1] = b;
       batch_entropy_credit[batch_head] = num;
@@ -667,11 +693,12 @@ void batch_entropy_store(u32 a, u32 b, i
               /*
                * Schedule it for the next timer tick:
                */
-               schedule_delayed_work(&batch_work, 1);
+               tasklet_schedule(&batch_work);
               batch_head = new;
       } else {
               DEBUG_ENT("batch entropy buffer full\n");
       }
+       spin_unlock_irqrestore(&entropy_lock, flags);
}

/*
@@ -679,25 +706,34 @@ void batch_entropy_store(u32 a, u32 b, i
 * store (normally random_state).  If that store has enough entropy, alternate
 * between randomizing the data of the primary and secondary stores.
 */
-static void batch_entropy_process(void *private_)
+static void batch_entropy_process(unsigned long private_)
{
       struct entropy_store *r = (struct entropy_store *) private_, *p;
       int max_entropy = r->poolinfo.POOLBITS;
+       struct entropy_data cache;

       if (!batch_max)
               return;

       p = r;
+       spin_lock_irq(&entropy_lock);
       while (batch_head != batch_tail) {
+               cache.entropy[0] = batch_entropy_pool[2*batch_tail];
+               cache.entropy[1] = batch_entropy_pool[2*batch_tail + 1];
+               cache.credit = batch_entropy_credit[batch_tail];
+               batch_tail = (batch_tail+1) & (batch_max-1);
+               spin_unlock_irq(&entropy_lock);
+
               if (r->entropy_count >= max_entropy) {
                       r = (r == sec_random_state) ?   random_state :
                                                       sec_random_state;
                       max_entropy = r->poolinfo.POOLBITS;
               }
-               add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2);
-               credit_entropy_store(r, batch_entropy_credit[batch_tail]);
-               batch_tail = (batch_tail+1) & (batch_max-1);
+               add_entropy_words(r, cache.entropy, 2);
+               credit_entropy_store(r, cache.credit);
+               spin_lock_irq(&entropy_lock);
       }
+       spin_unlock_irq(&entropy_lock);
       if (p->entropy_count >= random_read_wakeup_thresh)
               wake_up_interruptible(&random_read_wait);
}
@@ -1738,7 +1774,8 @@ static int change_poolsize(int poolsize)

       sysctl_init_random(new_store);
       old_store = random_state;
-       random_state = batch_work.data = new_store;
+       random_state = new_store;
+       batch_work.data = (unsigned long)new_store;
       free_entropy_store(old_store);
       return 0;
}