Writing Ubuntu 20.04 driver, problems with compiling it - c

I was writing a code for my driver and i cannot check it because i cannot compile it. I tried to reinstall ubuntu and used all this commands on a clean OS but i faced the same problem so i suppose it's only a problem with library installation.
Code for my driver:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> // kmalloc()
#include <linux/uaccess.h> // copy_to/from_user()
#include <linux/proc_fs.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/netdevice.h>
#include <linux/device.h>
#define BUF_SIZE 1024
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Stab linux module for operating system's lab");
MODULE_VERSION("1.0");
static int pid = 1;
static int struct_id = 1;
static struct proc_dir_entry *parent;
/*
** Function Prototypes
*/
static int __init lab_driver_init(void);
static void __exit lab_driver_exit(void);
/***************** Procfs Functions *******************/
static int open_proc(struct inode *inode, struct file *file);
static int release_proc(struct inode *inode, struct file *file);
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset);
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off);
/*
** procfs operation sturcture
*/
static struct proc_ops proc_fops = {
.proc_open = open_proc,
.proc_read = read_proc,
.proc_write = write_proc,
.proc_release = release_proc
};
// net_device
static size_t write_net_device_struct(char __user *ubuf){
char buf[BUF_SIZE];
size_t len = 0;
static struct net_device *dev;
read_lock(&dev_base_lock);
dev = first_net_device(&init_net);
while(dev){
len += sprintf(buf+len, "found [%s]\n", dev->name);
len += sprintf(buf+len, "base_addr = %ld\n", dev->base_addr);
len += sprintf(buf+len, "mem_start = %ld\n", dev->mem_start);
len += sprintf(buf+len, "mem_end = %ld\n\n", dev->mem_end);
dev = next_net_device(dev);
}
read_unlock(&dev_base_lock);
if (copy_to_user(ubuf, buf, len)){
return -EFAULT;
}
return len;
}
// signal_struct
static size_t write_signal_struct(char __user *ubuf, struct task_struct *task_struct_ref){
char buf[BUF_SIZE];
size_t len = 0;
struct signal_struct *signalStruct = task_struct_ref->signal;
len += sprintf(buf, "live = %d\n", atomic_read(&(signalStruct->live)));
len += sprintf(buf+len, "nr_threads = %d\n", signalStruct->nr_threads);
len += sprintf(buf+len, "group_exit_code = %d\n", signalStruct->group_exit_code);
len += sprintf(buf+len, "notify_count = %d\n", signalStruct->notify_count);
len += sprintf(buf+len, "group_stop_count = %d\n", signalStruct->group_stop_count);
len += sprintf(buf+len, "flags = %d\n", signalStruct->flags);
len += sprintf(buf+len, "is_child_subreaper = %d\n", signalStruct->is_child_subreaper);
len += sprintf(buf+len, "has_child_subreaper = %d\n", signalStruct->has_child_subreaper);
if (copy_to_user(ubuf, buf, len)){
return -EFAULT;
}
return len;
}
/*
** Эта фануция будет вызвана, когда мы ОТКРОЕМ файл procfs
*/
static int open_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file opend.....\t");
return 0;
}
/*
** Эта фануция будет вызвана, когда мы ЗАКРОЕМ файл procfs
*/
static int release_proc(struct inode *inode, struct file *file)
{
printk(KERN_INFO "proc file released.....\n");
return 0;
}
/*
** Эта фануция будет вызвана, когда мы ПРОЧИТАЕМ файл procfs
*/
static ssize_t read_proc(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) {
char buf[BUF_SIZE];
int len = 0;
struct task_struct *task_struct_ref = get_pid_task(find_get_pid(pid), PIDTYPE_PID);
printk(KERN_INFO "proc file read.....\n");
if (*ppos > 0 || count < BUF_SIZE){
return 0;
}
if (task_struct_ref == NULL){
len += sprintf(buf,"task_struct for pid %d is NULL. Can not get any information\n",pid);
if (copy_to_user(ubuf, buf, len)){
return -EFAULT;
}
*ppos = len;
return len;
}
switch(struct_id){
default:
case 0:
len = write_net_device_struct(ubuf);
break;
case 1:
len = write_signal_struct(ubuf, task_struct_ref);
break;
}
*ppos = len;
return len;
}
/*
** Эта фануция будет вызвана, когда мы ЗАПИШЕМ в файл procfs
*/
static ssize_t write_proc(struct file *filp, const char __user *ubuf, size_t count, loff_t *ppos) {
int num_of_read_digits, c, a, b;
char buf[BUF_SIZE];
printk(KERN_INFO "proc file wrote.....\n");
if (*ppos > 0 || count > BUF_SIZE){
return -EFAULT;
}
if( copy_from_user(buf, ubuf, count) ) {
return -EFAULT;
}
num_of_read_digits = sscanf(buf, "%d %d", &a, &b);
if (num_of_read_digits != 2){
return -EFAULT;
}
struct_id = a;
pid = b;
c = strlen(buf);
*ppos = c;
return c;
}
/*
** Функция инициализации Модуля
*/
static int __init lab_driver_init(void) {
/* Создание директории процесса. Она будет создана в файловой системе "/proc" */
parent = proc_mkdir("lab",NULL);
if( parent == NULL )
{
pr_info("Error creating proc entry");
return -1;
}
/* Создание записи процесса в разделе "/proc/lab/" */
proc_create("struct_info", 0666, parent, &proc_fops);
pr_info("Device Driver Insert...Done!!!\n");
return 0;
}
/*
** Функция выхода из Модуля
*/
static void __exit lab_driver_exit(void)
{
/* Удаляет 1 запись процесса */
//remove_proc_entry("lab/struct_info", parent);
/* Удяление полностью /proc/lab */
proc_remove(parent);
pr_info("Device Driver Remove...Done!!!\n");
}
module_init(lab_driver_init);
module_exit(lab_driver_exit);
My makefile:
obj-m += driver.c
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The problem i am facing:
sudo make
make -C /lib/modules/5.11.0-37-generic/build M= modules
make[1]: Entering directory '/usr/src/linux-headers-5.11.0-37-generic'
make[2]: *** No rule to make target 'arch/x86/tools/relocs_32.c', needed by 'arch/x86/tools/relocs_32.o'. Stop.
make[1]: *** [arch/x86/Makefile:211: archscripts] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.11.0-37-generic'
make: *** [Makefile:4: all] Error 2
Also i installed a list of tools for developing drivers: sudo apt-get install libncurses-dev flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf and sudo apt-get install build-essential linux-headers-'uname -r'. So i don't know how to fix this problem and maybe you know.

Related

One ioctl not being executed in kernel module

I wrote a kernel module demonstrating on how ioctl works.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
int base_minor = 0;
char *device_name = "msg";
int count = 1;
dev_t devicenumber;
static struct class *class = NULL;
static struct device *device = NULL;
static struct cdev mycdev;
#define MAX_SIZE 1024
char kernel_buffer[MAX_SIZE];
int buffer_index;
MODULE_LICENSE("GPL");
static int device_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
file->f_pos = 0;
buffer_index = 0;
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
return 0;
}
static ssize_t device_read(struct file *file, char __user *user_buffer,
size_t read_count, loff_t *offset)
{
int bytes_read;
int available_space;
int bytes_to_read;
pr_info("%s read offset:%lld\n", __func__, *offset);
available_space = MAX_SIZE - *(offset);
if (read_count < available_space)
bytes_to_read = read_count;
else
bytes_to_read = available_space;
pr_info("bytes_to_read:%d\n", bytes_to_read);
if (bytes_to_read == 0) {
pr_err("%s: No available space in the buffer for reading\n",
__func__);
return -ENOSPC;
}
if (buffer_index > *offset)
bytes_to_read = buffer_index - *offset;
else
return 0;
bytes_read = bytes_to_read - copy_to_user(user_buffer, kernel_buffer+*offset, bytes_to_read);
pr_info("%s: Copy to user returned:%d\n", __func__, bytes_to_read);
//update file offset
*offset += bytes_read;
return bytes_read;
}
static ssize_t device_write(struct file *file, const char __user *user_buffer,
size_t write_count, loff_t *offset)
{
int bytes_written;
int available_space;
int bytes_to_write;
pr_info("%s write offset:%lld\n", __func__, *offset);
available_space = MAX_SIZE - *(offset);
if (write_count < available_space)
bytes_to_write = write_count;
else
bytes_to_write = available_space;
if (bytes_to_write == 0) {
pr_err("%s: No available space in the buffer for writing\n",
__func__);
return -ENOSPC;
}
bytes_written = bytes_to_write - copy_from_user(kernel_buffer+*offset, user_buffer, bytes_to_write);
pr_info("%s: Bytes written:%d\n", __func__, bytes_written);
pr_info("%s: kernel_buffer:%s\n", __func__, kernel_buffer);
//update file offset
*offset += bytes_written;
buffer_index += bytes_written;
return bytes_written;
}
static loff_t device_lseek(struct file *file, loff_t offset, int orig)
{
loff_t new_pos = 0;
switch(orig) {
case 0 : /*seek set*/
new_pos = offset;
break;
case 1 : /*seek cur*/
new_pos = file->f_pos + offset;
break;
case 2 : /*seek end*/
new_pos = MAX_SIZE - offset;
break;
}
if(new_pos > MAX_SIZE)
new_pos = MAX_SIZE;
if(new_pos < 0)
new_pos = 0;
file->f_pos = new_pos;
return new_pos;
}
long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char ch;
pr_info("%s: Cmd:%u\t Arg:%lu\n", __func__, cmd, arg);
switch(cmd)
{
//Get Length of buffer
case 0x01:
pr_info("Get Buffer Length\n");
put_user(MAX_SIZE, (unsigned int *)arg);
break;
//clear buffer
case 0x02:
pr_info("Clear buffer\n");
memset(kernel_buffer, 0, sizeof(kernel_buffer));
break;
//fill character
case 0x03:
get_user(ch, (unsigned char *)arg);
pr_info("Fill Character:%c\n", ch);
memset(kernel_buffer, ch, sizeof(kernel_buffer));
buffer_index = sizeof(kernel_buffer);
break;
default:
pr_info("Unknown Command:%u\n", cmd);
return -EINVAL;
}
return 0;
}
struct file_operations device_fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release,
.llseek = device_lseek,
.unlocked_ioctl = device_ioctl
};
static int test_hello_init(void)
{
class = class_create(THIS_MODULE, "myclass");
if (!alloc_chrdev_region(&devicenumber, base_minor, count, device_name)) {
printk("Device number registered\n");
printk("Major number received:%d\n", MAJOR(devicenumber));
device = device_create(class, NULL, devicenumber, NULL, device_name);
cdev_init(&mycdev, &device_fops);
mycdev.owner = THIS_MODULE;
cdev_add(&mycdev, devicenumber, count);
}
else
printk("Device number registration Failed\n");
return 0;
}
static void test_hello_exit(void)
{
device_destroy(class, devicenumber);
class_destroy(class);
cdev_del(&mycdev);
unregister_chrdev_region(devicenumber, count);
}
module_init(test_hello_init);
module_exit(test_hello_exit);
Then i wrote a user space code
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
int main(int argc, char *argv[])
{
char buffer[1024];
int fd;
unsigned int length;
unsigned char ch = 'A';
int i = 0;
fd = open("/dev/msg", O_RDWR);
if (fd < 0) {
perror("fd failed");
exit(2);
}
//Get Length - 0x01
ioctl(fd, 0x01, &length);
printf("Length:%u\n", length);
ioctl(fd, 0x02);
//Set Character - 0x03
ioctl(fd, 0x03, &ch);
perror("ioctl");
lseek(fd, 0, SEEK_SET);
perror("lseek");
length = read(fd, buffer, 1024);
perror("Read");
printf("length:%d\n", length);
buffer[1023] = '\0';
printf("Buffer:%s\n", buffer);
close(fd);
}
ioctl commands 1, 3 work but not 2. Can you please provide what's the mistake in the code
You should review the requirements for ioctl on the man page:
DESCRIPTION
The ioctl() system call manipulates the underlying device parameters of
special files. In particular, many operating characteristics of char‐
acter special files (e.g., terminals) may be controlled with ioctl()
requests. The argument fd must be an open file descriptor.
The second argument is a device-dependent request code. The third
argument is an untyped pointer to memory. It's traditionally char
*argp (from the days before void * was valid C), and will be so named
for this discussion.
An ioctl() request has encoded in it whether the argument is an in
parameter or out parameter, and the size of the argument argp in bytes.
Macros and defines used in specifying an ioctl() request are located in
the file <sys/ioctl.h>.

Linux kernel module : Is it possible to use an open function inside another open function for my module?

Maybe this question makes no sense, but I was wondering if there was a "recommended practice" on how to open a file descriptor for a device inside an open function of the created module.
In fact, I developped a simple Linux kernel module with its basic functions :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
I compile it and no errors occured.
Now I want to open the file descriptor of my device ( BUTTON ) in order to manipulate it later from user space program, so I made some modifications by adding the BUTTON device path and another open function like this :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
#define BTN_FILE_PATH "/dev/input/event0"
int file;
char *str = BTN_FILE_PATH;
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
if((file = open(str, O_RDONLY)) < 0) {
printk("simplekey: File can not open");
return(-1);
}
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
But the problem, when I try to compile the module now errors are printed :
/home/gaston/ledshared/exer_simple_char_drv.c: In function
‘exer_open’: /home/gaston/ledshared/exer_simple_char_drv.c:32:13:
error: implicit declaration of function ‘open’
[-Werror=implicit-function-declaration]
if((file = open(str,O_RDONLY)) < 0) {
How can I fix the problem please ?
open() is a user-space function. The equivalent kernel-space function is filp_open(), but it returns a struct file * instead of a int file descriptor. The returned struct file * could be an error code instead of a valid pointer. Use the IS_ERR(ptr) macro to check for that, and the PTR_ERR(ptr) macro to extract the error code (which will be a negated errno value).
Use of the filp_open function is discouraged, but here are some modifications to your code to use this function:
int exer_open(struct inode *pinode, struct file *pfile) {
struct file *f;
f = filp_open(str, O_RDONLY);
if (IS_ERR(f)) {
printk("simplekey: File can not open");
return(PTR_ERR(f));
}
pfile->private_data = f;
printk(KERN_INFO "Device has been opened\n");
return 0;
}
The close function should look something like this:
int exer_close(struct inode *pinode, struct file *pfile) {
struct file *f = pfile->private_data;
int rc;
rc = filp_close(f, NULL);
if (rc == 0) {
printk(KERN_INFO "Device successfully closed\n");
}
return rc;
}
There is no legitimate way for a module to read from a struct file * directly into a user-space buffer or write from a user-space buffer to a struct file *, so an intermediate buffer in kernel memory is needed, so that kernel_read() or kernel_write() can be used to read or write the file:
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
buf = kmalloc(buf_size, GFP_KERNEL);
if (buf == NULL) {
return -ENOMEM;
}
}
/* Read file to buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
rc = kernel_read(f, buf, amount, offset);
if (rc > 0) {
/* Have read some data from file. */
if (copy_to_user(buffer, buf, rc) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
if (rc < amount) {
/* Didn't read the full amount, so terminate early. */
rc = 0;
}
}
}
} while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
buf = kmalloc(buf_size, GFP_KERNEL);
if (buf == NULL) {
return -ENOMEM;
}
}
/* Write file from buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
if (copy_from_user(buf, buffer, amount) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
rc = kernel_write(f, buf, amount, offset);
if (rc > 0) {
/* Have written some data to file. */
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
if (rc < amount) {
/* Didn't write the full amount, so terminate early. */
rc = 0;
}
}
}
} while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}

make error aliased to undefined symbol devone_init

I have just made a driver program, and when I execute make, it said
make error aliased to undefined symbol devone_init
I find many sites and cannot find the same error.Because I am new to
device programing , I am not clear about init_module.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/uaccess.h>
MODULE_LICENCE("Dual BSD/GPL");
#define DRIVER_NAME "devone";
static int devone_devs = 2;
static int devone_major = 0;
module_param(devone_major. uint, 0);
static struct cdev devone_cdev;
static int devone_open(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
static int devone_close(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
struct file_operations devone_fops = {
.open = devone_opens;
.release = devone_close;
}
static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, DRIVER_NAME);
if(alloc_ret)
goto error;
devone_major = major = MAJOR(dev);
cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, 0), devone_devs);
if(cdev_err)
goto error;
printk(KERN_ALERT "%s driver(%d) loaded\n", DRIVER_NAME, major);
return 0;
error:
if(cdev_err == 0)
cdev_del(devone_cdev);
if(alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);
return -1;
}
static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);
cdev_del(&devone_cdev);
cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);
printk(KERN_ALERT "%s driver unloaded\n", DRIVER_NAME);
}
module_init(devone_init);
module_exit(devone_exit);
here is my makefile.When I add cflags , it returned cflags was changed.
#CFLAGS += -Wall
CFILES = devone.c
obj-m += sample.o
KDIR =/lib/modules/$(shell uname -r)/build
sample-objs := $(CFILES:.c=.o)
all:
$(MAKE) -C $(KDIR) M=$(shell pwd) modules
clean:
rm -rf *.o *.ko *.mod.* *.symvers *.order
There are several minute problems in the code which is preventing it from compilation. Modified code which compiles properly is below. you can compare and find out the diff.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#define DRIVER_NAME "devone"
static int devone_devs = 2;
static int devone_major = 0;
module_param(devone_major, uint, 0);
static struct cdev devone_cdev;
static int devone_open(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
static int devone_close(struct inode *inode, struct file *file)
{
printk("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid);
inode->i_private = inode;
file->private_data = file;
printk("i_private=%p private_data=%p\n", inode->i_private, file->private_data);
return 0;
}
struct file_operations devone_fops = {
.open = devone_open,
.release = devone_close,
};
static int devone_init(void)
{
dev_t dev = MKDEV(devone_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, DRIVER_NAME);
if(alloc_ret)
goto error;
devone_major = major = MAJOR(dev);
cdev_init(&devone_cdev, &devone_fops);
devone_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, 0), devone_devs);
if(cdev_err)
goto error;
printk(KERN_ALERT "%s driver(%d) loaded\n", DRIVER_NAME, major);
return 0;
error:
if(cdev_err == 0)
cdev_del(&devone_cdev);
if(alloc_ret == 0)
unregister_chrdev_region(dev, devone_devs);
return -1;
}
static void devone_exit(void)
{
dev_t dev = MKDEV(devone_major, 0);
cdev_del(&devone_cdev);
cdev_del(&devone_cdev);
unregister_chrdev_region(dev, devone_devs);
printk(KERN_ALERT "%s driver unloaded\n", DRIVER_NAME);
}
module_init(devone_init);
module_exit(devone_exit);
MODULE_LICENSE("Dual BSD/GPL");

insmod: ERROR: Could not insert module : No such device

I'm trying to implement character device driver in C at Linux.
My code is as follows:
#include<linux/device.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/err.h>
#include<asm/uaccess.h>
#define SUCCESS 0
#define DEVICE_NAME "chardev"
#define BUF_LEN 80
MODULE_LICENSE("GPL");
static int Major;
static char msg[BUF_LEN]={0};
static short s_o_msg;
static int Device_Open = 0;
static struct class* chardevClass = NULL;
static struct device* chardevDevice = NULL;
static char *msg_Ptr;
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init chardev_init(void){
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
if (IS_ERR(chardevDevice)) {
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_ALERT
"Failed to create the device\n");
return PTR_ERR(chardevDevice);
}
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
static void __exit chardev_exit(void){
device_destroy(chardevClass, MKDEV(Major, 0));
class_unregister(chardevClass);
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Goodbye!\n");
}
static int device_open(struct inode *inodep, struct file *filep)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file *filep, char *buffer, size_t length, loff_t * offset){
int bytes_read = 0;
if (*msg_Ptr == 0)
return 0;
while (length && *msg_Ptr) {
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
return bytes_read;
}
static int device_release(struct inode *inodep, struct file *filep)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t device_write(struct file *filep, const char *buffer, size_t length, loff_t *offset){
sprintf(msg, "%s(%zu letters)", buffer, length);
s_o_msg = strlen(msg);
printk(KERN_INFO "Received %zu characters from the user\n", length);
return length;
}
module_init(chardev_init);
module_exit(chardev_exit);
then, I compile this with following command and to this moment everything looks just fine:
obj-m := memory.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
but when I tried to run this module with
sudo /sbin/insmod memory.ko
I get an error :
insmod: ERROR: Could not insert module : No such device
Could you explain me please what I'm doing wrong and what should I do to run this module properly?
Thanks a lot.
You forget to create the class( class_create) before device_create() because if you see
root#achal:/sys/class# ls
.. there are so many different class..
your device also should be in one class that's why create one class using class_create();
Add below line in your code.
chardevClass = class_create(THIS_MODULE, "overflow");
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
root mode is required for inserting a module, Sequence for compiling, inserting and running a module are :
First do make
root#root:~/s_flow# make
then do insmod & analyse dmesg output
root#root:~/s_flow# insmod memory.ko
root#root:~/s_flow# dmesg
..
.. check here whether __init chardev_init() is invoked or not
or you can check modinfo also
root#root:~/s_flow# modifno memory.ko
I hope it helps.

Error: "device or resource busy" in removing proc module

I wrote a linux module to creat a proc file and write and read the data from it. But I am unable to remove the module, its showing an error unable to remove saying "device or resource busy. here is my code.
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h> /*this is the file structure, file open read close */
#include<linux/cdev.h> /* this is for character device, makes cdev avilable*/
#include<linux/semaphore.h> /* this is for the semaphore*/
#include<linux/uaccess.h> /*this is for copy_user vice vers*/
#include<linux/proc_fs.h>
#define MAX_LEN 1024
int read_info(char *page, char **start, off_t off, int count, int *eof, void *data);
int write_info(struct file *filp, const char __user *buffer, unsigned long length, void *data);
static struct proc_dir_entry *proc_entry;
static char *info;
static int write_index;
static int read_index;
int write_info(struct file *filp, const char __user *buffer, unsigned long length, void *data) {
int capacity = (MAX_LEN - write_index) +1;
if(length > capacity) {
printk(KERN_INFO "NO sapce to write into peoc file \n");
return -1;
}
if(copy_from_user(&info[write_index], buffer, length))
return -2;
write_index += length;
printk(KERN_INFO " megharaj proc writing succesful, %d write \n", length);
return length;
}
int read_info(char *page, char **start, off_t off, int count, int *eof, void *data) {
int len;
len = sprintf(page, "%s\n", &info[read_index]);
read_index += len;
printk(KERN_INFO " megharaj proc reading succesful, %d read \n", len);
return len;
}
int init_module(void)
{
int ret = 0;
info = (char *)vmalloc(MAX_LEN);
memset(info, 0 , MAX_LEN);
/*truct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);*/
proc_entry = create_proc_entry("megharaj_proc", 0666, NULL);
if(proc_entry == NULL) {
ret = -1;
vfree(info);
printk(KERN_INFO " megharaj proc not created \n");
}
else {
write_index = 0;
read_index = 0;
proc_entry->read_proc = read_info;
proc_entry->write_proc = write_info;
printk(KERN_INFO " megharaj proc created \n");
}
return ret;
}
void clean_module(void)
{
vfree(info);
remove_proc_entry("megharaj_proc", NULL);
}
also attaching the makefile,
obj-m := proc.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
echo and cat on proc file are working. Once work is done i am not able to remove the module by using sudo rmmod proc
output from lsmod shows
proc 12518 0 [permanent]
Now another question, what is this permanent ? Is this the problem. ?
Either name the module cleanup function cleanup_module (and not clean_module) or specifically declare it as a cleanup function (much better) like so:
module_init(init_module);
module_exit(clean_module);

Resources