The prototype of request_irq is:
int request_irq ( unsigned int irq,
irq_handler_t handler,
unsigned long irqflags,
const char * devname,
void * dev_id);
I've noticed a similar question "Simple interrupt handler: request_irq returns error code -22", but I didn't use IRQF_SHARED flag, so there is no reason that it might conflict with dev_id being NULL. But it still fail to register test irq and the errno is always -22(-EINVAL).
Here is my simple irq test module:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/interrupt.h>
static irqreturn_t irq_handle(int irq, void *dev_id)
{
printk("irq happened\n");
return IRQ_HANDLED;
}
static int irq_test_init(void)
{
int rc = request_irq(50, irq_handle, IRQF_DISABLED, "irq_test", NULL);
if(rc!=0){
printk(KERN_INFO "fail to register test irq, errno:%d\n",rc);
return -1;
}
printk(KERN_INFO "success request irq\n");
return 0;
}
static void irq_test_exit(void)
{
free_irq(50, NULL);
printk(KERN_INFO "irq module removed!\n");
return;
}
module_init(irq_test_init);
module_exit(irq_test_exit);
MODULE_LICENSE("GPL");
Related
I am learning tracepoint related knowledge of Linux, and I wrote a module, as shown below.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/tracepoint.h>
#define MAXNUM 600
MODULE_LICENSE("GPL");
static int monitored_pid = 0;
module_param(monitored_pid, int, 0);
MODULE_PARM_DESC(monitored_pid, "The pid of the monitored process.");
void lookup_tps(struct tracepoint *tp, void *priv);
void sys_enter_probe(struct pt_regs *regs, long id);
static struct tracepoint * sys_enter_tp = NULL;
static unsigned monitored_syscalls[MAXNUM];
static int count = 0;
int __init start(void){
int i = 0;
// find sys_enter tracepoint
for_each_kernel_tracepoint(lookup_tps, NULL);
if(sys_enter_tp == NULL){
printk(KERN_INFO "cannot find sys_enter tracepoint.\n");
// let module loading fail
return -1;
}
if(tracepoint_probe_register(sys_enter_tp, sys_enter_probe, NULL) != 0){
printk(KERN_INFO "regist fail.\n");
return -1;
}
for(i=0; i<MAXNUM; i++){
monitored_syscalls[i] = 0;
}
monitored_syscalls[__NR_open] = 1; // I want to monitor open operation
monitored_syscalls[__NR_openat] = 1;
printk(KERN_INFO "Start to monitor process of pid : %d\n", monitored_pid);
return 0;
}
void __exit end(void){
tracepoint_probe_unregister(sys_enter_tp, sys_enter_probe, NULL);
printk(KERN_INFO "End to monitor process of pid : %d\n", monitored_pid);
printk(KERN_INFO "open count : %d\n", count);
}
void lookup_tps(struct tracepoint *tp, void *priv){
if(strcmp(tp->name, "sys_enter") == 0){
sys_enter_tp = tp;
}
}
void sys_enter_probe(struct pt_regs *regs, long id){
if(id>=MAXNUM){
return;
}
if(monitored_syscalls[id] == 0){
return;
}
if(current->pid != monitored_pid){
return;
}
printk(KERN_INFO "1234\n");
count++;
}
module_init(start);
module_exit(end);
When I entered the insmod command on the command line and pressed Enter, the system did not respond. After many experiments, I found that this problem occurs when writing count or using printk in the probe function(sys_enter_probe). I don't know much about the various mechanisms in the kernel, and I hope someone can tell me what rules my code violates and where I can learn these rules.
I am trying to develop a kernel module which has to execute a thread.
I am facing an error while compiling the module.
This is the module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kthread.h> // for threads
static struct task_struct *thread1;
int thread_fn(void) {
while(1) {
printk("Thread_fuction is running ...\n");
msleep(2000);
}
return 0;
}
int thread_init(void) {
char our_thread[8]="thread1";
printk(KERN_INFO "in init");
thread1 = kthread_create(thread_fn,NULL,our_thread);
if((thread1)) {
printk(KERN_INFO "in if");
wake_up_process(thread1);
}
return 0;
}
void thread_cleanup(void) {
int ret;
ret = kthread_stop(thread1);
if(!ret)
printk(KERN_INFO "Thread stopped");
}
MODULE_LICENSE("GPL");
module_init(thread_init);
module_exit(thread_cleanup);
And this is the error :
thread.c:25:26: error: passing argument 1 of ‘kthread_create_on_node’
from incompatible pointer type [-Werror=incompatible-pointer-types]
thread1 = kthread_create(thread_fn,NULL,our_thread);
Could anyone help me to solve the problem?
In kernel source code you can see that kthread_create_on_node() function has first argument type: int (*threadfn)(void *data). But your "threadfn" int thread_fn (void) roughly speaking is of type int (*threadfn)(void).
So change (void) to (void *data).
Kernel module code:
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static void work_func(struct work_struct *work)
{
int i = 0;
while (i < 5) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
cancel_work_sync(&work);
destroy_workqueue(queue);
}
If I do:
insmod mymod.ko
rmmod mymod
rmmod hangs on cancel_work_sync, which first waits for the work to finish, until the counting is over.
Is it possible to immediately cancel that work item?
Minimal runnable example here.
Tested in Linux kernel 4.9.
There is another way to stop kthread with signals. This approach is better than yours because it doesn't require your thread to wake up regularly and poll the stop variable with kthread_should_stop(). No wasting CPU time, it allows your thread to sleep as long as it neeeded.
static int kthread_handle(void *param)
{
allow_signal(SIGINT);
allow_signal(SIGKILL);
for (;;)
{
// ...
// Some blocking functions such as kernel_read()/kernel_write()
// ...
if (signal_pending(current))
{
goto end;
}
// ...
// Some interruptible functions
// ...
if (mutex_lock_interruptible(...) == -EINTR)
{
goto end;
}
}
end:
while (!kthread_should_stop())
{
schedule();
}
return 0;
}
static int __init drv_init(void)
{
// Create and start kernel thread
kthread = kthread_run(kthread_handle, NULL, "kthread");
return 0;
}
static void __exit drv_exit(void)
{
send_sig(SIGKILL, kthread, 1);
kthread_stop(kthread);
}
module_init(drv_init);
module_exit(drv_exit);
I don't know how to send signals to work queues, so the solution is only for kthreads by now.
Atomic control variable
I could not find a way to stop work in a workqueue, but using a simple control variable is a possible solution.
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static atomic_t run = ATOMIC_INIT(1);
static void work_func(struct work_struct *work)
{
int i = 0;
while (atomic_read(&run)) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
atomic_set(&run, 0);
destroy_workqueue(queue);
}
kthread kthread_stop
Work queues are based on kthreads, and a work queue is basically useless in that example, so we could use the kthreads directly.
kthread_stop waits for the thread to return.
See also:
Proper way of handling threads in kernel?
How to wait for a linux kernel thread (kthread)to exit?
Signal handling in kthreads seems to have been a polemic subject, and is now not possible: https://unix.stackexchange.com/questions/355280/how-signals-are-handled-in-kernel
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static struct task_struct *kthread;
static int work_func(void *data)
{
int i = 0;
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
return 0;
}
int init_module(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
void cleanup_module(void)
{
kthread_stop(kthread);
}
Timer
Run in interrupt context directly, so more accurate, but more restricted.
See also: How to use timers in Linux kernel device drivers?
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
static void callback(unsigned long data);
static unsigned long onesec;
DEFINE_TIMER(mytimer, callback, 0, 0);
static void callback(unsigned long data)
{
pr_info("%u\n", (unsigned)jiffies);
mod_timer(&mytimer, jiffies + onesec);
}
int init_module(void)
{
onesec = msecs_to_jiffies(1000);
mod_timer(&mytimer, jiffies + onesec);
return 0;
}
void cleanup_module(void)
{
del_timer(&mytimer);
}
I am doubtful whether UMH_NO_WAIT option in call_usermodehelper() is working, or I am missing something.
This is with reference to the following thread,
Kernel module periodically calling user space program
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/jiffies.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>
#include <linux/delay.h>
#define TIME_PERIOD 5000000000
static struct hrtimer hr_timer;
static ktime_t ktime_period_ns;
static enum hrtimer_restart timer_callback(struct hrtimer *timer){
char userprog[] = "test.sh";
char *argv[] = {userprog, "2", NULL };
char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
printk("\n Timer is running");
hrtimer_forward_now(&hr_timer, ktime_period_ns);
printk("callmodule: %s\n", userprog);
call_usermodehelper(userprog, argv, envp, UMH_NO_WAIT);
return HRTIMER_RESTART;
}
static int __init timer_init() {
ktime_period_ns= ktime_set( 0, TIME_PERIOD);
hrtimer_init ( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = timer_callback;
hrtimer_start( &hr_timer, ktime_period_ns, HRTIMER_MODE_REL );
return 0;
}
static int __exit timer_exit(){
int cancelled = hrtimer_cancel(&hr_timer);
if (cancelled)
printk(KERN_ERR "Timer is still running\n");
else
printk(KERN_ERR "Timer is cancelled\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
I think because of the call_usermodehelper() call, the system hangs.Because, at the time of call_usermodehelper() function call only the system freezes. So, I have tried with the option UMH_NO_WAIT, so that the kernel code will not wait for the user process to execute.Then also the system hangs.kindly check www.kernel.org/doc/htmldocs/kernel-api/API-call-usermodehelper.html
I'm newbies with the module linux.
I try to create a counter module where the counter is increment on timer callback.
The result of the counter must be send to an other module (a memory module).
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/uaccess.h>
MODULE_AUTHOR("Helene");
MODULE_DESCRIPTION("Module memory");
MODULE_SUPPORTED_DEVICE("none");
MODULE_LICENSE("Dual BSD/GPL");
/* Global variables of the driver */
/* Buffer to store data */
char *memory_buffer;
int result;
struct file_operations memory_fops;
int memory_open(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Opening memory module\n");
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Releasing of memory module\n");
return 0;
}
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){
// printk(KERN_DEBUG "Reading memory module : %s\n", buf);
if (*f_pos > 0)
return 0;
if (count > strlen(memory_buffer))
count = strlen(memory_buffer);
copy_to_user(buf,memory_buffer,count);
*f_pos = *f_pos + count;
return count;
}
ssize_t memory_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos) {
// printk(KERN_DEBUG "Writing memory module : %s\n", buf);
copy_from_user(memory_buffer, buf, count);
return count;
}
static int __init memory_init(void) {
/* Registering device */
result = register_chrdev(0, "memory", &memory_fops);
if (result < 0) {
printk(KERN_DEBUG "memory: cannot obtain major number \n");
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk(KERN_ALERT "Inserting memory module : %d\n", result);
return 0;
fail:
//memory_exit();
return result;
}
static void __exit memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(result, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk(KERN_DEBUG "Removing memory module\n");
}
struct file_operations memory_fops = {
owner: THIS_MODULE,
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
module_init(memory_init);
module_exit(memory_exit);
The memory module works. My problem is when I call the function : filp_open/fp->f_op->write/filp_close on the function timer callback.
I have test these functions out of the timer callback and it's work.
Why the filp_open function (& co) don't work on timer callback function ?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("GPL");
static struct timer_list my_timer;
int cptNbClic ;
int result;
struct file_operations timer_fops;
int write_file_system(struct file *fp, char * buf){
int nb;
mm_segment_t old_fs=get_fs();
set_fs(get_ds());
nb = fp->f_op->write(fp,buf ,10, &fp->f_pos);
set_fs(old_fs);
return nb;
}
void writeInMemory(void){
// printk(KERN_DEBUG "busy %d\n", busy);
int nbwrite;
char buf[3];
int fmemory;
fmemory=filp_open ("/dev/memory", O_WRONLY | O_APPEND | O_CREAT,0); //don't work on this function
if (fmemory==NULL){//verification de l'ouverture
printk(KERN_ALERT "filp_open error input memory!!.\n");
return -1;
}
sprintf(buf, "%d", cptNbClic);
printk(KERN_DEBUG "%d\n", cptNbClic);
nbwrite = write_file_system(fmemory, buf);
filp_close(fmemory, 0);
}
void my_timer_callback( unsigned long data )
{
cptNbClic++;
printk(KERN_DEBUG "cptNbClic %d\n", cptNbClic);
writeInMemory();
setup_timer(&my_timer, my_timer_callback, 0);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
}
static int timer_open(struct inode *inode, struct file *filp) {
/* setup your timer to call my_timer_callback */
cptNbClic = 0;
setup_timer(&my_timer, my_timer_callback, 0);
/* setup timer interval to 200 msecs */
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
return 0;
}
static int timer_release(struct inode *inode, struct file *filp) {
/* Success */
printk(KERN_DEBUG "Releasing of cpt module\n");
del_timer(&my_timer);
return 0;
}
static int __init timer_init(void) {
/* Registering device */
result = register_chrdev(0, "timer", &timer_fops);
if (result < 0) {
printk(KERN_DEBUG "timer: cannot obtain major number \n");
return result;
}
printk(KERN_ALERT "Inserting timer module : %d\n", result);
return 0;
}
static void __exit timer_exit(void) {
unregister_chrdev(result, "timer");
printk(KERN_DEBUG "Removing timer module\n");
}
struct file_operations timer_fops = {
owner: THIS_MODULE,
open: timer_open,
release: timer_release
};
/* Declaration of the init and exit functions */
module_init(timer_init);
module_exit(timer_exit);
Sorry for my bad english
No need to call setup_timer function in your my_timer_callback().Already timer is setup. If you want a recurring timer then just again call mod_timer() in your handler which will updates your timer expire value and your timer happily runs again and again till del_timer() call.