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.
Related
I am a total beginner in kernel module programming. I wanted to create a module which reads input from the proc filesystem. With this you should be able to perform operations in the program. I did that with threading. However my machine crashes after inserting the module. Probably I did something wrong. Here is the source code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/string.h>
#define PROCFS_MAX_SIZE 1024
#define PROCFS_NAME "test"
MODULE_LICENSE("GPL");
int pid = 1;
static struct proc_dir_entry *Our_Proc_File;
static char procfs_buffer[PROCFS_MAX_SIZE];
static unsigned long procfs_buffer_size = 0;
struct task_struct *task;
static ssize_t procfile_read(struct file *file, char *buffer, size_t buffer_length, loff_t *offset) {
static int flag = 0;
if(flag) {
printk(KERN_INFO "read : END\n");
flag = 0;
return 0;
}
printk(KERN_INFO "read (/proc/%s) : called\n",PROCFS_NAME);
flag = 1;
return snprintf(buffer, buffer_lengh, procfs_buffer);
}
static ssize_t procfile_write(struct file *file,const char *buffer, size_t count, loff_t *offset) {
procfs_buffer_size = count;
if (copy_from_user(procfs_buffer, buffer, procfs_buffer_size)) {
return -EFAULT;
}
return procfs_buffer_size;
}
static int main_prog(void *data) {
int end = 0;
while(!end) {
while(memcmp(procfs_buffer,"\x00",1)==0);
if(memcmp(procfs_buffer,"test",4)) {
printk(KERN_INFO "Test triggered!\n");
}
if(memcmp(procfs_buffer,"exit",4)) {
end++;
}
memset(procfs_buffer, 0, 1024);
}
kthread_stop(task);
}
static struct file_operations fops_struct = {
.read = procfile_read,
.write = procfile_write,
};
int init_module() {
Our_Proc_File = proc_create(PROCFS_NAME, 0666, NULL, &fops_struct);
if (Our_Proc_File == NULL) {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME);
return -ENOMEM;
}
task = kthread_run(&main_prog, NULL, "thread");
wake_up_process(task);
printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);
return 0;
}
void cleanup_module() {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
}
Can someone help me?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have a Linux Kernel Module that checks for the presence of a specific USB device and performs a printk upon a match. This code works fine and performs as i expect.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/list.h>
#include <linux/slab.h>
MODULE_LICENSE("GPL");
static int HARD_VEND;
static int HARD_PROD;
static char *HARD_SERI;
struct USBCred
{
int vendor;
int product;
char serial[128];
};
static struct USBCred create_creds_device(struct usb_device *dev)
{
struct USBCred creds;
creds.vendor = dev->descriptor.idVendor;
creds.product = dev->descriptor.idProduct;
if((dev->serial) == NULL)
{
strcpy(creds.serial, "(null)");
} else {
strcpy(creds.serial, dev->serial);
}
return creds;
}
static struct USBCred create_creds_hub(struct usb_bus *bus)
{
struct USBCred creds;
creds.vendor = bus->root_hub->descriptor.idVendor;
creds.product = bus->root_hub->descriptor.idProduct;
if((bus->root_hub->serial) == NULL)
{
strcpy(creds.serial, "(null)");
} else {
strcpy(creds.serial, bus->root_hub->serial);
}
return creds;
}
static int check_usb_creds(struct USBCred usb_data)
{
if(usb_data.vendor != HARD_VEND && usb_data.product != HARD_PROD && strcmp(usb_data.serial, HARD_SERI))
{
return 1;
} else
{
printk(KERN_INFO "*********** RootPug Module - Match ***********");
printk(KERN_INFO "Vendor ID = %x, HC Vendor ID = %x", usb_data.vendor, HARD_VEND);
printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
return 0;
}
}
static int __init usb_fun_init (void)
{
int id;
int chix;
struct USBCred cred;
struct usb_bus *bus;
struct usb_device *dev, *childdev = NULL;
HARD_VEND = 0x26bd;
HARD_PROD = 0x9917;
HARD_SERI = "070172966462EB10";
mutex_lock(&usb_bus_idr_lock);
idr_for_each_entry(&usb_bus_idr, bus, id)
{
cred = create_creds_hub(bus);
//print_USBCred(cred);
check_usb_creds(cred);
dev = bus->root_hub;
usb_hub_for_each_child(dev, chix, childdev)
{
if(childdev)
{
usb_lock_device(childdev);
cred = create_creds_device(childdev);
//print_USBCred(cred);
check_usb_creds(cred);
usb_unlock_device(childdev);
}
}
}
mutex_unlock(&usb_bus_idr_lock);
return 0;
}
static void __exit usb_fun_exit (void)
{
printk(KERN_INFO "***************** RootPug Module - Exit *****************\n");
}
module_init(usb_fun_init);
module_exit(usb_fun_exit);
When moving over to an LSM, the LSM registers without an issue, and the hook registers correctly, yet the code is not behaving as I would like, and I can not understand why. I have added debugging statements to understand at which points the code is getting to, but it seems the idr_for_each_entry() is not being executed, as the debug statment ithin that loop is not being printed. I have used a flag based system to provide a mechanism for having -EPERM as the default return value, being overwritten if the usb is found.
I cannot understand why only the mutex is being performed, with no check to the hubs or usb devices, yet the same code works as an LKM. The actual code that is in question is within the appcl_inode_create hook. I have left out the other hooks for brevity, but they currently do nothing except return the expected value of 0.
#include <linux/init.h>
#include <linux/kd.h>
#include <linux/kernel.h>
#include <linux/tracehook.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/lsm_hooks.h>
#include <linux/xattr.h>
#include <linux/security.h>
#include <linux/capability.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <linux/magic.h>
#include <linux/ctype.h>
#include <linux/swap.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/dcache.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/parser.h>
#include <linux/nfs_mount.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/posix-timers.h>
#include <linux/syslog.h>
#include <linux/user_namespace.h>
#include <linux/export.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/cred.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/fsnotify.h>
#include <linux/path.h>
#include <linux/fdtable.h>
#include <linux/binfmts.h>
#include <linux/time.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "include/appcl_lsm.h"
//#include "include/audit.h"
MODULE_LICENSE("GPLv3");
MODULE_AUTHOR("Jack Cuthbertson");
static int HARD_VEND;
static int HARD_PROD;
static char *HARD_SERI;
struct USBCred
{
int vendor;
int product;
char serial[128];
};
static struct USBCred create_creds_device(struct usb_device *dev)
{
struct USBCred creds;
creds.vendor = dev->descriptor.idVendor;
creds.product = dev->descriptor.idProduct;
if((dev->serial) == NULL)
{
strcpy(creds.serial, "(null)");
} else {
strcpy(creds.serial, dev->serial);
}
return creds;
}
static struct USBCred create_creds_hub(struct usb_bus *bus)
{
struct USBCred creds;
creds.vendor = bus->root_hub->descriptor.idVendor;
creds.product = bus->root_hub->descriptor.idProduct;
if((bus->root_hub->serial) == NULL)
{
strcpy(creds.serial, "(null)");
} else {
strcpy(creds.serial, bus->root_hub->serial);
}
return creds;
}
static int check_usb_creds(struct USBCred usb_data)
{
if(usb_data.vendor != HARD_VEND && usb_data.product != HARD_PROD && strcmp(usb_data.serial, HARD_SERI))
{
printk(KERN_INFO "*********** RootPlug Module - Non Match ***********");
printk(KERN_INFO "Vendor ID = %x, HC Vendor ID = %x", usb_data.vendor, HARD_VEND);
printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
return 1;
} else
{
printk(KERN_INFO "*********** RootPlug Module - Match ***********");
printk(KERN_INFO "Vendor ID = %x, HC Vendor ID = %x", usb_data.vendor, HARD_VEND);
printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
return 0;
}
}
static int appcl_lsm_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int id;
int chix;
int flag = -EPERM;
struct USBCred cred;
struct usb_bus *bus;
struct usb_device *dev, *childdev = NULL;
HARD_VEND = 0x26bd;
HARD_PROD = 0x9917;
HARD_SERI = "070172966462EB10";
printk(KERN_ALERT "Rootplug: Beginning check\n");
mutex_lock(&usb_bus_idr_lock);
printk(KERN_ALERT "Rootplug: Mutex locked the bus list\n");
//loop though all usb buses
idr_for_each_entry(&usb_bus_idr, bus, id)
{
printk(KERN_ALERT "Rootplug: Checking hubs.\n");
cred = create_creds_hub(bus);
//Check creds of usb buses
if(check_usb_creds(cred) == 0)
{
mutex_unlock(&usb_bus_idr_lock);
printk(KERN_ALERT "Rootplug: Unlock hub success!\n");
flag = 0;
} else {
printk(KERN_ALERT "Rootplug: Unlock hub fail!\n");
}
dev = bus->root_hub;
usb_hub_for_each_child(dev, chix, childdev)
{
if(childdev)
{
printk(KERN_ALERT "Rootplug: Checking USB devices\n");
usb_lock_device(childdev);
cred = create_creds_device(childdev);
if(check_usb_creds(cred) == 0)
{
usb_unlock_device(childdev);
mutex_unlock(&usb_bus_idr_lock);
printk(KERN_ALERT "Rootplug: Unlock USB success!\n");
} else {
usb_unlock_device(childdev);
printk(KERN_ALERT "Rootplug: Unlock USB Failure!\n");
}
} else {
printk(KERN_ALERT "Rootplug: No child dev\n");
}
}
}
mutex_unlock(&usb_bus_idr_lock);
printk(KERN_ALERT "Rootplug: Unlock failed - Flag: %i\n", flag);
return flag;
}
static struct security_hook_list appcl_hooks[] = {
/*
* XATTR HOOKS
*/
LSM_HOOK_INIT(inode_setxattr, appcl_lsm_inode_setxattr),
LSM_HOOK_INIT(inode_post_setxattr, appcl_lsm_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, appcl_lsm_inode_getxattr),
LSM_HOOK_INIT(inode_removexattr, appcl_lsm_inode_removexattr),
LSM_HOOK_INIT(d_instantiate, appcl_lsm_d_instantiate),
LSM_HOOK_INIT(inode_setsecurity, appcl_lsm_inode_setsecurity),
LSM_HOOK_INIT(inode_init_security, appcl_lsm_inode_init_security),
/*
* INODE HOOKS
*/
LSM_HOOK_INIT(inode_alloc_security, appcl_lsm_inode_alloc_security),
LSM_HOOK_INIT(inode_free_security, appcl_lsm_inode_free_security),
/*
* General permission mask
*/
LSM_HOOK_INIT(inode_permission, appcl_lsm_inode_permission),
/*
* Specific permission hooks
*/
LSM_HOOK_INIT(inode_create, appcl_lsm_inode_create),
LSM_HOOK_INIT(inode_rename, appcl_lsm_inode_rename),
LSM_HOOK_INIT(inode_link, appcl_lsm_inode_link),
LSM_HOOK_INIT(inode_unlink, appcl_lsm_inode_unlink),
LSM_HOOK_INIT(inode_symlink, appcl_lsm_inode_symlink),
LSM_HOOK_INIT(inode_mkdir, appcl_lsm_inode_mkdir),
LSM_HOOK_INIT(inode_rmdir, appcl_lsm_inode_rmdir),
LSM_HOOK_INIT(inode_mknod, appcl_lsm_inode_mknod),
LSM_HOOK_INIT(inode_readlink, appcl_lsm_inode_readlink),
LSM_HOOK_INIT(inode_follow_link, appcl_lsm_inode_follow_link),
//LSM_HOOK_INIT(inode_setattr, appcl_lsm_inode_setattr),
//LSM_HOOK_INIT(inode_getattr, appcl_lsm_inode_getattr),
/*
* FILE HOOKS
*/
LSM_HOOK_INIT(file_alloc_security, appcl_lsm_file_alloc_security),
LSM_HOOK_INIT(file_free_security, appcl_lsm_file_free_security),
LSM_HOOK_INIT(file_permission, appcl_lsm_file_permission),
//LSM_HOOK_INIT(file_fcntl, appcl_lsm_file_fcntl),
LSM_HOOK_INIT(file_open, appcl_lsm_file_open),
LSM_HOOK_INIT(file_receive, appcl_lsm_file_receive),
/*
* CRED HOOKS
*/
LSM_HOOK_INIT(cred_alloc_blank, appcl_lsm_cred_alloc_blank),
LSM_HOOK_INIT(cred_free, appcl_lsm_cred_free),
LSM_HOOK_INIT(cred_prepare, appcl_lsm_cred_prepare),
LSM_HOOK_INIT(cred_transfer, appcl_lsm_cred_transfer),
LSM_HOOK_INIT(bprm_set_creds, appcl_lsm_bprm_set_creds),
/*
* SUPERBLOCK HOOKS
*/
LSM_HOOK_INIT(sb_alloc_security, appcl_lsm_sb_alloc_security),
LSM_HOOK_INIT(sb_free_security, appcl_lsm_sb_free_security),
};
static __init int appcl_init(void)
{
printk(KERN_ALERT "Rootplug: Module loading... \n");
/*
* Set security attributes for initial task
*/
security_add_hooks(appcl_hooks, ARRAY_SIZE(appcl_hooks), "appcl");
printk(KERN_ALERT "Rootplug: module initialised\n");
return 0;
}
DEFINE_LSM(appcl) = {
.name = "appcl",
.init = appcl_init,
};
The function that handled the matching used a different alert level for the printk function. As such, the messages were not displayed to the console at that stage in the boot process.
What was:
printk(KERN_INFO "message");
Should be:
printk(KERN_ALERT "message");
The matching function was being called, after recompiling the kernel with the hooks forced to return 0, i could see from /var/log/* that the function was being executed and outputting the correct information.
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 wrote this linux char driver just to control open call,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem;
static int myopen(struct inode *inod, struct file *fp)
{
down(sem);
printk(KERN_INFO "critical section\n");
return 0;
}
static int myclose(struct inode *inod, struct file *fp )
{
up(sem);
printk(KERN_INFO "critical section freed\n");
return 0;
}
static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
.write = mywrite,
};
static int __init myinit(void)
{
int ret;
ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
if(ret<0)
{
printk(KERN_INFO "chardev can't be allocated\n");
// goto label;//todo
}
mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
if(mycdev == NULL)
{
printk(KERN_INFO"cdev_alloc failed\n");
// goto label;//todo
}
mycdev->ops = &fops;
ret = cdev_add(mycdev, mycdevt, 1);
if(ret < 0)
{
printk(KERN_INFO"cdev_add failed\n");
// goto label;//todo
}
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(myclass == NULL)
{
printk(KERN_INFO"class create failed\n");
// goto label;//todo
}
mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
if(mydevice == NULL)
{
printk(KERN_INFO"device create failed\n");
// goto label;//todo
}
sema_init(sem, 1);//here is the problem
printk(KERN_INFO"myinit done\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(myclass, mycdevt);
class_unregister(myclass);
class_destroy(myclass);
cdev_del(mycdev);
unregister_chrdev(MAJOR(mycdevt), "mycdevt");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
I am following ldd3 book, and tried to use simple APIs to use semahore for an app.
What happened is my kernel crashed when it called sema_init function. I read that semaphore is used in mutex mode
http://www.makelinux.net/ldd3/chp-5-sect-3
I also read that semaphore is not a mutex as there is no ownership. I have yet to explore that 'ownership' thing, but for now I am not able to make a simple semaphore.
What wrong I am doing here?
There's no actual semaphore.
This line:
static struct semaphore *sem;
creates a pointer to a semaphore, not a semaphore itself. It's almost certain initialized to NULL.
You probably want something like
static struct semaphore sem;
and therefore
sema_init( &sem, 1);
along with
up( &sem );
and
down( &sem );
Note that these calls are taking the address of an actual semaphore.
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.