All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 7/7] new kfifo API
@ 2009-08-11 22:32 Stefani Seibold
  0 siblings, 0 replies; only message in thread
From: Stefani Seibold @ 2009-08-11 22:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: Andrew Morton, Arnd Bergmann, Andi Kleen

include/linux/kfifo.h |  381 ++++++++++++++++++++++++++++++++++++++++++++++++--
 kernel/kfifo.c        |  275 ++++++++++++++++++++++++------------
 2 files changed, 551 insertions(+), 105 deletions(-)

Signed-off-by: Stefani Seibold <stefani@seibold.net>

diff -u -N -r linux-2.6.31-rc4-kfifo6/include/linux/kfifo.h linux-2.6.31-rc4-kfifo7/include/linux/kfifo.h
--- linux-2.6.31-rc4-kfifo6/include/linux/kfifo.h	2009-08-11 22:53:41.000000000 +0200
+++ linux-2.6.31-rc4-kfifo7/include/linux/kfifo.h	2009-08-12 00:02:51.000000000 +0200
@@ -60,9 +60,9 @@
 			unsigned int size, gfp_t gfp_mask);
 extern void kfifo_free(struct kfifo *fifo);
 extern __must_check unsigned int kfifo_in(struct kfifo *fifo,
-				const unsigned char *buffer, unsigned int len);
+				const unsigned char *from, unsigned int len);
 extern __must_check unsigned int kfifo_out(struct kfifo *fifo,
-				unsigned char *buffer, unsigned int len);
+				unsigned char *to, unsigned int len);
 
 /**
  * kfifo_reset - removes the entire FIFO contents
@@ -83,7 +83,7 @@
 }
 
 /**
- * kfifo_reset_in - skip output FIFO contents
+ * kfifo_reset_out - skip output FIFO contents
  * @fifo: the fifo to be emptied.
  */
 static inline void kfifo_reset_out(struct kfifo *fifo)
@@ -92,6 +92,15 @@
 }
 
 /**
+ * kfifo_is_empty - returns true if the fifo is empty
+ * @fifo: the fifo to be used.
+ */
+static inline __must_check int kfifo_is_empty(struct kfifo *fifo)
+{
+	return fifo->in == fifo->out;
+}
+
+/**
  * kfifo_in_locked - puts some data into the FIFO using a spinlock for locking
  * @fifo: the fifo to be used.
  * @buffer: the data to be added.
@@ -141,8 +150,8 @@
 	 * optimization: if the FIFO is empty, set the indices to 0
 	 * so we don't wrap the next time
 	 */
-	if (fifo->in == fifo->out)
-		fifo->in = fifo->out = 0;
+	if (kfifo_is_empty(fifo))
+		kfifo_reset(fifo);
 
 	spin_unlock_irqrestore(lock, flags);
 
@@ -172,15 +181,6 @@
 }
 
 /**
- * kfifo_is_empty - returns true if the fifo is empty
- * @fifo: the fifo to be used.
- */
-static inline __must_check int kfifo_is_empty(struct kfifo *fifo)
-{
-	return fifo->in == fifo->out;
-}
-
-/**
  * kfifo_is_full - returns true if the fifo is full
  * @fifo: the fifo to be used.
  */
@@ -204,4 +204,357 @@
 extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo,
 	void __user *to, unsigned int n);
 
+/**
+ * __kfifo_add_out internal helper function for updating the out offset
+ */
+static inline void __kfifo_add_out(struct kfifo *fifo,
+				unsigned int off)
+{
+	smp_mb();
+	fifo->out += off;
+}
+
+/**
+ * __kfifo_add_in internal helper function for updating the in offset
+ */
+static inline void __kfifo_add_in(struct kfifo *fifo,
+				unsigned int off)
+{
+	smp_wmb();
+	fifo->in += off;
+}
+
+/**
+ * __kfifo_off internal helper function for calculating the index of a
+ * given offeset
+ */
+static inline unsigned int __kfifo_off(struct kfifo *fifo, unsigned int off)
+{
+	return off & (fifo->size-1);
+}
+
+/**
+ * __kfifo_peek_n internal helper function for determinate the length of
+ * the next record in the fifo
+ */
+static inline unsigned int __kfifo_peek_n(struct kfifo *fifo,
+				unsigned int recsize)
+{
+#define	KFIFO_GET(fifo, off, shift) \
+	((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift))
+
+	unsigned int l;
+
+	l = KFIFO_GET(fifo, 0, 0);
+
+	if (unlikely(--recsize))
+		l |= KFIFO_GET(fifo, 1, 8);
+
+	return l;
+}
+
+/**
+ * __kfifo_poke_n internal helper function for storing the length of
+ * the next record into the fifo
+ */
+static inline void __kfifo_poke_n(struct kfifo *fifo,
+			unsigned int recsize, unsigned int n)
+{
+#define	KFIFO_PUT(fifo, off, val, shift) \
+		( \
+		(fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \
+		(unsigned char)((val) >> (shift)) \
+		)
+
+	KFIFO_PUT(fifo, 0, n, 0);
+
+	if (unlikely(--recsize))
+		KFIFO_PUT(fifo, 1, n, 8);
+}
+
+/**
+ * __kfifo_in_... internal functions for put date into the fifo
+ * do not call it directly, use kfifo_in_rec() instead
+ */
+extern unsigned int __kfifo_in_n(struct kfifo *fifo,
+	const unsigned char *from, unsigned int n, unsigned int recsize);
+
+extern unsigned int __kfifo_in_generic(struct kfifo *fifo,
+	const unsigned char *from, unsigned int n, unsigned int recsize);
+
+static inline unsigned int __kfifo_in_rec(struct kfifo *fifo,
+	const unsigned char *from, unsigned int n, unsigned int recsize)
+{
+	unsigned int ret;
+
+	ret = __kfifo_in_n(fifo, from, n, recsize);
+
+	if (ret > n)
+		return ret;
+
+	if (likely(ret == 0)) {
+		if (recsize)
+			__kfifo_poke_n(fifo, recsize, n);
+		__kfifo_add_in(fifo, n + recsize);
+	}
+	return ret;
+}
+
+/**
+ * kfifo_in_rec - puts some record data into the FIFO
+ * @fifo: the fifo to be used.
+ * @from: the data to be added.
+ * @n: the length of the data to be added.
+ * @recsize: size of record field
+ *
+ * This function copies @n bytes from the @from into
+ * the FIFO and returns the number of bytes which cannot be copied.
+ * A returned value greater than the @n value means that the record doesn't
+ * fit into the buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_in_rec(struct kfifo *fifo,
+	unsigned char *from, unsigned int n, unsigned int recsize)
+{
+	if (!__builtin_constant_p(recsize))
+		return __kfifo_in_generic(fifo, from, n, recsize);
+
+	return __kfifo_in_rec(fifo, from, n, recsize);
+}
+
+/**
+ * __kfifo_out_... internal functions for get date from the fifo
+ * do not call it directly, use kfifo_out_rec() instead
+ */
+extern unsigned int __kfifo_out_n(struct kfifo *fifo,
+	unsigned char *to, unsigned int n, unsigned int reclen,
+	unsigned int recsize);
+
+extern unsigned int __kfifo_out_generic(struct kfifo *fifo,
+	unsigned char *to, unsigned int n,
+	unsigned int recsize, unsigned int *total);
+
+static inline unsigned int __kfifo_out_rec(struct kfifo *fifo,
+	unsigned char *to, unsigned int n, unsigned int recsize,
+	unsigned int *total)
+{
+	unsigned int l;
+
+	if (!recsize) {
+		l = n;
+		if (total)
+			*total = l;
+	} else {
+		l = __kfifo_peek_n(fifo, recsize);
+		if (total)
+			*total = l;
+		if (n < l)
+			return l;
+	}
+
+	return __kfifo_out_n(fifo, to, n, l, recsize);
+}
+
+/**
+ * kfifo_out_rec - gets some record data from the FIFO
+ * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ * @recsize: size of record field
+ * @total: pointer where the total number of to copied bytes should stored
+ *
+ * This function copies at most @n bytes from the @to into
+ * the FIFO and returns the number of bytes which cannot be copied.
+ * A returned value greater than the @n value means that the record doesn't
+ * fit into the @to buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_out_rec(struct kfifo *fifo,
+	unsigned char *to, unsigned int n, unsigned int recsize,
+	unsigned int *total)
+
+{
+	if (!__builtin_constant_p(recsize))
+		return __kfifo_out_generic(fifo, to, n, recsize, total);
+
+	return __kfifo_out_rec(fifo, to, n, recsize, total);
+}
+
+/**
+ * __kfifo_from_user_... internal functions for transfer from user space into
+ * the fifo. do not call it directly, use kfifo_from_user_rec() instead
+ */
+extern unsigned int __kfifo_from_user_n(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize);
+
+extern unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize);
+
+static inline unsigned int __kfifo_from_user_rec(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize)
+{
+	unsigned int ret;
+
+	ret = __kfifo_from_user_n(fifo, from, n, recsize);
+
+	if (ret > n)
+		return ret;
+
+	if (likely(ret == 0)) {
+		if (recsize)
+			__kfifo_poke_n(fifo, recsize, n);
+		__kfifo_add_in(fifo, n + recsize);
+	}
+	return ret;
+}
+
+/**
+ * kfifo_from_user_rec - puts some data from user space into the FIFO
+ * @fifo: the fifo to be used.
+ * @from: pointer to the data to be added.
+ * @n: the length of the data to be added.
+ * @recsize: size of record field
+ *
+ * This function copies @n bytes from the @from into the
+ * FIFO and returns the number of bytes which cannot be copied.
+ *
+ * If the returned value is equal or less the @n value, the copy_from_user()
+ * functions has failed. Otherwise the record doesn't fit into the buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_from_user_rec(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize)
+{
+	if (__builtin_constant_p(recsize))
+		return __kfifo_from_user_rec(fifo, from, n, recsize);
+	return __kfifo_from_user_generic(fifo, from, n, recsize);
+}
+
+/**
+ * __kfifo_to_user_... internal functions for transfer fifo data into user space
+ * do not call it directly, use kfifo_to_user_rec() instead
+ */
+extern unsigned int __kfifo_to_user_n(struct kfifo *fifo,
+	void __user *to, unsigned int n, unsigned int reclen,
+	unsigned int recsize);
+
+extern unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
+	void __user *to, unsigned int n, unsigned int recsize,
+	unsigned int *total);
+
+static inline unsigned int __kfifo_to_user_rec(struct kfifo *fifo,
+	void __user *to, unsigned int n,
+	unsigned int recsize, unsigned int *total)
+{
+	unsigned int l;
+
+	if (!recsize) {
+		l = n;
+		if (total)
+			*total = l;
+	} else {
+		l = __kfifo_peek_n(fifo, recsize);
+		if (total)
+			*total = l;
+		if (n < l)
+			return l;
+	}
+
+	return __kfifo_to_user_n(fifo, to, n, l, recsize);
+}
+
+/**
+ * kfifo_to_user_rec - gets data from the FIFO and write it to user space
+ * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ * @recsize: size of record field
+ * @total: pointer where the total number of to copied bytes should stored
+ *
+ * This function copies at most @n bytes from the FIFO into the
+ * @to.
+ * In case of an error, the function returns the number of bytes which cannot
+ * be copied.
+ * If the returned value is equal or less the @n value, the copy_to_user()
+ * functions has failed. Otherwise the record doesn't fit into the @to buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_to_user_rec(struct kfifo *fifo,
+		void __user *to, unsigned int n, unsigned int recsize,
+		unsigned int *total)
+{
+	if (__builtin_constant_p(recsize))
+		return __kfifo_to_user_rec(fifo, to, n, recsize, total);
+	return __kfifo_to_user_generic(fifo, to, n, recsize, total);
+}
+
+/**
+ * __kfifo_peek_... internal functions for peek into the next fifo record
+ * do not call it directly, use kfifo_peek_rec() instead
+ */
+extern unsigned int __kfifo_peek_generic(struct kfifo *fifo,
+				unsigned int recsize);
+
+/**
+ * kfifo_peek_rec - gets the size of the next FIFO record data
+ * @fifo: the fifo to be used.
+ * @recsize: size of record field
+ *
+ * This function returns the size of the next FIFO record in number of bytes
+ */
+static inline __must_check unsigned int kfifo_peek_rec(struct kfifo *fifo,
+	unsigned int recsize)
+{
+	if (__builtin_constant_p(recsize)) {
+		if (!recsize)
+			return kfifo_len(fifo);
+		return __kfifo_peek_n(fifo, recsize);
+	}
+	return __kfifo_peek_generic(fifo, recsize);
+}
+
+/**
+ * __kfifo_skip_... internal functions for peek into the next fifo record
+ * do not call it directly, use kfifo_skip_rec() instead
+ */
+extern unsigned int __kfifo_peek_generic(struct kfifo *fifo,
+				unsigned int recsize);
+
+static inline __must_check void __kfifo_skip_rec(struct kfifo *fifo,
+	unsigned int recsize)
+{
+	if (!recsize)
+		kfifo_reset_out(fifo);
+
+	l = __kfifo_peek_n(fifo, recsize);
+
+	if (l + recsize > kfifo_len())
+		kfifo_reset_out(fifo);
+
+	__kfifo_add_out(fifo, l + recsize);
+}
+
+/**
+ * kfifo_skip_rec - skip the next output record
+ * @fifo: the fifo to be used.
+ * @recsize: size of record field
+ *
+ * This function skips the next FIFO record
+ */
+static inline __must_check unsigned int kfifo_skip_rec(struct kfifo *fifo,
+	unsigned int recsize)
+{
+	if (__builtin_constant_p(recsize))
+		return __kfifo_skip_rec(fifo, recsize);
+	return __kfifo_skip_generic(fifo, recsize);
+}
+
 #endif
diff -u -N -r linux-2.6.31-rc4-kfifo6/kernel/kfifo.c linux-2.6.31-rc4-kfifo7/kernel/kfifo.c
--- linux-2.6.31-rc4-kfifo6/kernel/kfifo.c	2009-08-11 22:33:15.000000000 +0200
+++ linux-2.6.31-rc4-kfifo7/kernel/kfifo.c	2009-08-11 23:44:27.000000000 +0200
@@ -99,26 +99,11 @@
 }
 EXPORT_SYMBOL(kfifo_free);
 
-/**
- * kfifo_in - puts some data into the FIFO, no locking version
- * @fifo: the fifo to be used.
- * @buffer: the data to be added.
- * @len: the length of the data to be added.
- *
- * This function copies at most @len bytes from the @buffer into
- * the FIFO depending on the free space, and returns the number of
- * bytes copied.
- *
- * Note that with only one concurrent reader and one concurrent
- * writer, you don't need extra locking to use these functions.
- */
-unsigned int kfifo_in(struct kfifo *fifo,
-			const unsigned char *buffer, unsigned int len)
+static inline void __kfifo_in_data(struct kfifo *fifo,
+		const unsigned char *from, unsigned int n, unsigned int off)
 {
 	unsigned int l;
 
-	len = min(len, fifo->size - fifo->in + fifo->out);
-
 	/*
 	 * Ensure that we sample the fifo->out index -before- we
 	 * start putting bytes into the kfifo.
@@ -126,44 +111,62 @@
 
 	smp_mb();
 
+	off += __kfifo_off(fifo, fifo->in+off);
+
 	/* first put the data starting from fifo->in to buffer end */
-	l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
-	memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
+	l = min(n, fifo->size - off);
+	memcpy(fifo->buffer + off, from, l);
 
 	/* then put the rest (if any) at the beginning of the buffer */
-	memcpy(fifo->buffer, buffer + l, len - l);
-
-	/*
-	 * Ensure that we add the bytes to the kfifo -before-
-	 * we update the fifo->in index.
-	 */
-
-	smp_wmb();
+	memcpy(fifo->buffer, from + l, n - l);
+}
 
-	fifo->in += len;
+unsigned int __kfifo_in_n(struct kfifo *fifo,
+	const unsigned char *from, unsigned int n, unsigned int recsize)
+{
+	if (kfifo_avail(fifo) < n + recsize)
+		return n + 1;
 
-	return len;
+	__kfifo_in_data(fifo, from, n, recsize);
+	return 0;
 }
-EXPORT_SYMBOL(kfifo_in);
+EXPORT_SYMBOL(__kfifo_in_n);
 
 /**
- * kfifo_out - gets some data from the FIFO, no locking version
+ * kfifo_in - puts some data into the FIFO
  * @fifo: the fifo to be used.
- * @buffer: where the data must be copied.
- * @len: the size of the destination buffer.
+ * @from: the data to be added.
+ * @n: the length of the data to be added.
  *
- * This function copies at most @len bytes from the FIFO into the
- * @buffer and returns the number of copied bytes.
+ * This function copies at most @n bytes from @from into
+ * the FIFO depending on the free space, and returns the number of
+ * bytes copied.
  *
  * Note that with only one concurrent reader and one concurrent
  * writer, you don't need extra locking to use these functions.
  */
-unsigned int kfifo_out(struct kfifo *fifo,
-			 unsigned char *buffer, unsigned int len)
+unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from,
+				unsigned int n)
 {
-	unsigned int l;
+	n = min(kfifo_avail(fifo), n);
 
-	len = min(len, fifo->in - fifo->out);
+	__kfifo_in_data(fifo, from, n, 0);
+	__kfifo_add_in(fifo, n);
+	return n;
+}
+EXPORT_SYMBOL(kfifo_in);
+
+unsigned int __kfifo_in_generic(struct kfifo *fifo,
+	const unsigned char *from, unsigned int n, unsigned int recsize)
+{
+	return __kfifo_in_rec(fifo, from, n, recsize);
+}
+EXPORT_SYMBOL(__kfifo_in_generic);
+
+static inline void __kfifo_out_data(struct kfifo *fifo,
+		unsigned char *to, unsigned int n, unsigned int off)
+{
+	unsigned int l;
 
 	/*
 	 * Ensure that we sample the fifo->in index -before- we
@@ -172,47 +175,66 @@
 
 	smp_rmb();
 
+	off += __kfifo_off(fifo, fifo->out+off);
+
 	/* first get the data from fifo->out until the end of the buffer */
-	l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
-	memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
+	l = min(n, fifo->size - off);
+	memcpy(to, fifo->buffer + off, l);
 
 	/* then get the rest (if any) from the beginning of the buffer */
-	memcpy(buffer + l, fifo->buffer, len - l);
-
-	/*
-	 * Ensure that we remove the bytes from the kfifo -before-
-	 * we update the fifo->out index.
-	 */
-
-	smp_mb();
+	memcpy(to + l, fifo->buffer, n - l);
+}
 
-	fifo->out += len;
+unsigned int __kfifo_out_n(struct kfifo *fifo,
+	unsigned char *to, unsigned int n, unsigned int reclen,
+	unsigned int recsize)
+{
+	if (kfifo_len(fifo) < reclen + recsize)
+		return 0;
 
-	return len;
+	__kfifo_out_data(fifo, to, n, recsize);
+	__kfifo_add_out(fifo, reclen + recsize);
+	return 0;
 }
-EXPORT_SYMBOL(kfifo_out);
+EXPORT_SYMBOL(__kfifo_out_n);
 
 /**
- * kfifo_from_user - puts some data from user space into the FIFO
+ * kfifo_out - gets some data from the FIFO
  * @fifo: the fifo to be used.
- * @from: pointer to the data to be added.
- * @n: the length of the data to be added.
+ * @to: where the data must be copied.
+ * @len: the size of the destination buffer.
  *
- * This function copies at most @n bytes from the @from into the
- * FIFO depending and returns the number of copied bytes.
+ * This function copies at most @n bytes from the FIFO into
+ * @to 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_from_user(struct kfifo *fifo,
-	const void __user *from, unsigned int n)
+unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int n)
+{
+	n = min(kfifo_len(fifo), n);
+
+	__kfifo_out_data(fifo, to, n, 0);
+	__kfifo_add_out(fifo, n);
+
+	return n;
+}
+EXPORT_SYMBOL(kfifo_out);
+
+unsigned int __kfifo_out_generic(struct kfifo *fifo,
+	unsigned char *to, unsigned int n, unsigned int recsize,
+	unsigned int *total)
+{
+	return __kfifo_out_rec(fifo, to, n, recsize, total);
+}
+EXPORT_SYMBOL(__kfifo_out_generic);
+
+static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
+	 const void __user *from, unsigned int n, unsigned int off)
 {
 	unsigned int l;
-	unsigned int off;
 	int ret;
 
-	n = min(n, fifo->size - fifo->in + fifo->out);
-
 	/*
 	 * Ensure that we sample the fifo->out index -before- we
 	 * start putting bytes into the kfifo.
@@ -220,56 +242,69 @@
 
 	smp_mb();
 
-	off = fifo->in & (fifo->size - 1);
+	off = __kfifo_off(fifo, fifo->in+off);
 
 	/* first put the data starting from fifo->in to buffer end */
 	l = min(n, fifo->size - off);
-
 	ret = copy_from_user(fifo->buffer + off, from, l);
 
 	if (unlikely(ret))
-		return l - ret;
+		return ret + n - l;
 
 	/* then put the rest (if any) at the beginning of the buffer */
 	ret = copy_from_user(fifo->buffer, from + l, n - l);
 
 	if (unlikely(ret))
-		return n - ret;
+		return ret;
 
-	/*
-	 * Ensure that we add the bytes to the kfifo -before-
-	 * we update the fifo->in index.
-	 */
-
-	smp_wmb();
+	return 0;
+}
 
-	fifo->in += n;
+unsigned int __kfifo_from_user_n(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize)
+{
+	if (kfifo_avail(fifo) < n + recsize)
+		return n + 1;
 
-	return n;
+	return __kfifo_from_user_data(fifo, from, n, recsize);
 }
-EXPORT_SYMBOL(kfifo_from_user);
+EXPORT_SYMBOL(__kfifo_from_user_n);
 
 /**
- * kfifo_to_user - gets data from the FIFO and write it to user space
+ * kfifo_from_user - puts some data from user space into the FIFO
  * @fifo: the fifo to be used.
- * @to: where the data must be copied.
- * @n: the size of the destination buffer.
+ * @from: pointer to the data to be added.
+ * @n: the length of the data to be added.
  *
- * This function copies at most @n bytes from the FIFO into the
- * @to and returns the number of copied bytes.
+ * This function copies at most @n bytes from the @from into the
+ * FIFO 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_to_user(struct kfifo *fifo,
-	void __user *to, unsigned int n)
+unsigned int kfifo_from_user(struct kfifo *fifo,
+	const void __user *from, unsigned int n)
+{
+	n = min(kfifo_avail(fifo), n);
+	n -= __kfifo_from_user_data(fifo, from, n, 0);
+	__kfifo_add_in(fifo, n);
+	return n;
+}
+EXPORT_SYMBOL(kfifo_from_user);
+
+unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
+	const void __user *from, unsigned int n, unsigned int recsize)
+{
+	return __kfifo_from_user_rec(fifo, from, n, recsize);
+}
+EXPORT_SYMBOL(__kfifo_from_user_generic);
+
+static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
+		void __user *to, unsigned int n, unsigned int off)
 {
 	unsigned int l;
-	unsigned int off;
 	int ret;
 
-	n = min(n, fifo->in - fifo->out);
-
 	/*
 	 * Ensure that we sample the fifo->in index -before- we
 	 * start removing bytes from the kfifo.
@@ -277,27 +312,85 @@
 
 	smp_rmb();
 
-	off = fifo->out & (fifo->size - 1);
+	off = __kfifo_off(fifo, fifo->out+off);
 
 	/* first get the data from fifo->out until the end of the buffer */
 	l = min(n, fifo->size - off);
-
 	ret = copy_to_user(to, fifo->buffer + off, l);
 
 	if (unlikely(ret))
-		return l - ret;
+		return ret + n - l;
 
 	/* then get the rest (if any) from the beginning of the buffer */
 	ret = copy_to_user(to + l, fifo->buffer, n - l);
 
 	if (unlikely(ret))
-		return n - ret;
+		return ret;
 
-	smp_mb();
+	return 0;
+}
 
-	fifo->out += n;
+unsigned int __kfifo_to_user_n(struct kfifo *fifo,
+	void __user *to, unsigned int n, unsigned int reclen,
+	unsigned int recsize)
+{
+	unsigned int ret;
+
+	if (kfifo_len(fifo) < reclen + recsize)
+		return 0;
+
+	ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
+
+	if (likely(ret == 0))
+		__kfifo_add_out(fifo, reclen + recsize);
 
+	return ret;
+}
+EXPORT_SYMBOL(__kfifo_to_user_n);
+
+/**
+ * kfifo_to_user - gets data from the FIFO and write it to user space
+ * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ *
+ * This function copies at most @n bytes from the FIFO into the
+ * @to 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_to_user(struct kfifo *fifo,
+	void __user *to, unsigned int n)
+{
+	n = min(kfifo_len(fifo), n);
+	n -= __kfifo_to_user_data(fifo, to, n, 0);
+	__kfifo_add_out(fifo, n);
 	return n;
 }
 EXPORT_SYMBOL(kfifo_to_user);
 
+unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
+	void __user *to, unsigned int n, unsigned int recsize,
+	unsigned int *total)
+{
+	return __kfifo_to_user_rec(fifo, to, n, recsize, total);
+}
+EXPORT_SYMBOL(__kfifo_to_user_generic);
+
+unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize)
+{
+	if (recsize == 0)
+		return kfifo_avail(fifo);
+
+	return __kfifo_peek_n(fifo, recsize);
+}
+EXPORT_SYMBOL(__kfifo_peek_generic);
+
+void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize)
+{
+	__kfifo_skip_rec(fifo, recsize);
+}
+EXPORT_SYMBOL(__kfifo_skip_generic);
+
+



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-08-11 22:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-11 22:32 [PATCH 7/7] new kfifo API Stefani Seibold

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.