From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755611AbZHKWcM (ORCPT ); Tue, 11 Aug 2009 18:32:12 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755591AbZHKWcJ (ORCPT ); Tue, 11 Aug 2009 18:32:09 -0400 Received: from www84.your-server.de ([213.133.104.84]:36412 "EHLO www84.your-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755580AbZHKWcG (ORCPT ); Tue, 11 Aug 2009 18:32:06 -0400 Subject: [PATCH 6/7] new kfifo API From: Stefani Seibold To: linux-kernel Cc: Andrew Morton , Arnd Bergmann , Andi Kleen Content-Type: text/plain Date: Wed, 12 Aug 2009 00:32:06 +0200 Message-Id: <1250029926.17599.104.camel@wall-e> Mime-Version: 1.0 X-Mailer: Evolution 2.26.3 Content-Transfer-Encoding: 7bit X-Authenticated-Sender: stefani@seibold.net Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org include/linux/kfifo.h | 6 ++ kernel/kfifo.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) Signed-off-by: Stefani Seibold diff -u -N -r linux-2.6.31-rc4-kfifo5/include/linux/kfifo.h linux-2.6.31-rc4-kfifo6/include/linux/kfifo.h --- linux-2.6.31-rc4-kfifo5/include/linux/kfifo.h 2009-08-11 22:53:29.000000000 +0200 +++ linux-2.6.31-rc4-kfifo6/include/linux/kfifo.h 2009-08-11 22:53:41.000000000 +0200 @@ -198,4 +198,10 @@ return kfifo_size(fifo) - kfifo_len(fifo); } +extern __must_check unsigned int kfifo_from_user(struct kfifo *fifo, + const void __user *from, unsigned int n); + +extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo, + void __user *to, unsigned int n); + #endif diff -u -N -r linux-2.6.31-rc4-kfifo5/kernel/kfifo.c linux-2.6.31-rc4-kfifo6/kernel/kfifo.c --- linux-2.6.31-rc4-kfifo5/kernel/kfifo.c 2009-08-11 22:33:06.000000000 +0200 +++ linux-2.6.31-rc4-kfifo6/kernel/kfifo.c 2009-08-11 22:33:15.000000000 +0200 @@ -26,6 +26,7 @@ #include #include #include +#include static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size) @@ -190,3 +191,113 @@ return len; } EXPORT_SYMBOL(kfifo_out); + +/** + * kfifo_from_user - 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. + * + * This function copies at most @n bytes from the @from into the + * FIFO depending 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 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. + */ + + smp_mb(); + + off = fifo->in & (fifo->size - 1); + + /* 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; + + /* 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; + + /* + * Ensure that we add the bytes to the kfifo -before- + * we update the fifo->in index. + */ + + smp_wmb(); + + fifo->in += n; + + return n; +} +EXPORT_SYMBOL(kfifo_from_user); + +/** + * 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) +{ + 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. + */ + + smp_rmb(); + + off = fifo->out & (fifo->size - 1); + + /* 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; + + /* 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; + + smp_mb(); + + fifo->out += n; + + return n; +} +EXPORT_SYMBOL(kfifo_to_user); +