aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kfifo.c
diff options
context:
space:
mode:
authorStefani Seibold <stefani@seibold.net>2009-12-21 17:37:26 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-22 17:17:55 -0500
commit45465487897a1c6d508b14b904dc5777f7ec7e04 (patch)
tree935c8dae68dc793ff2f795d57cf027531475cd53 /kernel/kfifo.c
parent2ec91eec47f713e3d158ba5b28a24a85a2cf3650 (diff)
kfifo: move struct kfifo in place
This is a new generic kernel FIFO implementation. The current kernel fifo API is not very widely used, because it has to many constrains. Only 17 files in the current 2.6.31-rc5 used it. FIFO's are like list's a very basic thing and a kfifo API which handles the most use case would save a lot of development time and memory resources. I think this are the reasons why kfifo is not in use: - The API is to simple, important functions are missing - A fifo can be only allocated dynamically - There is a requirement of a spinlock whether you need it or not - There is no support for data records inside a fifo So I decided to extend the kfifo in a more generic way without blowing up the API to much. The new API has the following benefits: - Generic usage: For kernel internal use and/or device driver. - Provide an API for the most use case. - Slim API: The whole API provides 25 functions. - Linux style habit. - DECLARE_KFIFO, DEFINE_KFIFO and INIT_KFIFO Macros - Direct copy_to_user from the fifo and copy_from_user into the fifo. - The kfifo itself is an in place member of the using data structure, this save an indirection access and does not waste the kernel allocator. - Lockless access: if only one reader and one writer is active on the fifo, which is the common use case, no additional locking is necessary. - Remove spinlock - give the user the freedom of choice what kind of locking to use if one is required. - Ability to handle records. Three type of records are supported: - Variable length records between 0-255 bytes, with a record size field of 1 bytes. - Variable length records between 0-65535 bytes, with a record size field of 2 bytes. - Fixed size records, which no record size field. - Preserve memory resource. - Performance! - Easy to use! This patch: Since most users want to have the kfifo as part of another object, reorganize the code to allow including struct kfifo in another data structure. This requires changing the kfifo_alloc and kfifo_init prototypes so that we pass an existing kfifo pointer into them. This patch changes the implementation and all existing users. [akpm@linux-foundation.org: fix warning] Signed-off-by: Stefani Seibold <stefani@seibold.net> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com> Acked-by: Andi Kleen <ak@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/kfifo.c')
-rw-r--r--kernel/kfifo.c65
1 files changed, 33 insertions, 32 deletions
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 3765ff3c1bbe..8da6bb9782bb 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * A simple kernel FIFO implementation. 2 * A generic kernel FIFO implementation.
3 * 3 *
4 * Copyright (C) 2009 Stefani Seibold <stefani@seibold.net>
4 * Copyright (C) 2004 Stelian Pop <stelian@popies.net> 5 * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -26,49 +27,51 @@
26#include <linux/kfifo.h> 27#include <linux/kfifo.h>
27#include <linux/log2.h> 28#include <linux/log2.h>
28 29
30static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer,
31 unsigned int size, spinlock_t *lock)
32{
33 fifo->buffer = buffer;
34 fifo->size = size;
35 fifo->lock = lock;
36
37 kfifo_reset(fifo);
38}
39
29/** 40/**
30 * kfifo_init - allocates a new FIFO using a preallocated buffer 41 * kfifo_init - initialize a FIFO using a preallocated buffer
42 * @fifo: the fifo to assign the buffer
31 * @buffer: the preallocated buffer to be used. 43 * @buffer: the preallocated buffer to be used.
32 * @size: the size of the internal buffer, this have to be a power of 2. 44 * @size: the size of the internal buffer, this have to be a power of 2.
33 * @gfp_mask: get_free_pages mask, passed to kmalloc()
34 * @lock: the lock to be used to protect the fifo buffer 45 * @lock: the lock to be used to protect the fifo buffer
35 * 46 *
36 * Do NOT pass the kfifo to kfifo_free() after use! Simply free the
37 * &struct kfifo with kfree().
38 */ 47 */
39struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size, 48void kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size,
40 gfp_t gfp_mask, spinlock_t *lock) 49 spinlock_t *lock)
41{ 50{
42 struct kfifo *fifo;
43
44 /* size must be a power of 2 */ 51 /* size must be a power of 2 */
45 BUG_ON(!is_power_of_2(size)); 52 BUG_ON(!is_power_of_2(size));
46 53
47 fifo = kmalloc(sizeof(struct kfifo), gfp_mask); 54 _kfifo_init(fifo, buffer, size, lock);
48 if (!fifo)
49 return ERR_PTR(-ENOMEM);
50
51 fifo->buffer = buffer;
52 fifo->size = size;
53 fifo->in = fifo->out = 0;
54 fifo->lock = lock;
55
56 return fifo;
57} 55}
58EXPORT_SYMBOL(kfifo_init); 56EXPORT_SYMBOL(kfifo_init);
59 57
60/** 58/**
61 * kfifo_alloc - allocates a new FIFO and its internal buffer 59 * kfifo_alloc - allocates a new FIFO internal buffer
62 * @size: the size of the internal buffer to be allocated. 60 * @fifo: the fifo to assign then new buffer
61 * @size: the size of the buffer to be allocated, this have to be a power of 2.
63 * @gfp_mask: get_free_pages mask, passed to kmalloc() 62 * @gfp_mask: get_free_pages mask, passed to kmalloc()
64 * @lock: the lock to be used to protect the fifo buffer 63 * @lock: the lock to be used to protect the fifo buffer
65 * 64 *
65 * This function dynamically allocates a new fifo internal buffer
66 *
66 * The size will be rounded-up to a power of 2. 67 * The size will be rounded-up to a power of 2.
68 * The buffer will be release with kfifo_free().
69 * Return 0 if no error, otherwise the an error code
67 */ 70 */
68struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) 71int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask,
72 spinlock_t *lock)
69{ 73{
70 unsigned char *buffer; 74 unsigned char *buffer;
71 struct kfifo *ret;
72 75
73 /* 76 /*
74 * round up to the next power of 2, since our 'let the indices 77 * round up to the next power of 2, since our 'let the indices
@@ -80,26 +83,24 @@ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
80 } 83 }
81 84
82 buffer = kmalloc(size, gfp_mask); 85 buffer = kmalloc(size, gfp_mask);
83 if (!buffer) 86 if (!buffer) {
84 return ERR_PTR(-ENOMEM); 87 _kfifo_init(fifo, 0, 0, NULL);
85 88 return -ENOMEM;
86 ret = kfifo_init(buffer, size, gfp_mask, lock); 89 }
87 90
88 if (IS_ERR(ret)) 91 _kfifo_init(fifo, buffer, size, lock);
89 kfree(buffer);
90 92
91 return ret; 93 return 0;
92} 94}
93EXPORT_SYMBOL(kfifo_alloc); 95EXPORT_SYMBOL(kfifo_alloc);
94 96
95/** 97/**
96 * kfifo_free - frees the FIFO 98 * kfifo_free - frees the FIFO internal buffer
97 * @fifo: the fifo to be freed. 99 * @fifo: the fifo to be freed.
98 */ 100 */
99void kfifo_free(struct kfifo *fifo) 101void kfifo_free(struct kfifo *fifo)
100{ 102{
101 kfree(fifo->buffer); 103 kfree(fifo->buffer);
102 kfree(fifo);
103} 104}
104EXPORT_SYMBOL(kfifo_free); 105EXPORT_SYMBOL(kfifo_free);
105 106