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);
Related
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.
I have an assignment, where I have to create a proc_entry which can be written to(by user) and read from(by kernel).
The motive is that the kernel code should be able to read the value in the proc_entry, and use it later as a threshold for number of files opened by a process. If a process has opened more files that this threshold, it will be penalized in the scheduler. As user can also change value inside this proc_entry, thus, kernel will use this threshold dynamically.
Most of the codes I have seen online, tell how to create a module that will create such an entry, and another module that given the path of this entry, will read the string present.
The code for the module to create I/O proc_entry is- (Using the below module, I am able to create a proc_entry "/proc/my_proc_entry_write", to which, I can write using- "echo 200 > /proc/my_proc_entry_write", and read this value via "cat /proc/my_proc_entry_write")-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/types.h>
#define DATA_SIZE 3000000 // We can keep 1024 bytes of data with us.
#define MY_PROC_ENTRY "my_proc_entry_write"
#define PROC_FULL_PATH "/proc/my_proc_entry_write"
struct proc_dir_entry *proc;
int len;
char *msg = NULL;
/*
* Function to write to the proc. Here we free get the new value from buffer,
* count from the buffer and then overwrite the data in our file.
*
* Note that - you can have any other implementation as well for this, all you have to
* ensure that you comply with the expectations of the write() system calls
* like filling in the buffer, and returning the numbers of character written.
*/
static ssize_t my_proc_write(struct file *filp, const char __user * buffer, size_t count, loff_t *pos) // buffer, of length count, should be copied to kernel
{
int i;
char *data = PDE_DATA(file_inode(filp)); // gives data pointer of file
if (count > DATA_SIZE) {
return -EFAULT;
}
printk(KERN_INFO "Printing the data passed. Count is %lu", (size_t) count);
for (i=0; i < count; i++) {
printk(KERN_INFO "Index: %d . Character: %c Ascii: %d", i, buffer[i], buffer[i]);
}
printk(KERN_INFO "Writing to proc");
if (copy_from_user(data, buffer, count)) {
return -EFAULT;
}
data[count-1] = '\0';
printk(KERN_INFO "msg has been set to %s", msg); // Due to kmalloc, msg points to this. So, when we write, msg is changed.
printk(KERN_INFO "Message is: ");
for (i=0; i < count; i++) {
printk(KERN_INFO "\n Index: %d . Character: %c", i, msg[i]);
}
*pos = (int) count; // length written to be copied to pos at end
len = count-1; // len is length of string. count is len+1, to accomodate the \0.
return count;
}
/*
* Function to read the proc entry, here we copy the data from our proc entry
* to the buffer passed.
*/
ssize_t my_proc_read(struct file *filp,char *buf, size_t count, loff_t *offp ) // copy to buf,which is in userspace
{
char* f_path; int i=0; char f_arr[128]; char* f_path_2;
while(i<128)
{
f_arr[i]=0;
i++;
}
f_path=dentry_path_raw(filp->f_path.dentry,f_arr,128);
printk(KERN_ERR"f_path: %s\n",f_path);
i=0;
while(i<128 && f_arr[i]==0)
{
i++;
}
if(i!=128)
{
f_path_2=&f_arr[i];
printk(KERN_ERR"f_path_2: %s\n",f_path_2);
}
int err;
char *data = PDE_DATA(file_inode(filp));
if ((int) (*offp) > len) {
return 0;
}
printk(KERN_INFO "Reading the proc entry, len of the file is %d", len);
if(!(data)) {
printk(KERN_INFO "NULL DATA");
return 0;
}
if (count == 0) {
printk(KERN_INFO "Read of size zero, doing nothing.");
return count;
} else {
printk(KERN_INFO "Read of size %d", (int) count);
}
count = len + 1; // +1 to read the \0 ; thus we store the previous written length in global variable len
err = copy_to_user(buf, data, count); // +1 for \0
printk(KERN_INFO "Read data : %s", buf);
*offp = count;
if (err) {
printk(KERN_INFO "Error in copying data.");
} else {
printk(KERN_INFO "Successfully copied data.");
}
return count;
}
/*
* The file_operations structure. This is the glue layer which associates the
* proc entry to the read and write operations.
*/
struct file_operations proc_fops = {
.read = my_proc_read,
.write = my_proc_write,
};
/*
* This function will create the proc entry. This function will allocate some
* data where the data will be written incase of a write to the proc entry. The
* same memory will be used to serve the reads. * Initially the function fills
* the data with DATA which has "100".
* The important function to see here is the proc_create_data, this function
* will take the proc entry name and create it with the given permissions
* (0666). We also need to pass the file_operations structure which has the
* function pointers to the functions which needs to be called when read or
* write is called on the file.
The last argument has the pointer to the data
* associated with the file. (So, by "char *data = PDE_DATA(file_inode(filp));", the 'data' is actually 'msg')
*/
int create_new_proc_entry(void) {
int i;
char *DATA = "100";
len = strlen(DATA);
msg = kmalloc((size_t) DATA_SIZE, GFP_KERNEL); // +1 for \0
if (msg != NULL) {
printk(KERN_INFO "Allocated memory for msg");
} else {
return -1;
}
strncpy(msg, DATA, len+1);
for (i=0; i < len +1 ; i++) {
printk(KERN_INFO "%c", msg[i]);
if (msg[i] == '\0') {
printk(KERN_INFO "YES");
}
}
proc = proc_create_data(MY_PROC_ENTRY, 0666, NULL, &proc_fops, msg);
if (proc) {
return 0;
}
return -1;
}
/* The init function of the module. Does nothing other than calling the
* create_new_proc_entry. */
int proc_init (void) {
if (create_new_proc_entry()) {
return -1;
}
return 0;
}
/* Function to remove the proc entry. Call this when the module unloads. */
void proc_cleanup(void) {
remove_proc_entry(MY_PROC_ENTRY, NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
Makefile for the above module is(assuming the code of module is written in file proc_write_read.c):-
MYPROC=proc_write_read
obj-m += $(MYPROC).o
export KROOT=/lib/modules/$(shell uname -r)/build
#export KROOT=/lib/modules/$(uname)3.2.0-23-generic/build
allofit: modules
modules: clean
#$(MAKE) -C $(KROOT) M=$(PWD) modules
modules_install:
#$(MAKE) -C $(KROOT) M=$(PWD) modules_install
kernel_clean:
#$(MAKE) -C $(KROOT) M=$(PWD) clean
clean: kernel_clean
rm -rf Module.symvers modules.order
insert: modules
dmesg -c
insmod proc_write_read.ko
remove: clean
rmmod proc_write_read
The module that reads this proc_entry, like a file is-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/types.h>
int proc_init(void)
{
struct file *f; ssize_t ret = -EBADF;int i;
char* f_path;
i=0;
f=NULL;
char buf[128]; char f_arr[128];
mm_segment_t fs;
i=0;
while(i<128)
{
buf[i] = 0;
f_arr[i]=0;
i++;
}
// To see in /var/log/messages that the module is operating
//printk(KERN_INFO "read_file- my module is loaded\n");
f = filp_open("/proc/my_proc_entry_write", O_RDONLY, 0);
if (IS_ERR(f)) {
printk(KERN_ERR "Error in filp_open: %p ; %d\n", f,PTR_ERR(f));
return 100000;
}
f_path=dentry_path_raw(f->f_path.dentry,f_arr,128);
printk(KERN_ERR"f_path_in_proc_entry_read: %s\n",f_path);
printk(KERN_ERR"kernel Below1!!!\n");
// Get current segment descriptor
fs = get_fs();
printk(KERN_ERR"kernel Below2!!!\n");
// Set segment descriptor associated to kernel space
set_fs(get_ds());
printk(KERN_ERR"kernel Below3!!!\n");
// Read the file
if (f!=NULL) {
if ((f->f_op)!=NULL && (f->f_op->read)!=NULL){
ret=f->f_op->read(f, buf, 128, &f->f_pos);
printk(KERN_ERR"kernel Below4!!!\n");
}
else
return 100000;
}
else
return 100000;
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_ERR "kernel Read my_proc_entry_write buf:%s\n",buf);
int val=0;
sscanf(buf, "%d", &val);
printk(KERN_ERR"kernel val: %d\n",val);
filp_close(f,NULL);
return val;
}
void proc_cleanup(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
module_init(proc_init);
module_exit(proc_cleanup);
Makefile for the above module(name=read_file_in_kernel) is-
obj-m += read_file_in_kernel.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
My question is- Both these modules work fine as userspace modules, via insmod, but if I copy-paste this code to the source code of kernel 4.19.200 (not exact copy-paste, just the main parts as functions), and use the 2nd module,i.e, read_file_in_kernel's code to access the proc value, I am getting an error, i.e, kernel is not able to boot.
On running gdb through the kernel, I found that the code in read_file_in_kernel went through the below code, thrice (i.e, when update_curr function in linux kernel called this function 3 times),i.e, f is being returned as an error every time-
if (IS_ERR(f)) {
printk(KERN_ERR "Error in filp_open: %p ; %d\n", f,PTR_ERR(f));
return 100000;
}
In the 4th call to read_file_in_kernel, the kernel froze on -
f = filp_open("/proc/my_proc_entry_write", O_RDONLY, 0);
Same case with gdb.
I don't know what I am doing wrong here. Is it that /proc/my_proc_entry_write is not being created during bootup when it is read, and so, filp_open is not able to open that proc_entry to be read.
I even tried removing the first module from kernel entirely, running it separately from user-space to create a proc_entry(my_proc_entry_write) beforehand, that will be loaded by default every time the kernel boots up. But still, same error is coming.
What correction should I make to this?
If this is not the way to create a dynamic proc_entry that can be written to by user and ready by kernel, what is?
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.
I want to get the process name from task_struct, but
I get an error dereferencing pointer to incomplete type (task->comm).
I have to use pid_task function.
I have no idea why it does not work.
ssize_t simple_read(struct file *filp, char __user *user_buf, size_t count, loff_t *f_pos) {
int len=0;
pid_struct = find_get_pid(pid);
task = pid_task(pid_struct,PIDTYPE_PID);
len = sprintf(user_buf,"\nname %s\n ",task->comm);
return len;
}
To find the task_struct of a process we can make use of the function pid_task defined in kernel/pid.c .
struct task_struct *pid_task(struct pid *pid, enum pid_type type)
Arguments:
pid : Pointer to the struct pid of the process.
pid_type: PIDTYPE_PID,
PIDTYPE_PGID,
PIDTYPE_SID,
PIDTYPE_MAX
To find the pid structure if we have the pid of a process we can use the functionfind_get_pid which is also defined in kernel/pid.c
struct pid *find_get_pid(pid_t nr)
In the below module we create a read/write proc entry named task_by_pid. Which ever process we want to find the task_struct of using its pid we can write to number into the proc entry.
When we read the proc entry, it will display the name of the process corresponding to the pid we wrote into it.
proc_task_pid:
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/pid.h>
#include <linux/pid_namespace.h>
int p_id;
struct pid *pid_struct;
struct task_struct *task;
static struct proc_dir_entry *proc_write_entry;
char *proc_name="task_by_pid";
int read_proc(char *buf,char **start,off_t offset,int count,int *eof,void *data )
{
int len=0;
pid_struct = find_get_pid(p_id);
task = pid_task(pid_struct,PIDTYPE_PID);
len = sprintf(buf,"\nname %s\n ",task->comm);
return len;
}
int write_proc(struct file *file,const char *buf,int count,void *data )
{
int ret;
char *id;
id = (char *)kmalloc(1000*sizeof(char),GFP_KERNEL);
printk(KERN_INFO "buf passed %s",buf);
if(copy_from_user(id,buf,count))
return -EFAULT;
printk(KERN_INFO "id passed %s",id);
p_id = simple_strtoul(id,NULL,0);
printk(KERN_INFO "pid %d ret %d",p_id,ret);
return sizeof(buf);
}
void create_new_proc_entry()
{
proc_write_entry = create_proc_entry(proc_name,0666,NULL);
if(!proc_write_entry)
{
printk(KERN_INFO "Error creating proc entry");
return -ENOMEM;
}
proc_write_entry->read_proc = read_proc ;
proc_write_entry->write_proc = write_proc;
printk(KERN_INFO "proc initialized");
}
int proc_init (void) {
create_new_proc_entry();
return 0;
}
void proc_cleanup(void) {
printk(KERN_INFO " Inside cleanup_module\n");
remove_proc_entry(proc_name,NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
Use the following make file to compile it:
ifneq ($(KERNELRELEASE),)
obj-m := proc_task_pid.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
Compile it using
$make
Insert it into the kernel:
$ insmod proc_task_pid.ko
Now let us try to find the name of the process with pid "1", which is always init.
$ printf "1" > /proc/task_by_pid
$ cat /proc/task_by_pid
name init
As expected the output is "init". Thus we can find the task_struct of any process using its pid.
Source code from here.
I wrote a simple character device driver & wanted to cross-compile it for craneboard (ARM architecture). My file name is gDev.c. I copied the file to kernel/drivers/char directory in craneboard source. I modified the Kconfig file in that same directory & added the following lines to it.
config TEST_GCHARD
tristate "My Character driver"
default m
I added the following line to the Makefile in the same directory.
obj-$(CONFIG_TEST_GCHARD) += gDev.o
I added the following line in the am3517_crane_defconfig in arch/arm/configs directory.
CONFIG_TEST_GCHARD=m
My problem is, when I set it as m in am3517_crane_defconfig, the file is not getting included for compilation. But, if I change it as y, it is getting compiled. But, I need it to be a module which I must insmod after board boots up. Please guide me whether I'm missing any steps. Thanks.
here goes the driver in megharajchard.c
#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*/
int chardev_init(void);
void chardev_exit(void);
static int device_open(struct inode *, struct file *);
static int device_close(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 loff_t device_lseek(struct file *file, loff_t offset, int orig);
/*new code*/
#define BUFFER_SIZE 1024
static char device_buffer[BUFFER_SIZE];
struct semaphore sem;
struct cdev *mcdev; /*this is the name of my char driver that i will be registering*/
int major_number; /* will store the major number extracted by dev_t*/
int ret; /*used to return values*/
dev_t dev_num; /*will hold the major number that the kernel gives*/
#define DEVICENAME "megharajchard"
/*inode reffers to the actual file on disk*/
static int device_open(struct inode *inode, struct file *filp) {
if(down_interruptible(&sem) != 0) {
printk(KERN_ALERT "megharajchard : the device has been opened by some other device, unable to open lock\n");
return -1;
}
//buff_rptr = buff_wptr = device_buffer;
printk(KERN_INFO "megharajchard : device opened succesfully\n");
return 0;
}
static ssize_t device_read(struct file *fp, char *buff, size_t length, loff_t *ppos) {
int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
int bytes_to_read; /* gives the number of bytes to read*/
int bytes_read;/*number of bytes actually read*/
maxbytes = BUFFER_SIZE - *ppos;
if(maxbytes > length)
bytes_to_read = length;
else
bytes_to_read = maxbytes;
if(bytes_to_read == 0)
printk(KERN_INFO "megharajchard : Reached the end of the device\n");
bytes_read = bytes_to_read - copy_to_user(buff, device_buffer + *ppos, bytes_to_read);
printk(KERN_INFO "megharajchard : device has been read %d\n",bytes_read);
*ppos += bytes_read;
printk(KERN_INFO "megharajchard : device has been read\n");
return bytes_read;
}
static ssize_t device_write(struct file *fp, const char *buff, size_t length, loff_t *ppos) {
int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
int bytes_to_write; /* gives the number of bytes to write*/
int bytes_writen;/*number of bytes actually writen*/
maxbytes = BUFFER_SIZE - *ppos;
if(maxbytes > length)
bytes_to_write = length;
else
bytes_to_write = maxbytes;
bytes_writen = bytes_to_write - copy_from_user(device_buffer + *ppos, buff, bytes_to_write);
printk(KERN_INFO "megharajchard : device has been written %d\n",bytes_writen);
*ppos += bytes_writen;
printk(KERN_INFO "megharajchard : device has been written\n");
return bytes_writen;
}
static loff_t device_lseek(struct file *file, loff_t offset, int orig) {
loff_t new_pos = 0;
printk(KERN_INFO "megharajchard : lseek function in work\n");
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 = BUFFER_SIZE - offset;
break;
}
if(new_pos > BUFFER_SIZE)
new_pos = BUFFER_SIZE;
if(new_pos < 0)
new_pos = 0;
file->f_pos = new_pos;
return new_pos;
}
static int device_close(struct inode *inode, struct file *filp) {
up(&sem);
printk(KERN_INFO "megharajchard : device has been closed\n");
return ret;
}
struct file_operations fops = { /* these are the file operations provided by our driver */
.owner = THIS_MODULE, /*prevents unloading when operations are in use*/
.open = device_open, /*to open the device*/
.write = device_write, /*to write to the device*/
.read = device_read, /*to read the device*/
.release = device_close, /*to close the device*/
.llseek = device_lseek
};
int chardev_init(void)
{
/* we will get the major number dynamically this is recommended please read ldd3*/
ret = alloc_chrdev_region(&dev_num,0,1,DEVICENAME);
if(ret < 0) {
printk(KERN_ALERT " megharajchard : failed to allocate major number\n");
return ret;
}
else
printk(KERN_INFO " megharajchard : mjor number allocated succesful\n");
major_number = MAJOR(dev_num);
printk(KERN_INFO "megharajchard : major number of our device is %d\n",major_number);
printk(KERN_INFO "megharajchard : to use mknod /dev/%s c %d 0\n",DEVICENAME,major_number);
mcdev = cdev_alloc(); /*create, allocate and initialize our cdev structure*/
mcdev->ops = &fops; /*fops stand for our file operations*/
mcdev->owner = THIS_MODULE;
/*we have created and initialized our cdev structure now we need to add it to the kernel*/
ret = cdev_add(mcdev,dev_num,1);
if(ret < 0) {
printk(KERN_ALERT "megharajchard : device adding to the kerknel failed\n");
return ret;
}
else
printk(KERN_INFO "megharajchard : device additin to the kernel succesful\n");
sema_init(&sem,1); /* initial value to one*/
return 0;
}
void chardev_exit(void)
{
cdev_del(mcdev); /*removing the structure that we added previously*/
printk(KERN_INFO " megharajchard : removed the mcdev from kernel\n");
unregister_chrdev_region(dev_num,1);
printk(KERN_INFO "megharajchard : unregistered the device numbers\n");
printk(KERN_ALERT " megharajchard : character driver is exiting\n");
}
MODULE_AUTHOR("A G MEGHARAJ(agmegharaj#gmail.com)");
MODULE_DESCRIPTION("A BASIC CHAR DRIVER");
//MODULE_LICENCE("GPL");
module_init(chardev_init);
module_exit(chardev_exit);
Make file for the same.
obj-m := megharajchard.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
load script
#!/bin/sh
sudo insmod megharajchard.ko
sudo mknod /dev/megharajchard c 251 0
sudo chmod 777 /dev/megharajchard
unload script
#!/bin/sh
sudo rmmod megharajchard
sudo rm /dev/megharajchard
A C application to test the functionalities of the driver.
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<malloc.h>
#define DEVICE "/dev/megharajchard"
//#define DEVICE "megharaj.txt"
int debug = 1, fd = 0;
int write_device() {
int write_length = 0;
ssize_t ret;
char *data = (char *)malloc(1024 * sizeof(char));
printf("please enter the data to write into device\n");
scanf(" %[^\n]",data); /* a space added after"so that it reads white space, %[^\n] is addeed so that it takes input until new line*/
write_length = strlen(data);
if(debug)printf("the length of dat written = %d\n",write_length);
ret = write(fd, data, write_length);
if(ret == -1)
printf("writting failed\n");
else
printf("writting success\n");
if(debug)fflush(stdout);/*not to miss any log*/
free(data);
return 0;
}
int read_device() {
int read_length = 0;
ssize_t ret;
char *data = (char *)malloc(1024 * sizeof(char));
printf("enter the length of the buffer to read\n");
scanf("%d",&read_length);
if(debug)printf("the read length selected is %d\n",read_length);
memset(data,0,sizeof(data));
data[0] = '0\';
ret = read(fd,data,read_length);
printf("DEVICE_READ : %s\n",data);
if(ret == -1)
printf("reading failed\n");
else
printf("reading success\n");
if(debug)fflush(stdout);/*not to miss any log*/
free(data);
return 0;
}
int lseek_device() {
int lseek_offset = 0,seek_value = 0;
int counter = 0; /* to check if function called multiple times or loop*/
counter++;
printf("counter value = %d\n",counter);
printf("enter the seek offset\n");
scanf("%d",&lseek_offset);
if(debug) printf("seek_offset selected is %d\n",lseek_offset);
printf("1 for SEEK_SET, 2 for SEEK_CUR and 3 for SEEK_END\n");
scanf("%d", &seek_value);
printf("seek value = %d\n", seek_value);
switch(seek_value) {
case 1: lseek(fd,lseek_offset,SEEK_SET);
return 0;
break;
case 2: lseek(fd,lseek_offset,SEEK_CUR);
return 0;
break;
case 3: lseek(fd,lseek_offset,SEEK_END);
return 0;
break;
default : printf("unknown option selected, please enter right one\n");
break;
}
/*if(seek_value == 1) {
printf("seek value = %d\n", seek_value);
lseek(fd,lseek_offset,SEEK_SET);
return 0;
}
if(seek_value == 2) {
lseek(fd,lseek_offset,SEEK_CUR);
return 0;
}
if(seek_value == 3) {
lseek(fd,lseek_offset,SEEK_END);
return 0;
}*/
if(debug)fflush(stdout);/*not to miss any log*/
return 0;
}
int lseek_write() {
lseek_device();
write_device();
return 0;
}
int lseek_read() {
lseek_device();
read_device();
return 0;
}
int main()
{
int value = 0;
if(access(DEVICE, F_OK) == -1) {
printf("module %s not loaded\n",DEVICE);
return 0;
}
else
printf("module %s loaded, will be used\n",DEVICE);
while(1) {
printf("\t\tplease enter 1 to write\n \
2 to read\n \
3 to lseek and write\
4 to lseek and read\n");
scanf("%d",&value);
switch(value) {
case 1 :printf("write option selected\n");
fd = open(DEVICE, O_RDWR);
write_device();
close(fd); /*closing the device*/
break;
case 2 :printf("read option selected\n");
/* dont know why but i am suppoesed to open it for writing and close it, i cant keep open and read.
its not working, need to sort out why is that so */
fd = open(DEVICE, O_RDWR);
read_device();
close(fd); /*closing the device*/
break;
case 3 :printf("lseek option selected\n");
fd = open(DEVICE, O_RDWR);
lseek_write();
close(fd); /*closing the device*/
break;
case 4 :printf("lseek option selected\n");
fd = open(DEVICE, O_RDWR);
lseek_read();
close(fd); /*closing the device*/
break;
default : printf("unknown option selected, please enter right one\n");
break;
}
}
return 0;
}
This is because you have to build the modules in a separate process:
make modules
Also, you can install them with:
make modules_install
If this is not for your own system, but for another one, like an embedded one, you should "install" them in a specific directory which you will then copy on the target, using INSTALL_MOD_PATH:
make INSTALL_MOD_PATH=/tmp/modules_for_target modules_install