我最近更新了内核,但无法再使用以前编写的设备驱动程序。我的驱动程序的 init 和 exit 功能运行良好,并将一条消息记录到内核日志中。但是,我不再能够写、读、ioctl、打开或释放< /em> 文件。这些函数不会将任何内容打印到日志文件中。我正在编译 linux-headers-5.4.79-v7l+。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "device"
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 long int device_ioctl(struct file *, unsigned int, unsigned long);
static struct file_operations fops =
{
owner: THIS_MODULE,
read: device_read,
write:device_write,
unlocked_ioctl: device_ioctl,
open: device_open,
release: device_release
};
struct cdev *device_cdev;
dev_t deviceNumbers;
static int init(void)
{
int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ALERT "Error registering: %d", ret);
return -1;
}
device_cdev = cdev_alloc();
cdev_init(device_cdev, &fops);
ret = cdev_add(device_cdev, deviceNumbers, 1);
printk(KERN_INFO "Device initialized");
return 0;
}
static void cleanup(void)
{
unregister_chrdev_region(deviceNumbers, 1);
cdev_del(device_cdev);
printk(KERN_INFO "Device unloaded");
}
static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device open");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device released");
return 0;
}
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device write");
return 0;
}
static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device read");
return 0;
}
static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
printk(KERN_INFO "Device IOCTL");
return 0;
}
module_init(init);
module_exit(cleanup);
答案 0 :(得分:3)
您应该在打印的末尾添加终止“\n”以强制将它们刷新到内核日志缓冲区中。这是您的模块,其中包含一些增强建议:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "device"
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 long int device_ioctl(struct file *, unsigned int, unsigned long);
static const struct file_operations fops =
{
.owner= THIS_MODULE,
.read= device_read,
.write=device_write,
.unlocked_ioctl= device_ioctl,
.open= device_open,
.release= device_release
};
struct cdev *device_cdev;
dev_t deviceNumbers;
static int __init init(void) // <------ Add __init keyword for kernel cleanups
{
// This returns the major number chosen dynamically in deviceNumbers
int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ALERT "Error registering: %d\n", ret);
return -1;
}
device_cdev = cdev_alloc();
cdev_init(device_cdev, &fops);
ret = cdev_add(device_cdev, deviceNumbers, 1);
printk(KERN_INFO "Device initialized (major number is %d)\n", MAJOR(deviceNumbers));
return 0;
}
static void __exit cleanup(void) // <------ Add __exit keyword for kernel cleanups
{
unregister_chrdev_region(deviceNumbers, 1);
cdev_del(device_cdev);
printk(KERN_INFO "Device unloaded\n");
}
static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device open\n");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device released\n");
return 0;
}
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device write\n");
return len; // <-------------- To stop the write
}
static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device read\n");
return len; // <-------------- To stop the read
}
static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
printk(KERN_INFO "Device IOCTL\n");
return 0;
}
module_init(init);
module_exit(cleanup);
检查 kernel log level 的当前设置。
$ cat /proc/sys/kernel/printk
4 4 1 7
在前面,第一列指定只打印日志级别低于 4 的消息。
printk() 接受的值是:
KERN_EMERG 0 System is unusable
KERN_ALERT 1 Action must be taken immediately
KERN_CRIT 2 Critical conditions
KERN_ERR 3 Error conditions
KERN_WARNING 4 Warning conditions
KERN_NOTICE 5 Normal but significant condition
KERN_INFO 6 Informational
KERN_DEBUG 7 Debug-level messages
因此,KERN_INFO 级别是 6,它大于 4!
我们修改配置:
$ sudo sh -c "echo 7 4 1 7 > /proc/sys/kernel/printk"
$ cat /proc/sys/kernel/printk
7 4 1 7
我按照建议的修改构建了您的模块,并在 Linux 5.4.0-58 上进行了尝试:
$ uname -a Linux xxxx 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ sudo insmod ./device.ko $ dmesg [...] [ 7244.516706] Device initialized (major number is 235) $ lsmod Module Size Used by device 16384 0 [...] $ cat /proc/devices Character devices: [...] 235 device $ sudo mknod /dev/device c 235 0 $ ls -l /dev/device crw-r--r-- 1 root root 235, 0 janv. 3 10:33 /dev/device $ sudo sh -c "echo foo > /dev/device" $ dmesg [...] [ 7244.516706] Device initialized (major number is 235) [ 7311.507652] Device open [ 7311.507672] Device write [ 7311.507677] Device released $ sudo rmmod device $ dmesg [...] [ 7244.516706] Device initialized (major number is 235) [ 7311.507652] Device open [ 7311.507672] Device write [ 7311.507677] Device released [ 7361.523964] Device unloaded $ sudo rm /dev/device