1912d0f0bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25bf2b193SStefani Seibold /*
35bf2b193SStefani Seibold * Sample dynamic sized record fifo implementation
45bf2b193SStefani Seibold *
55bf2b193SStefani Seibold * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
65bf2b193SStefani Seibold */
75bf2b193SStefani Seibold
85bf2b193SStefani Seibold #include <linux/init.h>
95bf2b193SStefani Seibold #include <linux/module.h>
105bf2b193SStefani Seibold #include <linux/proc_fs.h>
115bf2b193SStefani Seibold #include <linux/mutex.h>
125bf2b193SStefani Seibold #include <linux/kfifo.h>
135bf2b193SStefani Seibold
145bf2b193SStefani Seibold /*
155bf2b193SStefani Seibold * This module shows how to create a variable sized record fifo.
165bf2b193SStefani Seibold */
175bf2b193SStefani Seibold
185bf2b193SStefani Seibold /* fifo size in elements (bytes) */
195bf2b193SStefani Seibold #define FIFO_SIZE 128
205bf2b193SStefani Seibold
215bf2b193SStefani Seibold /* name of the proc entry */
225bf2b193SStefani Seibold #define PROC_FIFO "record-fifo"
235bf2b193SStefani Seibold
245bf2b193SStefani Seibold /* lock for procfs read access */
25*880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(read_access);
265bf2b193SStefani Seibold
275bf2b193SStefani Seibold /* lock for procfs write access */
28*880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(write_access);
295bf2b193SStefani Seibold
305bf2b193SStefani Seibold /*
315bf2b193SStefani Seibold * define DYNAMIC in this example for a dynamically allocated fifo.
325bf2b193SStefani Seibold *
335bf2b193SStefani Seibold * Otherwise the fifo storage will be a part of the fifo structure.
345bf2b193SStefani Seibold */
355bf2b193SStefani Seibold #if 0
365bf2b193SStefani Seibold #define DYNAMIC
375bf2b193SStefani Seibold #endif
385bf2b193SStefani Seibold
395bf2b193SStefani Seibold /*
405bf2b193SStefani Seibold * struct kfifo_rec_ptr_1 and STRUCT_KFIFO_REC_1 can handle records of a
415bf2b193SStefani Seibold * length between 0 and 255 bytes.
425bf2b193SStefani Seibold *
435bf2b193SStefani Seibold * struct kfifo_rec_ptr_2 and STRUCT_KFIFO_REC_2 can handle records of a
445bf2b193SStefani Seibold * length between 0 and 65535 bytes.
455bf2b193SStefani Seibold */
465bf2b193SStefani Seibold
475bf2b193SStefani Seibold #ifdef DYNAMIC
485bf2b193SStefani Seibold struct kfifo_rec_ptr_1 test;
495bf2b193SStefani Seibold
505bf2b193SStefani Seibold #else
515bf2b193SStefani Seibold typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest;
525bf2b193SStefani Seibold
535bf2b193SStefani Seibold static mytest test;
545bf2b193SStefani Seibold #endif
555bf2b193SStefani Seibold
56a25effa4SAndrea Righi static const char *expected_result[] = {
57a25effa4SAndrea Righi "a",
58a25effa4SAndrea Righi "bb",
59a25effa4SAndrea Righi "ccc",
60a25effa4SAndrea Righi "dddd",
61a25effa4SAndrea Righi "eeeee",
62a25effa4SAndrea Righi "ffffff",
63a25effa4SAndrea Righi "ggggggg",
64a25effa4SAndrea Righi "hhhhhhhh",
65a25effa4SAndrea Righi "iiiiiiiii",
66a25effa4SAndrea Righi "jjjjjjjjjj",
67a25effa4SAndrea Righi };
68a25effa4SAndrea Righi
testfunc(void)695bf2b193SStefani Seibold static int __init testfunc(void)
705bf2b193SStefani Seibold {
715bf2b193SStefani Seibold char buf[100];
725bf2b193SStefani Seibold unsigned int i;
735bf2b193SStefani Seibold unsigned int ret;
745bf2b193SStefani Seibold struct { unsigned char buf[6]; } hello = { "hello" };
755bf2b193SStefani Seibold
765bf2b193SStefani Seibold printk(KERN_INFO "record fifo test start\n");
775bf2b193SStefani Seibold
785bf2b193SStefani Seibold kfifo_in(&test, &hello, sizeof(hello));
795bf2b193SStefani Seibold
805bf2b193SStefani Seibold /* show the size of the next record in the fifo */
815bf2b193SStefani Seibold printk(KERN_INFO "fifo peek len: %u\n", kfifo_peek_len(&test));
825bf2b193SStefani Seibold
835bf2b193SStefani Seibold /* put in variable length data */
845bf2b193SStefani Seibold for (i = 0; i < 10; i++) {
855bf2b193SStefani Seibold memset(buf, 'a' + i, i + 1);
865bf2b193SStefani Seibold kfifo_in(&test, buf, i + 1);
875bf2b193SStefani Seibold }
885bf2b193SStefani Seibold
89a25effa4SAndrea Righi /* skip first element of the fifo */
90a25effa4SAndrea Righi printk(KERN_INFO "skip 1st element\n");
91a25effa4SAndrea Righi kfifo_skip(&test);
92a25effa4SAndrea Righi
935bf2b193SStefani Seibold printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
945bf2b193SStefani Seibold
955bf2b193SStefani Seibold /* show the first record without removing from the fifo */
965bf2b193SStefani Seibold ret = kfifo_out_peek(&test, buf, sizeof(buf));
975bf2b193SStefani Seibold if (ret)
985bf2b193SStefani Seibold printk(KERN_INFO "%.*s\n", ret, buf);
995bf2b193SStefani Seibold
100a25effa4SAndrea Righi /* check the correctness of all values in the fifo */
101a25effa4SAndrea Righi i = 0;
1025bf2b193SStefani Seibold while (!kfifo_is_empty(&test)) {
1035bf2b193SStefani Seibold ret = kfifo_out(&test, buf, sizeof(buf));
104a25effa4SAndrea Righi buf[ret] = '\0';
105a25effa4SAndrea Righi printk(KERN_INFO "item = %.*s\n", ret, buf);
106a25effa4SAndrea Righi if (strcmp(buf, expected_result[i++])) {
107a25effa4SAndrea Righi printk(KERN_WARNING "value mismatch: test failed\n");
108a25effa4SAndrea Righi return -EIO;
1095bf2b193SStefani Seibold }
110a25effa4SAndrea Righi }
111a25effa4SAndrea Righi if (i != ARRAY_SIZE(expected_result)) {
112a25effa4SAndrea Righi printk(KERN_WARNING "size mismatch: test failed\n");
113a25effa4SAndrea Righi return -EIO;
114a25effa4SAndrea Righi }
115a25effa4SAndrea Righi printk(KERN_INFO "test passed\n");
1165bf2b193SStefani Seibold
1175bf2b193SStefani Seibold return 0;
1185bf2b193SStefani Seibold }
1195bf2b193SStefani Seibold
fifo_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1205bf2b193SStefani Seibold static ssize_t fifo_write(struct file *file, const char __user *buf,
1215bf2b193SStefani Seibold size_t count, loff_t *ppos)
1225bf2b193SStefani Seibold {
1235bf2b193SStefani Seibold int ret;
1245bf2b193SStefani Seibold unsigned int copied;
1255bf2b193SStefani Seibold
126*880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&write_access))
1275bf2b193SStefani Seibold return -ERESTARTSYS;
1285bf2b193SStefani Seibold
1295bf2b193SStefani Seibold ret = kfifo_from_user(&test, buf, count, &copied);
1305bf2b193SStefani Seibold
131*880732aeSSebastian Andrzej Siewior mutex_unlock(&write_access);
132926ee00eSDan Carpenter if (ret)
133926ee00eSDan Carpenter return ret;
1345bf2b193SStefani Seibold
135926ee00eSDan Carpenter return copied;
1365bf2b193SStefani Seibold }
1375bf2b193SStefani Seibold
fifo_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)1385bf2b193SStefani Seibold static ssize_t fifo_read(struct file *file, char __user *buf,
1395bf2b193SStefani Seibold size_t count, loff_t *ppos)
1405bf2b193SStefani Seibold {
1415bf2b193SStefani Seibold int ret;
1425bf2b193SStefani Seibold unsigned int copied;
1435bf2b193SStefani Seibold
144*880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&read_access))
1455bf2b193SStefani Seibold return -ERESTARTSYS;
1465bf2b193SStefani Seibold
1475bf2b193SStefani Seibold ret = kfifo_to_user(&test, buf, count, &copied);
1485bf2b193SStefani Seibold
149*880732aeSSebastian Andrzej Siewior mutex_unlock(&read_access);
150926ee00eSDan Carpenter if (ret)
151926ee00eSDan Carpenter return ret;
1525bf2b193SStefani Seibold
153926ee00eSDan Carpenter return copied;
1545bf2b193SStefani Seibold }
1555bf2b193SStefani Seibold
15697a32539SAlexey Dobriyan static const struct proc_ops fifo_proc_ops = {
15797a32539SAlexey Dobriyan .proc_read = fifo_read,
15897a32539SAlexey Dobriyan .proc_write = fifo_write,
15997a32539SAlexey Dobriyan .proc_lseek = noop_llseek,
1605bf2b193SStefani Seibold };
1615bf2b193SStefani Seibold
example_init(void)1625bf2b193SStefani Seibold static int __init example_init(void)
1635bf2b193SStefani Seibold {
1645bf2b193SStefani Seibold #ifdef DYNAMIC
1655bf2b193SStefani Seibold int ret;
1665bf2b193SStefani Seibold
1675bf2b193SStefani Seibold ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
1685bf2b193SStefani Seibold if (ret) {
1695bf2b193SStefani Seibold printk(KERN_ERR "error kfifo_alloc\n");
1705bf2b193SStefani Seibold return ret;
1715bf2b193SStefani Seibold }
1725bf2b193SStefani Seibold #else
1735bf2b193SStefani Seibold INIT_KFIFO(test);
1745bf2b193SStefani Seibold #endif
175a25effa4SAndrea Righi if (testfunc() < 0) {
176a25effa4SAndrea Righi #ifdef DYNAMIC
177a25effa4SAndrea Righi kfifo_free(&test);
178a25effa4SAndrea Righi #endif
179a25effa4SAndrea Righi return -EIO;
180a25effa4SAndrea Righi }
1815bf2b193SStefani Seibold
18297a32539SAlexey Dobriyan if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
1835bf2b193SStefani Seibold #ifdef DYNAMIC
1845bf2b193SStefani Seibold kfifo_free(&test);
1855bf2b193SStefani Seibold #endif
1865bf2b193SStefani Seibold return -ENOMEM;
1875bf2b193SStefani Seibold }
1885bf2b193SStefani Seibold return 0;
1895bf2b193SStefani Seibold }
1905bf2b193SStefani Seibold
example_exit(void)1915bf2b193SStefani Seibold static void __exit example_exit(void)
1925bf2b193SStefani Seibold {
1935bf2b193SStefani Seibold remove_proc_entry(PROC_FIFO, NULL);
1945bf2b193SStefani Seibold #ifdef DYNAMIC
1955bf2b193SStefani Seibold kfifo_free(&test);
1965bf2b193SStefani Seibold #endif
1975bf2b193SStefani Seibold }
1985bf2b193SStefani Seibold
1995bf2b193SStefani Seibold module_init(example_init);
2005bf2b193SStefani Seibold module_exit(example_exit);
2015bf2b193SStefani Seibold MODULE_LICENSE("GPL");
2025bf2b193SStefani Seibold MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");
203