]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/kfifo.c
h63xx: nfs mount works, gpe image boots to ts config screen.
[linux-2.6-omap-h63xx.git] / kernel / kfifo.c
index cee419143fd47bb410b0cf80e7762a0f02ffbfce..6d3e9999cf763e54e3b27665f7ab086053952771 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/kfifo.h>
+#include <linux/log2.h>
+#include <linux/uaccess.h>
 
 /**
  * kfifo_init - allocates a new FIFO using a preallocated buffer
@@ -41,7 +43,7 @@ struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
        struct kfifo *fifo;
 
        /* size must be a power of 2 */
-       BUG_ON(size & (size - 1));
+       BUG_ON(!is_power_of_2(size));
 
        fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
        if (!fifo)
@@ -194,3 +196,59 @@ unsigned int __kfifo_get(struct kfifo *fifo,
        return len;
 }
 EXPORT_SYMBOL(__kfifo_get);
+
+/**
+ * __kfifo_get_to_user - gets some data from the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied. user buffer.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * user @buffer and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int __kfifo_get_to_user(struct kfifo *fifo,
+                                unsigned char __user *buffer,
+                                unsigned int len)
+{
+       unsigned int n1, n2;
+       int ret;
+
+       len = min(len, fifo->in - fifo->out);
+
+       /*
+        * Ensure that we sample the fifo->in index -before- we
+        * start removing bytes from the kfifo.
+        */
+
+       smp_rmb();
+
+       /* first get the data from fifo->out until the end of the buffer */
+       n1 = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
+       n2 = len -n1;
+       ret = copy_to_user(buffer,
+                          fifo->buffer + (fifo->out & (fifo->size - 1)), n1);
+       if (ret) {
+               len = n1 - ret;
+               goto out;
+       }
+
+       /* then get the rest (if any) from the beginning of the buffer */
+       ret = copy_to_user(buffer + n1, fifo->buffer, n2);
+       if (ret)
+               len = n1 + n2 - ret;
+
+       /*
+        * Ensure that we remove the bytes from the kfifo -before-
+        * we update the fifo->out index.
+        */
+out:
+       smp_mb();
+
+       fifo->out += len;
+
+       return len;
+}
+EXPORT_SYMBOL(__kfifo_get_to_user);