Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Sample dynamic sized record fifo implementation
0004  *
0005  * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
0006  */
0007 
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 #include <linux/proc_fs.h>
0011 #include <linux/mutex.h>
0012 #include <linux/kfifo.h>
0013 
0014 /*
0015  * This module shows how to create a variable sized record fifo.
0016  */
0017 
0018 /* fifo size in elements (bytes) */
0019 #define FIFO_SIZE   128
0020 
0021 /* name of the proc entry */
0022 #define PROC_FIFO   "record-fifo"
0023 
0024 /* lock for procfs read access */
0025 static DEFINE_MUTEX(read_access);
0026 
0027 /* lock for procfs write access */
0028 static DEFINE_MUTEX(write_access);
0029 
0030 /*
0031  * define DYNAMIC in this example for a dynamically allocated fifo.
0032  *
0033  * Otherwise the fifo storage will be a part of the fifo structure.
0034  */
0035 #if 0
0036 #define DYNAMIC
0037 #endif
0038 
0039 /*
0040  * struct kfifo_rec_ptr_1 and  STRUCT_KFIFO_REC_1 can handle records of a
0041  * length between 0 and 255 bytes.
0042  *
0043  * struct kfifo_rec_ptr_2 and  STRUCT_KFIFO_REC_2 can handle records of a
0044  * length between 0 and 65535 bytes.
0045  */
0046 
0047 #ifdef DYNAMIC
0048 struct kfifo_rec_ptr_1 test;
0049 
0050 #else
0051 typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest;
0052 
0053 static mytest test;
0054 #endif
0055 
0056 static const char *expected_result[] = {
0057     "a",
0058     "bb",
0059     "ccc",
0060     "dddd",
0061     "eeeee",
0062     "ffffff",
0063     "ggggggg",
0064     "hhhhhhhh",
0065     "iiiiiiiii",
0066     "jjjjjjjjjj",
0067 };
0068 
0069 static int __init testfunc(void)
0070 {
0071     char        buf[100];
0072     unsigned int    i;
0073     unsigned int    ret;
0074     struct { unsigned char buf[6]; } hello = { "hello" };
0075 
0076     printk(KERN_INFO "record fifo test start\n");
0077 
0078     kfifo_in(&test, &hello, sizeof(hello));
0079 
0080     /* show the size of the next record in the fifo */
0081     printk(KERN_INFO "fifo peek len: %u\n", kfifo_peek_len(&test));
0082 
0083     /* put in variable length data */
0084     for (i = 0; i < 10; i++) {
0085         memset(buf, 'a' + i, i + 1);
0086         kfifo_in(&test, buf, i + 1);
0087     }
0088 
0089     /* skip first element of the fifo */
0090     printk(KERN_INFO "skip 1st element\n");
0091     kfifo_skip(&test);
0092 
0093     printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
0094 
0095     /* show the first record without removing from the fifo */
0096     ret = kfifo_out_peek(&test, buf, sizeof(buf));
0097     if (ret)
0098         printk(KERN_INFO "%.*s\n", ret, buf);
0099 
0100     /* check the correctness of all values in the fifo */
0101     i = 0;
0102     while (!kfifo_is_empty(&test)) {
0103         ret = kfifo_out(&test, buf, sizeof(buf));
0104         buf[ret] = '\0';
0105         printk(KERN_INFO "item = %.*s\n", ret, buf);
0106         if (strcmp(buf, expected_result[i++])) {
0107             printk(KERN_WARNING "value mismatch: test failed\n");
0108             return -EIO;
0109         }
0110     }
0111     if (i != ARRAY_SIZE(expected_result)) {
0112         printk(KERN_WARNING "size mismatch: test failed\n");
0113         return -EIO;
0114     }
0115     printk(KERN_INFO "test passed\n");
0116 
0117     return 0;
0118 }
0119 
0120 static ssize_t fifo_write(struct file *file, const char __user *buf,
0121                         size_t count, loff_t *ppos)
0122 {
0123     int ret;
0124     unsigned int copied;
0125 
0126     if (mutex_lock_interruptible(&write_access))
0127         return -ERESTARTSYS;
0128 
0129     ret = kfifo_from_user(&test, buf, count, &copied);
0130 
0131     mutex_unlock(&write_access);
0132     if (ret)
0133         return ret;
0134 
0135     return copied;
0136 }
0137 
0138 static ssize_t fifo_read(struct file *file, char __user *buf,
0139                         size_t count, loff_t *ppos)
0140 {
0141     int ret;
0142     unsigned int copied;
0143 
0144     if (mutex_lock_interruptible(&read_access))
0145         return -ERESTARTSYS;
0146 
0147     ret = kfifo_to_user(&test, buf, count, &copied);
0148 
0149     mutex_unlock(&read_access);
0150     if (ret)
0151         return ret;
0152 
0153     return copied;
0154 }
0155 
0156 static const struct proc_ops fifo_proc_ops = {
0157     .proc_read  = fifo_read,
0158     .proc_write = fifo_write,
0159     .proc_lseek = noop_llseek,
0160 };
0161 
0162 static int __init example_init(void)
0163 {
0164 #ifdef DYNAMIC
0165     int ret;
0166 
0167     ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
0168     if (ret) {
0169         printk(KERN_ERR "error kfifo_alloc\n");
0170         return ret;
0171     }
0172 #else
0173     INIT_KFIFO(test);
0174 #endif
0175     if (testfunc() < 0) {
0176 #ifdef DYNAMIC
0177         kfifo_free(&test);
0178 #endif
0179         return -EIO;
0180     }
0181 
0182     if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
0183 #ifdef DYNAMIC
0184         kfifo_free(&test);
0185 #endif
0186         return -ENOMEM;
0187     }
0188     return 0;
0189 }
0190 
0191 static void __exit example_exit(void)
0192 {
0193     remove_proc_entry(PROC_FIFO, NULL);
0194 #ifdef DYNAMIC
0195     kfifo_free(&test);
0196 #endif
0197 }
0198 
0199 module_init(example_init);
0200 module_exit(example_exit);
0201 MODULE_LICENSE("GPL");
0202 MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");