lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1250029932.17599.105.camel@wall-e>
Date:	Wed, 12 Aug 2009 00:32:12 +0200
From:	Stefani Seibold <stefani@...bold.net>
To:	linux-kernel <linux-kernel@...r.kernel.org>
Cc:	Andrew Morton <akpm@...ux-foundation.org>,
	Arnd Bergmann <arnd@...db.de>, Andi Kleen <andi@...stfloor.org>
Subject: [PATCH 7/7] new kfifo API

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

Signed-off-by: Stefani Seibold <stefani@...bold.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);
+
+


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ