#include <linux/kmemcheck.h>
 #include <linux/workqueue.h>
 #include <linux/irq.h>
+#include <linux/syscalls.h>
+#include <linux/completion.h>
 
 #include <asm/processor.h>
 #include <asm/uaccess.h>
  */
 static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
 static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
+static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait);
 static struct fasync_struct *fasync;
 
 /**********************************************************************
                r->entropy_total = 0;
                if (r == &nonblocking_pool) {
                        prandom_reseed_late();
+                       wake_up_interruptible(&urandom_init_wait);
                        pr_notice("random: %s pool is initialized\n", r->name);
                }
        }
 {
        ssize_t ret = 0, i;
        __u8 tmp[EXTRACT_SIZE];
+       int large_request = (nbytes > 256);
 
        trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
        xfer_secondary_pool(r, nbytes);
        nbytes = account(r, nbytes, 0, 0);
 
        while (nbytes) {
-               if (need_resched()) {
+               if (large_request && need_resched()) {
                        if (signal_pending(current)) {
                                if (ret == 0)
                                        ret = -ERESTARTSYS;
 }
 
 static ssize_t
-random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+_random_read(int nonblock, char __user *buf, size_t nbytes)
 {
        ssize_t n;
 
                if (arch_random_refill())
                        continue;
 
-               if (file->f_flags & O_NONBLOCK)
+               if (nonblock)
                        return -EAGAIN;
 
                wait_event_interruptible(random_read_wait,
        }
 }
 
+static ssize_t
+random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+{
+       return _random_read(file->f_flags & O_NONBLOCK, buf, nbytes);
+}
+
 static ssize_t
 urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
        .llseek = noop_llseek,
 };
 
+SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+               unsigned int, flags)
+{
+       if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
+               return -EINVAL;
+
+       if (count > INT_MAX)
+               count = INT_MAX;
+
+       if (flags & GRND_RANDOM)
+               return _random_read(flags & GRND_NONBLOCK, buf, count);
+
+       if (unlikely(nonblocking_pool.initialized == 0)) {
+               if (flags & GRND_NONBLOCK)
+                       return -EAGAIN;
+               wait_event_interruptible(urandom_init_wait,
+                                        nonblocking_pool.initialized);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+       return urandom_read(NULL, buf, count, NULL);
+}
+
 /***************************************************************
  * Random UUID interface
  *