proc_create() example for kernel module - linux-kernel

Can someone give me proc_create() example?
Earlier they used create_proc_entry() in the kernel but now they are using proc_create().

This example will create a proc entry which enables reading access. I think you can enable other kinds of access by changing the mode argument passed to the function. I haven't passed a parent directory because there is no need to. The structure file_operations is where you setup your reading and writing callbacks.
struct proc_dir_entry *proc_file_entry;
static const struct file_operations proc_file_fops = {
.owner = THIS_MODULE,
.open = open_callback,
.read = read_callback,
};
int __init init_module(void){
proc_file_entry = proc_create("proc_file_name", 0, NULL, &proc_file_fops);
if(proc_file_entry == NULL)
return -ENOMEM;
return 0;
}
You can check this example for more details: https://www.linux.com/learn/linux-training/37985-the-kernel-newbie-corner-kernel-debugging-using-proc-qsequenceq-files-part-1

Here is a 'hello_proc' code, which makes use of the newer 'proc_create()' interface.
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static int hello_proc_show(struct seq_file *m, void *v) {
seq_printf(m, "Hello proc!\n");
return 0;
}
static int hello_proc_open(struct inode *inode, struct file *file) {
return single_open(file, hello_proc_show, NULL);
}
static const struct file_operations hello_proc_fops = {
.owner = THIS_MODULE,
.open = hello_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init hello_proc_init(void) {
proc_create("hello_proc", 0, NULL, &hello_proc_fops);
return 0;
}
static void __exit hello_proc_exit(void) {
remove_proc_entry("hello_proc", NULL);
}
MODULE_LICENSE("GPL");
module_init(hello_proc_init);
module_exit(hello_proc_exit);
This code has been taken from http://pointer-overloading.blogspot.com/2013/09/linux-creating-entry-in-proc-file.html

This reply is just an update to #Alhaad Gokhale's great answer. The hello world module, as of kernels > 5.6 looks like this:
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static int hello_proc_show(struct seq_file *m, void *v) {
seq_printf(m, "Hello proc!\n");
return 0;
}
static int hello_proc_open(struct inode *inode, struct file *file) {
return single_open(file, hello_proc_show, NULL);
}
static const struct proc_ops hello_proc_fops = {
.proc_open = hello_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init hello_proc_init(void) {
proc_create("hello_proc", 0, NULL, &hello_proc_fops);
return 0;
}
static void __exit hello_proc_exit(void) {
remove_proc_entry("hello_proc", NULL);
}
MODULE_LICENSE("GPL");
module_init(hello_proc_init);
module_exit(hello_proc_exit);
Key differences to note are:
struct proc_ops replaces struct file_operations.
member name changes from .open, .read to .proc_open, .proc_read...
Need to remove the .owner line.
Further information:
This patch
This more detailed SO answer on changes.

Related

BUG: Unable to handle kernel paging request at error for the sample kernel module

I am writing a sample kernel module which reads data sent through ioctl call from application and prints them.
I am passing structure "ioctl_struct" through ioctl from the application and in the kernel module, I will be printing its member variables.
this works absolutely fine in a few machines. In a few machines
"BUG: unable to handle kernel paging request at"
the error is thrown while accessing "name and testStruct's id1 and id2".
I don't think this module is hardware/kernel dependent.
I am not sure where it's going wrong. any help would be appreciated.
thanks.
Driver.c kernel module
static const char DEVICE_NAME[]="testipc";
static struct proc_dir_entry * proc_ipc = NULL;
struct test
{
int id1;
int id2;
};
struct ioctl_struct
{
__user struct test *testStruct;
__user int * id;
__user char * name;
int cmd;
};
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
.unlocked_ioctl = etx_ioctl,
};
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk("reached ioctl....\n");
struct ioctl_struct buf;
if (copy_from_user(&buf, (void *)arg, sizeof(buf)))
return -EFAULT;
printk("succes..2\n");
printk("id %d\n",buf.id);
printk("cmd %d\n",buf.cmd);
printk("filename %s\n",buf.name);
printk("token %d\n",buf.testStruct->id1);
printk("token %d\n",buf.testStruct->id2);
return 0;
}
static int __init etx_driver_init(void)
{
printk("new test driver loaded..");
proc_ipc = proc_create(DEVICE_NAME, 0, NULL, &fops);
if (!proc_ipc)
{
printk(KERN_ALERT "Unable to create /proc/%s\n", DEVICE_NAME);
return 1;
}
return 0;
}
void __exit etx_driver_exit(void)
{
if (proc_ipc)
proc_remove(proc_ipc);
proc_ipc = NULL;
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lin");
MODULE_DESCRIPTION("A simple driver");
MODULE_VERSION("1.0");
and following is my application file
#include <stdio.h>
#include<sys/ioctl.h>
# define __user
static int fd=NULL;
#define TEST_IOCTL _IOWR('z', 80, struct ioctl_struct)
struct test
{
int id1;
int id2;
};
struct ioctl_struct
{
__user struct test *testStruct;
__user int * id;
__user char * name;
int cmd;
};
void init()
{
printf("\nOpening Driver\n");
fd = open("/proc/testipc", O_RDWR);
if(fd < 0) {
printf("Cannot open device file...\n");
return 0;
}
}
void send()
{
int id=5;
int *pid=id;
char name[10]={'H','e','l','l','o'};
struct test testStruct;
testStruct.id1=44;
testStruct.id2=33;
struct ioctl_struct request;
request.name = name ;
request.id = pid;
request.cmd = 33;
request.testStruct = &testStruct;
ioctl(fd, TEST_IOCTL, &request);
}
void finish()
{
printf("Closing Driver\n");
close(fd);
}
int main()
{
init();
send();
finish();
return 0;
}
In dmesg,
id 5,
cmd 33,
Hello,
44,
33,
should be printed

Create an Entry in /proc

I have successfully created a pseudo Hello World Entry with a LKM.
http://pointer-overloading.blogspot.co.at/2013/09/linux-creating-entry-in-proc-file.html
However in my init function, i have one integer value which i want to return in "cat /proc/example".
Any Ideas how to do this in this code?
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static int hello_proc_show(struct seq_file *m, void *v) {
seq_printf(m, "Hello proc!\n");
return 0;
}
static int hello_proc_open(struct inode *inode, struct file *file) {
return single_open(file, hello_proc_show, NULL);
}
static const struct file_operations hello_proc_fops = {
.owner = THIS_MODULE,
.open = hello_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init hello_proc_init(void) {
proc_create("hello_proc", 0, NULL, &hello_proc_fops);
return 0;
}
static void __exit hello_proc_exit(void) {
remove_proc_entry("hello_proc", NULL);
}
MODULE_LICENSE("GPL");
module_init(hello_proc_init);
module_exit(hello_proc_exit);
If procfs is not the strict requirement then make use of 'kobject' to create the sysfs entry. Refer below example and modify foo_show function as per your requirement. Otherwise, the comment from #mali will do the trick.
https://github.com/saiyamd/linux/blob/master/samples/kobject/kobject-example.c

in kernel driver, why does not mmap work in procfs?

I implement mmap function, and mount it to file operation.
And create a file in /proc.
but when I insmod, it responses "mmap_example2: Unknown symbol _page_cachable_default
insmod: can't insert 'mmap_example2.ko': unknown symbol in module, or unknown parameter"
when i remove mmap function from file operations, it can be inserted.
so do i neglect something? how to make mmap work in procfs?
the code is below
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#define FILE_NAME "test"
typedef enum ALLOC_TYPE
{
KMALLOC = 0, VMALLOC, MAX_ALLOC_TYPE,
} eAllocType;
static unsigned char array[10]={0,1,2,3,4,5,6,7,8,9};
static unsigned char *buffer;
static int file_open(struct inode *pInode, struct file *pFile)
{
printk("%s\n", __FUNCTION__);
return 0;
}
static int file_release(struct inode *pInode, struct file *pFile)
{
printk("%s\n", __FUNCTION__);
return 0;
}
static int file_mmap(struct file *pFile, struct vm_area_struct* pVMA)
{
unsigned long page;
unsigned char i;
unsigned long start = (unsigned long)pVMA->vm_start;
unsigned long size = (unsigned long)(pVMA->vm_end - pVMA->vm_start);
page = virt_to_phys(buffer);
if(remap_pfn_range(pVMA,start,page>>PAGE_SHIFT,size,PAGE_SHARED))
return -1;
for(i=0;i<10;i++)
buffer[i] = array[i];
return 0;
}
struct file_operations file_ops =
{
.open = file_open,
.release = file_release,
.mmap = file_mmap,
};
static int mmap_example2_init(void)
{
struct proc_dir_entry* entry = NULL;
printk("%s init\n", __FUNCTION__);
if(!(entry = create_proc_entry(FILE_NAME,0666,NULL)))
{
printk("%s fail to create proc file\n",__FUNCTION__);
return -EINVAL;
}
entry->proc_fops = &file_ops;
buffer = kmalloc(10,GFP_KERNEL);
if (!buffer)
{
printk("allocate mem error\n");
return -1;
}
SetPageReserved(virt_to_page(buffer));
return 0;
}
static void mmap_example2_exit(void)
{
printk("%s exit\n", __FUNCTION__);
remove_proc_entry(FILE_NAME,NULL);
ClearPageReserved(virt_to_page(buffer));
kfree(buffer);
}
module_init(mmap_example2_init);
module_exit(mmap_example2_exit);
To add file_operations use proc_create instead of create_proc_entry and pass it your file_operation object
static struct file_operations myops =
{
.read = myread,
.mmap = mymmap,
};
static int simple_init(void)
{
ent=proc_create("mytest",0660,NULL,&myops);
printk(KERN_ALERT "hello, module %d...\n",irq);
return 0;
}

Copy data into buffer to print at stdout

I am writing a linux kernel module that creates a block device which lists the process list.
I am able to display the list in the kernel log file but now I am trying to display the output to stdout. My aim is to create a big string in dev_open() that contains all the processes and then copy that string to the buffer which goes to the dev_read() function.
However, I am trying the following code but I get a message to stdout saying "Killed".
What does this mean ? How can I solve this.
Code ::
#include <linux/module.h>
#include<linux/sched.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
static int dev_open(struct inode *, struct file *);
static int dev_rls(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
int len,temp;
char msg[1000];
int tem;
static struct file_operations fops =
{
.read = dev_read,
.open = dev_open,
.release = dev_rls,
};
int init_module(void)
{
int t = register_chrdev(81,"tempo",&fops);
if(t<0) printk(KERN_ALERT "Device failed to register!");
else printk(KERN_ALERT "Registered device...\n");
return t;
}
static int dev_open(struct inode *inod, struct file *fil)
{
struct task_struct *task;
for_each_process(task)
{
printk("%s [%d]\n",task->comm, task->pid);
strcat(&msg[0],task->comm);
len=strlen(msg);
temp=len;
tem++;
}
printk("%s [%d]\n",task->comm , task->pid);
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(81,"tempo");
}
static ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offp)
{
printk("Hi\n");
if(count>temp)
{
count=temp;
}
temp=temp-count;
copy_to_user(buf,msg, count);
if(count==0)
temp=len;
return count;
//return 0;
}
static int dev_rls(struct inode *inod, struct file *fil)
{
printk(KERN_ALERT"Done with device\n");
return 0;
}

After insmod I am not able to see the device entry in /proc/devices

After performing the command "insmod demo_device" the modules listed in /proc/modules
**demo_device 2528 0 - Live 0xe02da000**
fp_indicators 5072 1 - Live 0xe02d2000 (P)
screader 22672 1 - Live 0xe02c5000 (P)
icamdescrambler 12912 0 - Live 0xe02b2000 (P)
icamemmfilter 16208 0 - Live 0xe02a4000 (P)
icamecmfilter 14992 0 - Live 0xe0294000 (P)
but "(P)" is not avail after that.
After firing the command cat /proc/devices the device "demo_device" is not listed there.
So my question is that: what (P) stands in (cat /proc/modules) and what could be the reason that the device is not listed in (cat /proc/devices).
Thanks in Advance !!
The source code is as:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include "query_ioctl.h"
#define FIRST_MINOR 0
#define MINOR_CNT 1
static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static int status = 1, dignity = 3, ego = 5;
static int my_open(struct inode *i, struct file *f)
{
return 0;
}
static int my_close(struct inode *i, struct file *f)
{
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
{
query_arg_t q;
switch (cmd)
{
case QUERY_GET_VARIABLES:
q.status = status;
q.dignity = dignity;
q.ego = ego;
if (copy_to_user((query_arg_t *)arg, &q, sizeof(query_arg_t)))
{
return -EACCES;
}
break;
case QUERY_CLR_VARIABLES:
status = 0;
dignity = 0;
ego = 0;
break;
case QUERY_SET_VARIABLES:
if (copy_from_user(&q, (query_arg_t *)arg, sizeof(query_arg_t)))
{
return -EACCES;
}
status = q.status;
dignity = q.dignity;
ego = q.ego;
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations query_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = my_ioctl
#else
.unlocked_ioctl = my_ioctl
#endif
};
static int __init query_ioctl_init(void)
{
int ret;
struct device *dev_ret;
printk("Before calling alloc\n");
dev=150;
if ((ret = register_chrdev_region(dev, MINOR_CNT, "demo_device")))
{
return ret;
}
else if((ret = alloc_chrdev_region(&dev,0,MINOR_CNT,"demo_device")))
{
return ret;
}
printk("After alloc %d %d\n",ret,dev);
cdev_init(&c_dev, &query_fops);
if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
{
return ret;
}
printk("After cdev_add\n");
if (IS_ERR(cl = class_create(THIS_MODULE, "char")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(cl);
}
printk("After class_create\n");
if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "demo")))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(dev_ret);
}
printk("After device_create\n");
return 0;
}
static void __exit query_ioctl_exit(void)
{
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
}
module_init(query_ioctl_init);
module_exit(query_ioctl_exit);
MODULE_LICENSE("GPL");
And after inserting the module I am able to see these messages:
$insmod demo_device.ko
Before calling alloc
After alloc 0 217055232
After cdev_add
After class_create
After device_create
$
Make sure that Major Number of the device is not preoccupied by some other device file. use the following command to check the occupied Major Numbers
cat /proc/devices
Use the following code to capture initialization error in init function
int t=register_chrdev(majorNumber,"mydev",&fops);
if(t<0)
printk(KERN_ALERT "device registration failed.");
Use dmesg to look into kernel logs
Look at module_flags_taint() in kernel/module.c.
The 'P' flag merely indicated the other modules are proprietary. The reason your device doesn't show up in /proc/devices is probably because something is wrong with the initialisation, but we can't help you with that unless you show us code.
After perfroming make clean to the linux/application source code and rebuilding it again...make it works. Now after inserting the module the corresponding entry is visibe in the /proc/devcies file :)

Resources