From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755627AbZHKWca (ORCPT ); Tue, 11 Aug 2009 18:32:30 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754327AbZHKWc0 (ORCPT ); Tue, 11 Aug 2009 18:32:26 -0400 Received: from www84.your-server.de ([213.133.104.84]:36418 "EHLO www84.your-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755613AbZHKWcV (ORCPT ); Tue, 11 Aug 2009 18:32:21 -0400 Subject: [PATCH 7/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:12 +0200 Message-Id: <1250029932.17599.105.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 | 381 ++++++++++++++++++++++++++++++++++++++++++++++++-- kernel/kfifo.c | 275 ++++++++++++++++++++++++------------ 2 files changed, 551 insertions(+), 105 deletions(-) Signed-off-by: Stefani Seibold 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); + +