The problem was really simple. I had initialized the timer values but not the timer itself. Initialization of the timer is done with the function:
init_timer(struct timer_list *timer);
In this chase
init_timer(&my_timer);
Question
I'm making a module which counts with three parts. I'm working in Debian 6.
The first one is a timer that is triggered every 125 ticks. Its function is picking the system jiffies, masking them and including them into a circular buffer with 10 spaces. When the 80% of that space is busy, a work item will be added into a workqueue that will take the numbers into a list. That list will get its elements removed when any user reads the /proc/modtimer entry.
The issue I have is this: I can install the module without problem, the /proc entries (I will need 2 but now I have only one implemented) are created without a problem, but when I try to read the kernel crashes. When I read the control messages, I think that the problem is in the release procedure. I do not know what the problem or problems are. Here is my code
EDIT: After several tests, my program crashes with the line :"del_timer_sync(&my_timer);"
EDIT2: I have deleted everything except the Install/Uninstall/Open/close/read functions because anything else is irrelevant
EDIT3: It could be also "add_timer(&my_timer);"
#define PROC_ENTRY "modtimer"
#define PROC_ENTRY_OPS "modconfig"
#define CBUFFER_SIZE 10
#define TRESHOLD_SIZE 80 // percentage of the treshold for the workqueue calling
#define DELAY 125 //125 tics for timer (1 each half a sec)
#define MAX_BUFFER 512
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/semaphore.h>
#include <linux/vmalloc.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm-generic/uaccess.h>
#include "cbuffer.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Pseudo-Random number generator for DSO");
MODULE_AUTHOR("Kaostias");
/**********************************************************/
/********************** Declarations **********************/
/**********************************************************/
/*Timer*/
struct timer_list my_timer;
/*Workqueue*/
struct work_struct my_workqueue;
/* The workqueue has been planified but not resolved */
int workqueue_pendiente;
/* /proc entries */
static struct proc_dir_entry *proc_entry, *proc_entry_opts;
/*Semaphore used as spin_lock */
struct semaphore mtx;
int openDevices;
/*Spinlock*/
DEFINE_SPINLOCK(spinlock);
/*List*/
struct list_head mylist = LIST_HEAD_INIT(mylist);
typedef struct {
int data;
struct list_head links;
}list_item_t;
/*Buffer of integer numbers*/
cbuffer_t *cbuf;
/*Functions*/
void vacia_list_item(void);
void add_list(int num);
void fire_timer(unsigned long data);
void copy_items_into_list(struct work_struct *work);
static int modtimer_open (struct inode *, struct file *);
static int modtimer_release (struct inode*, struct file *);
static ssize_t modtimer_read (struct file *file, char __user*, size_t nbits, loff_t * offset);
/*Se escribe la entrada PROC_ENTRY_OPS*/
int procOpsWrite( struct file *punterofichero, const char __user *bufferusuario,
unsigned long longitud, void *data);
int procOpsRead( char *buffer, char **bufferlocation, off_t offset,
int buffer_lenghth, int *eof, void *data );
/*Operaciones de proc PROC_ENTRY*/
static const struct file_operations my_fops = {
.open = modtimer_open,
.read = modtimer_read,
.release = modtimer_release,
};
/**********************************************************/
/****** Install/Uninstall/Open/close/read functions *******/
/**********************************************************/
/*module install*/
int install_module(void){
int ret = 0;
printk(KERN_INFO "installing module");
/*Timer inicialization*/
my_timer.expires = jiffies + DELAY;
my_timer.data = 0;
my_timer.function = fire_timer;
printk(KERN_INFO "Timer created but not used");
/*workqueue inicialization*/
workqueue_pendiente = 0;
INIT_WORK(&my_workqueue, copy_items_into_list);
printk(KERN_INFO "creada workqueue");
/* Semaphore inicialization */
sema_init(&mtx,1);
openDevices = 0;
printk(KERN_INFO "Semapore created");
/*Spin_lock inicialization*/
spin_lock_init(&spinlock);
printk(KERN_INFO "spinlock created");
/*buffer inicialization*/
cbuf = create_cbuffer_t (CBUFFER_SIZE);
printk(KERN_INFO "buffer created");
/*list Inicialization*/
printk(KERN_INFO "list created");
/* /proc entries */
proc_entry = create_proc_entry(PROC_ENTRY,0777, NULL);
if (proc_entry == NULL) {
ret = -ENOMEM;
printk(KERN_INFO "Error: No puedo crear la entrada en proc /proc/%s\n",PROC_ENTRY);
} else {
proc_entry->proc_fops=&my_fops;
printk(KERN_INFO "Entrada /proc/%s creada.\n", PROC_ENTRY);
}
proc_entry_opts = create_proc_entry(PROC_ENTRY_OPS,0777, NULL);
if (proc_entry_opts == NULL) {
ret = -ENOMEM;
printk(KERN_INFO "Error: No puedo crear la entrada en proc /proc/%s\n",PROC_ENTRY_OPS);
remove_proc_entry(PROC_ENTRY, NULL);
printk(KERN_INFO "Entrada /proc/%s eliminada.\n", PROC_ENTRY);
} else {
proc_entry_opts->read_proc = procOpsRead;
proc_entry_opts->write_proc =procOpsWrite;
printk(KERN_INFO "Entrada /proc/%s creada.\n", PROC_ENTRY_OPS);
}
printk(KERN_INFO "módulo instalado correctamente");
return ret;
}
/*Uninstalling module*/
void uninstall_module(void){
printk(KERN_INFO "Uninstalling module");
/* /proc removal*/
remove_proc_entry(PROC_ENTRY, NULL);
printk(KERN_INFO " /proc/%s entry removed.\n", PROC_ENTRY);
remove_proc_entry(PROC_ENTRY_OPS, NULL);
printk(KERN_INFO " /proc/%s entry removed.\n", PROC_ENTRY_OPS);
/*buffer destruction*/
remove_cbuffer_t (cbuf);
/*list gets empty*/
vacia_list_item();
printk(KERN_INFO "The uninstalling procese has been complete");
}
/* PROC_ENTRY /proc entry is open (Like a file) */
static int modtimer_open (struct inode *inod, struct file *f){
int ret = 0;
printk(KERN_INFO "entering modtimer_open");
// timer is added (Not synchrone yet)
if(openDevices==0){
printk(KERN_INFO "Entra");
my_timer.expires = jiffies + DELAY;
add_timer(&my_timer);
}
openDevices++;
printk(KERN_INFO "saliendo de modtimer_open");
return ret;
}
/* PROC_ENTRY /proc entry is closed*/
static int modtimer_release (struct inode *inod, struct file *f){
int ret = 0;
printk(KERN_INFO "entering modtimer_release");
openDevices--; // In this moment there just will be 1 device open, i will fix this
printk(KERN_INFO "1");
del_timer_sync(&my_timer);
printk(KERN_INFO "2");
flush_scheduled_work();
printk(KERN_INFO "modtimer_release cerrado");
return ret;
}
module_init(install_module);
module_exit(uninstall_module);
Solution
The problem was really simple. I had initialized the timer values but not the timer itself. Initialization of the timer is done with the function:
init_timer(struct timer_list *timer);
In this chase
init_timer(&my_timer);