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>
This commit is contained in:
Stefani Seibold
2009-12-21 14:37:26 -08:00
committed by Linus Torvalds
parent 2ec91eec47
commit 4546548789
24 changed files with 238 additions and 259 deletions

View File

@@ -164,7 +164,7 @@ struct fujitsu_hotkey_t {
struct input_dev *input;
char phys[32];
struct platform_device *pf_device;
struct kfifo *fifo;
struct kfifo fifo;
spinlock_t fifo_lock;
int rfkill_supported;
int rfkill_state;
@@ -824,12 +824,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
/* kfifo */
spin_lock_init(&fujitsu_hotkey->fifo_lock);
fujitsu_hotkey->fifo =
kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL,
&fujitsu_hotkey->fifo_lock);
if (IS_ERR(fujitsu_hotkey->fifo)) {
error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
GFP_KERNEL, &fujitsu_hotkey->fifo_lock);
if (error) {
printk(KERN_ERR "kfifo_alloc failed\n");
error = PTR_ERR(fujitsu_hotkey->fifo);
goto err_stop;
}
@@ -934,7 +932,7 @@ err_unregister_input_dev:
err_free_input_dev:
input_free_device(input);
err_free_fifo:
kfifo_free(fujitsu_hotkey->fifo);
kfifo_free(&fujitsu_hotkey->fifo);
err_stop:
return result;
}
@@ -956,7 +954,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
input_free_device(input);
kfifo_free(fujitsu_hotkey->fifo);
kfifo_free(&fujitsu_hotkey->fifo);
fujitsu_hotkey->acpi_handle = NULL;
@@ -1008,7 +1006,7 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
vdbg_printk(FUJLAPTOP_DBG_TRACE,
"Push keycode into ringbuffer [%d]\n",
keycode);
status = kfifo_put(fujitsu_hotkey->fifo,
status = kfifo_put(&fujitsu_hotkey->fifo,
(unsigned char *)&keycode,
sizeof(keycode));
if (status != sizeof(keycode)) {
@@ -1022,7 +1020,7 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
} else if (keycode == 0) {
while ((status =
kfifo_get
(fujitsu_hotkey->fifo, (unsigned char *)
(&fujitsu_hotkey->fifo, (unsigned char *)
&keycode_r,
sizeof
(keycode_r))) == sizeof(keycode_r)) {

View File

@@ -142,7 +142,7 @@ struct sony_laptop_input_s {
atomic_t users;
struct input_dev *jog_dev;
struct input_dev *key_dev;
struct kfifo *fifo;
struct kfifo fifo;
spinlock_t fifo_lock;
struct workqueue_struct *wq;
};
@@ -300,7 +300,7 @@ static void do_sony_laptop_release_key(struct work_struct *work)
{
struct sony_laptop_keypress kp;
while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
while (kfifo_get(&sony_laptop_input.fifo, (unsigned char *)&kp,
sizeof(kp)) == sizeof(kp)) {
msleep(10);
input_report_key(kp.dev, kp.key, 0);
@@ -362,7 +362,7 @@ static void sony_laptop_report_input_event(u8 event)
/* we emit the scancode so we can always remap the key */
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
kfifo_put(sony_laptop_input.fifo,
kfifo_put(&sony_laptop_input.fifo,
(unsigned char *)&kp, sizeof(kp));
if (!work_pending(&sony_laptop_release_key_work))
@@ -385,12 +385,11 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
/* kfifo */
spin_lock_init(&sony_laptop_input.fifo_lock);
sony_laptop_input.fifo =
kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
error =
kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
&sony_laptop_input.fifo_lock);
if (IS_ERR(sony_laptop_input.fifo)) {
if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
error = PTR_ERR(sony_laptop_input.fifo);
goto err_dec_users;
}
@@ -474,7 +473,7 @@ err_destroy_wq:
destroy_workqueue(sony_laptop_input.wq);
err_free_kfifo:
kfifo_free(sony_laptop_input.fifo);
kfifo_free(&sony_laptop_input.fifo);
err_dec_users:
atomic_dec(&sony_laptop_input.users);
@@ -500,7 +499,7 @@ static void sony_laptop_remove_input(void)
}
destroy_workqueue(sony_laptop_input.wq);
kfifo_free(sony_laptop_input.fifo);
kfifo_free(&sony_laptop_input.fifo);
}
/*********** Platform Device ***********/
@@ -2079,7 +2078,7 @@ static struct attribute_group spic_attribute_group = {
struct sonypi_compat_s {
struct fasync_struct *fifo_async;
struct kfifo *fifo;
struct kfifo fifo;
spinlock_t fifo_lock;
wait_queue_head_t fifo_proc_list;
atomic_t open_count;
@@ -2104,12 +2103,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
/* Flush input queue on first open */
unsigned long flags;
spin_lock_irqsave(sonypi_compat.fifo->lock, flags);
spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
if (atomic_inc_return(&sonypi_compat.open_count) == 1)
__kfifo_reset(sonypi_compat.fifo);
__kfifo_reset(&sonypi_compat.fifo);
spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags);
spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
return 0;
}
@@ -2120,17 +2119,17 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
ssize_t ret;
unsigned char c;
if ((kfifo_len(sonypi_compat.fifo) == 0) &&
if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
kfifo_len(sonypi_compat.fifo) != 0);
kfifo_len(&sonypi_compat.fifo) != 0);
if (ret)
return ret;
while (ret < count &&
(kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
(kfifo_get(&sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
if (put_user(c, buf++))
return -EFAULT;
ret++;
@@ -2147,7 +2146,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
if (kfifo_len(sonypi_compat.fifo))
if (kfifo_len(&sonypi_compat.fifo))
return POLLIN | POLLRDNORM;
return 0;
}
@@ -2309,7 +2308,7 @@ static struct miscdevice sonypi_misc_device = {
static void sonypi_compat_report_event(u8 event)
{
kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
kfifo_put(&sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
wake_up_interruptible(&sonypi_compat.fifo_proc_list);
}
@@ -2319,11 +2318,12 @@ static int sonypi_compat_init(void)
int error;
spin_lock_init(&sonypi_compat.fifo_lock);
sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
error =
kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
&sonypi_compat.fifo_lock);
if (IS_ERR(sonypi_compat.fifo)) {
if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
return PTR_ERR(sonypi_compat.fifo);
return error;
}
init_waitqueue_head(&sonypi_compat.fifo_proc_list);
@@ -2342,14 +2342,14 @@ static int sonypi_compat_init(void)
return 0;
err_free_kfifo:
kfifo_free(sonypi_compat.fifo);
kfifo_free(&sonypi_compat.fifo);
return error;
}
static void sonypi_compat_exit(void)
{
misc_deregister(&sonypi_misc_device);
kfifo_free(sonypi_compat.fifo);
kfifo_free(&sonypi_compat.fifo);
}
#else
static int sonypi_compat_init(void) { return 0; }