为什么 printk() 只在内核模块的 init/exit 方法中起作用? (优先级应该没问题)
Why does printk() work only in the init/exit method of a kernel module? (Priority should be fine)
我的目标是编写内核模块。我正在关注 freesoftware magazine.
的内存教程
该教程效果很好。我能够编译代码。当加载 insmod
时,内核会按预期打印 <1>Inserting memory module
。当我使用 rmmod
删除模块时,内核打印 <1>Removing memory module
.
出于调试目的,我正在尝试将 printk()
添加到其他方法。但它们从未被打印出来。
所有消息的优先级是<1>
。
我通过以下方式写入设备:echo -n test1234 > /dev/memory
并使用 cat /dev/memory
取回数据。
cat /var/log/messages
和 dmesg
不再打印信息
[ 5550.651221] <1>Inserting memory module
[ 5550.655396] <1>Inserting memory module !!!!!!!!!!!!!!!
[12230.130847] <1>Removing memory module
cat /proc/sys/kernel/printk
7 4 1 7
uname- a
Linux generic-armv7a-hf 3.14.0-163850-g775a3df-dirty #2 SMP Mon Jan 12 13:53:50 CET 2015 armv7l GNU/Linux
为什么 printk()
只能在 init
和 exit
方法中工作?
有没有比 printk()
更好的打印变量值的方法?
这里是代码:
/* Necessary includes for device drivers */
#include <linux/init.h>
//#include <linux/config.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("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk(
"<1>memory: cannot obtain major number %d\n", memory_major);
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("<1>Inserting memory module\n"); ///this works fine
printk("<1>Inserting memory module !!!!!!!!!!!!!!!\n"); ///this works fine too
return 0;
fail:
memory_exit();
return result;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("<1>Removing memory module\n"); //never printed
}
int memory_open(struct inode *inode, struct file *filp) {
printk("<1>memory open\n"); //never printed
/* Success */
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
printk("<1>memory_release\n"); //never printed
/* Success */
return 0;
}
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem read\n"); //never printed
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem write\n"); //never printed
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}
你的驱动程序看起来不错,但你实际上并没有用你的测试命令与它对话,所以没有调用 printks 的函数。加载模块后,它会注册主要和次要编号,在您的情况下为 60 和 0。 (以后您应该更新模块以请求可用的主要编号,而不是使用硬编码。)
您需要使用 mknod 创建文件系统节点才能实际使用该驱动程序。这将创建 /dev/memory 节点并将其连接到您已加载的模块。然后当它打开、关闭、读取或写入时,将调用模块中的 file_operations,并且 printks 将起作用。
对于您的模块,您应该可以使用
mknod /dev/memory c 60 0
您还可以 chmod 666 /dev/memory
允许任何用户使用该设备,而不是一直 运行 以 root 身份使用。
这是一个基于我与我开发的模块一起使用的脚本:
#!/bin/sh
device="memory"
mode="666"
major=$(awk "$2==\"$device\" {print $1}" /proc/devices}
mknod /dev/${device} c $major 0
chmod $mode /dev/${device}
它将查找与您的模块关联的主编号并自动为其创建文件系统节点。
加载模块和 运行 mknod 或脚本后,您应该能够使用驱动程序。您会知道它正在工作,因为 cat 只会 return 写入设备的最后一个字符 - 您的驱动程序只有一个字符缓冲区,并且每次出现新字符时都会自动覆盖它。然后 dmesg 应该显示printk 与模块中的函数相关联。
您的驱动程序似乎可以工作的原因是因为您正在使用 echo 命令创建一个常规文件,猫很乐意立即将其打印回给您。如果您 运行 对主目录中的文件执行这些命令,则会发生同样的事情,而您恰好在 /dev 中。
我的目标是编写内核模块。我正在关注 freesoftware magazine.
的内存教程该教程效果很好。我能够编译代码。当加载 insmod
时,内核会按预期打印 <1>Inserting memory module
。当我使用 rmmod
删除模块时,内核打印 <1>Removing memory module
.
出于调试目的,我正在尝试将 printk()
添加到其他方法。但它们从未被打印出来。
所有消息的优先级是<1>
。
我通过以下方式写入设备:echo -n test1234 > /dev/memory
并使用 cat /dev/memory
取回数据。
cat /var/log/messages
和 dmesg
不再打印信息
[ 5550.651221] <1>Inserting memory module
[ 5550.655396] <1>Inserting memory module !!!!!!!!!!!!!!!
[12230.130847] <1>Removing memory module
cat /proc/sys/kernel/printk
7 4 1 7
uname- a
Linux generic-armv7a-hf 3.14.0-163850-g775a3df-dirty #2 SMP Mon Jan 12 13:53:50 CET 2015 armv7l GNU/Linux
为什么 printk()
只能在 init
和 exit
方法中工作?
有没有比 printk()
更好的打印变量值的方法?
这里是代码:
/* Necessary includes for device drivers */
#include <linux/init.h>
//#include <linux/config.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("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk(
"<1>memory: cannot obtain major number %d\n", memory_major);
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("<1>Inserting memory module\n"); ///this works fine
printk("<1>Inserting memory module !!!!!!!!!!!!!!!\n"); ///this works fine too
return 0;
fail:
memory_exit();
return result;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("<1>Removing memory module\n"); //never printed
}
int memory_open(struct inode *inode, struct file *filp) {
printk("<1>memory open\n"); //never printed
/* Success */
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
printk("<1>memory_release\n"); //never printed
/* Success */
return 0;
}
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem read\n"); //never printed
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
printk("<1>mem write\n"); //never printed
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}
你的驱动程序看起来不错,但你实际上并没有用你的测试命令与它对话,所以没有调用 printks 的函数。加载模块后,它会注册主要和次要编号,在您的情况下为 60 和 0。 (以后您应该更新模块以请求可用的主要编号,而不是使用硬编码。)
您需要使用 mknod 创建文件系统节点才能实际使用该驱动程序。这将创建 /dev/memory 节点并将其连接到您已加载的模块。然后当它打开、关闭、读取或写入时,将调用模块中的 file_operations,并且 printks 将起作用。
对于您的模块,您应该可以使用
mknod /dev/memory c 60 0
您还可以 chmod 666 /dev/memory
允许任何用户使用该设备,而不是一直 运行 以 root 身份使用。
这是一个基于我与我开发的模块一起使用的脚本:
#!/bin/sh
device="memory"
mode="666"
major=$(awk "$2==\"$device\" {print $1}" /proc/devices}
mknod /dev/${device} c $major 0
chmod $mode /dev/${device}
它将查找与您的模块关联的主编号并自动为其创建文件系统节点。
加载模块和 运行 mknod 或脚本后,您应该能够使用驱动程序。您会知道它正在工作,因为 cat 只会 return 写入设备的最后一个字符 - 您的驱动程序只有一个字符缓冲区,并且每次出现新字符时都会自动覆盖它。然后 dmesg 应该显示printk 与模块中的函数相关联。
您的驱动程序似乎可以工作的原因是因为您正在使用 echo 命令创建一个常规文件,猫很乐意立即将其打印回给您。如果您 运行 对主目录中的文件执行这些命令,则会发生同样的事情,而您恰好在 /dev 中。