Почему printk() работает только в методе init/exit модуля ядра? (Приоритет должен быть в порядке)
Моя цель - написать модуль ядра. Я слежу за учебником по памяти для бесплатного программного обеспечения журнала.
Учебник работает отлично. Я могу скомпилировать код. Когда загружен 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;
}
1 ответ
Ваш драйвер выглядит нормально, но вы на самом деле не разговариваете с ним с помощью своих тестовых команд, поэтому функции с printks не вызываются. Как только модуль загружен, он регистрирует старший и младший номер, 60 и 0 в вашем случае. (В будущем вы должны обновить модуль, чтобы запросить доступный основной номер вместо использования жестко запрограммированного номера.)
Вам нужно создать узел файловой системы с помощью mknod, чтобы фактически использовать драйвер. Это создаст узел /dev/memory и подключит его к модулю, который вы загрузили. Затем, когда он будет открыт, закрыт, прочитан или записан, будут вызваны операции file_operations в вашем модуле, и printks сработает.
Для вашего модуля вы должны быть в состоянии использовать
mknod /dev/memory c 60 0
Вы также можете chmod 666 /dev/memory
разрешить любому пользователю использовать устройство, а не работать от имени пользователя все время.
Вот скрипт, основанный на том, который я использую с модулями, которые разрабатываю:
#!/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 вернет только последний символ, записанный на устройство - ваш драйвер имеет только один символьный буфер, и он автоматически перезаписывается каждый раз, когда появляется новый символ. Тогда dmesg должен показать printk, связанный с функции в вашем модуле.
Причина, по которой ваш драйвер, похоже, работает, в том, что вы создавали обычный файл с помощью команды echo, которую cat с радостью распечатал вам. Это то же самое, что произошло бы, если бы вы запускали эти команды для файла в вашем домашнем каталоге, вы просто оказались в / dev.