xref: /linux/samples/kfifo/record-example.c (revision 9059044b)
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 */
25880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(read_access);
265bf2b193SStefani Seibold 
275bf2b193SStefani Seibold /* lock for procfs write access */
28880732aeSSebastian 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 
126880732aeSSebastian 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 
131880732aeSSebastian 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 
144880732aeSSebastian 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 
149880732aeSSebastian 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);
201*9059044bSJeff Johnson MODULE_DESCRIPTION("Sample dynamic sized record fifo implementation");
2025bf2b193SStefani Seibold MODULE_LICENSE("GPL");
2035bf2b193SStefani Seibold MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");
204