这是我自己的简单设备驱动程序,它使用工作队列在用户应用程序上生成异步中断。每次在向用户应用程序提供异步通知后调用它时,工作队列会自行重新安排(延迟)。 在询问驱动程序中断并等待之后,用户应用程序进入。要正确处理退出,当使用ctrl + c终止用户应用程序时,调用handle会告诉驱动程序取消预定任务,然后关闭驱动程序并退出。
问题是,如果我重复运行用户应用程序超过3次,系统会冻结,并且syslog条目没有错误。 以下是驱动程序的代码
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/kernel.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/stat.h>
#include"ioctrl.h"
#include<linux/cdev.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include<linux/timer.h>
#include<linux/workqueue.h>
#define DEVICE_NAME "myCharDevice"
#define MODULE_NAME "myCharDriver"
#define CLASS_NAME "myCharClass"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YASH BHATT");
MODULE_VERSION(".01");
static char *bufferMemory;
static int bufferPointer;
static int bufferSize = 15;
static dev_t myChrDevid;
static struct cdev *myChrDevCdev;
static struct class *pmyCharClass;
static struct device *pmyCharDevice;
static wait_queue_head_t waitQueue;
static int exit_now = 0;
static struct delayed_work *MyTask;
static int in_sleep = 0;
static volatile int wake_up = 5;
int majorNumber = 0;
static int charDriverOpen(struct inode *inodep, struct file *filep);
static int charDriverClose(struct inode *inodep, struct file *filep);
static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset);
static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset);
static int charDriverEntry(void);
static void charDriverExit(void);
static long charDriverCtrl(struct file *filep, unsigned int command, unsigned long argument);
static int myfasync(int fd, struct file *fp, int on);
static void send_signal_timerfn(struct work_struct *work);
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
.unlocked_ioctl = charDriverCtrl,
.fasync = myfasync,
};
static struct fasync_struct *fasyncQueue;
static int __init charDriverEntry()
{
int returnValue;
returnValue = alloc_chrdev_region(&myChrDevid, 0, 1, DEVICE_NAME);
majorNumber = MAJOR(myChrDevid);
if (returnValue < 0)
{
printk(KERN_ALERT "ERROR : can not aquire major number! error %d",returnValue);
return -1;
}
printk(KERN_INFO "Aquired Major Number! : %d\n", MAJOR(myChrDevid));
myChrDevCdev = cdev_alloc();
if (IS_ERR(myChrDevCdev))
{
printk(KERN_ALERT "Failed to allocate space for CharDev struct\n");
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
cdev_init(myChrDevCdev,&fops);
myChrDevCdev->owner = THIS_MODULE;
pmyCharClass = class_create(THIS_MODULE,CLASS_NAME);
if (IS_ERR(pmyCharClass))
{
printk(KERN_ALERT "Failed to Register Class\n");
cdev_del(myChrDevCdev);
kfree(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
printk(KERN_INFO "Class created!\n");
pmyCharDevice = device_create(pmyCharClass, NULL, MKDEV(majorNumber,0),NULL,DEVICE_NAME);
if (IS_ERR(pmyCharDevice))
{
printk(KERN_ALERT "Failed to Register Class\n");
class_unregister(pmyCharClass);
class_destroy(pmyCharClass);
cdev_del(myChrDevCdev);
kfree(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
printk(KERN_INFO "Device created!\n");
returnValue = cdev_add(myChrDevCdev, myChrDevid, 1);
if (returnValue < 0)
{
printk(KERN_ALERT "Failed to add chdev \n");
return -1;
}
printk(KERN_INFO "Now We will create the attribute entry in sysfs\n");
init_waitqueue_head(&waitQueue);
MyTask = kmalloc(sizeof(struct delayed_work), GFP_KERNEL);
INIT_DELAYED_WORK(MyTask, send_signal_timerfn);
return 0;
}
static void __exit charDriverExit()
{
device_destroy(pmyCharClass, MKDEV(majorNumber,0));
class_unregister(pmyCharClass);
class_destroy(pmyCharClass);
//unregister_chrdev(majorNumber,DEVICE_NAME);
cdev_del(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
kfree(myChrDevCdev);
printk(KERN_INFO "Unmounting module done !\n");
}
static int charDriverOpen(struct inode *inodep, struct file *filep)
{
if (bufferSize <= 0)
{
bufferSize = 15;
}
printk(KERN_INFO "INFO : CHARATER DRIVER OPENED\n");
bufferMemory = kmalloc(bufferSize,GFP_KERNEL);
bufferPointer = 0;
wake_up = 5;
in_sleep = 0;
//add_timer(&timer);
printk(KERN_INFO "timer setup \n");
return 0;
}
static int charDriverClose(struct inode *inodep, struct file *filep)
{
//del_timer(&timer);
kfree(bufferMemory);
printk(KERN_INFO "INFO : CHARACTER DRIVER CLOSED\n");
return 0;
}
static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset)
{
printk("dummy write\n");
}
static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset)
{
printk("Dummy read");
}
static long charDriverCtrl(struct file *filep, unsigned int command, unsigned long argument)
{
int returnVal;
bufferSizeStruct sizeStruct;
printk(KERN_INFO "INFO: IOCONTROL called\n");
switch(command)
{
case GO_TO_SLEEP:
printk("Going to sleep \n");
in_sleep = 1;
printk("value of wake_up before going to sleep %d\n",wake_up);
//returnVal = wait_event_interruptible(waitQueue, !wake_up);
wait_event(waitQueue, !wake_up);
returnVal = 0xA5A5;
printk("I have woken up returnVal = %d!\n",returnVal);
//del_timer(&timer);
wake_up = 5;
break;
case ADD_TO_QUEUE:
printk("Adding work to queue\n");
schedule_delayed_work(MyTask, 100);
exit_now = 0;
break;
case REMOVE_TASK_FROM_QUEUE:
exit_now = 1;
cancel_delayed_work_sync(MyTask);
printk("Removing task from queue\n");
break;
default:
printk(KERN_WARNING "WARNING: Invalid IOCTRL ARGUMENT!\n");
return -1;
}
printk("outside the switch already \n");
return 0;
}
static int myfasync(int fd, struct file *fp, int on)
{
return fasync_helper(fd, fp, 1, &fasyncQueue);
}
static void send_signal_timerfn(struct work_struct *work)
{
printk(KERN_INFO "timer expired \n");
kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
if (in_sleep == 1)
{
printk(KERN_INFO "in the timer callback with sleep on wake_up : %d\n", wake_up);
wake_up--;
if (!wake_up)
{
printk(KERN_INFO "now going to wake my self up\n");
wake_up(&waitQueue);
}
}
if (!exit_now)
schedule_delayed_work(MyTask, 100);
}
module_init(charDriverEntry);
module_exit(charDriverExit);
module_param(bufferSize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bufferSize, "Buffer Memory Size [15]");
用户申请如下:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include"ioctrl.h"
#include<sys/ioctl.h>
#include<signal.h>
bufferSizeStruct sizeStruct;
int fp;
void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}
void my_signal(int p)
{
ioctl(fp, REMOVE_TASK_FROM_QUEUE );
close(fp);
exit(0);
}
int main()
{
struct sigaction signalInfo;
int flagInfo;
signalInfo.sa_sigaction = my_notifier;
signalInfo.sa_flags = SA_SIGINFO;
sigemptyset(&signalInfo.sa_mask);
sigaction(SIGIO, &signalInfo, NULL);
signal(SIGINT, my_signal);
int i;
char c[5];
fp = open("/dev/myCharDevice",O_RDWR);
if (fp<0)
printf("Failed to open\n");
/*New we will own the device so that we can get the signal from the device*/
fcntl(fp, F_SETOWN, getpid());
flagInfo = fcntl(fp, F_GETFL);
fcntl(fp, F_SETFL, flagInfo|FASYNC);
sleep(5);
printf("Scheduling work queue\n");
ioctl(fp, ADD_TO_QUEUE );
//printf("Sending the drive to sleep for a while \n");
//ioctl(fp, GO_TO_SLEEP);
while(1);
return 0;
}
我想我忘了禁用某些东西而且正在加载内核。 当我与计时器合作时,我遇到了同样的问题,即使我在每个出口都执行了del_timer()。我在这里错过了什么? 谢谢
答案 0 :(得分:0)
看起来像一个内核错误。我在Linux 4.15上运行了相同的程序,并且运行正常,但在4.13.43上崩溃了