我正在编写一个内核模块。从用户空间读取字节并写回。
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
Node *msg;
int error_count = 0;
// Entering critical section
down(&sem); //wait state
msg = pop(&l, 0);
// No message? No wait!
if(!msg) {
up(&sem);
return -EAGAIN;
}
len = msg->length;
error_count = copy_to_user(buffer, msg->string, msg->length);
if (error_count == 0) {
current_size -= msg->length;
remove_element(&l, 0);
up(&sem);
return 0;
} else {
up(&sem);
printk(KERN_INFO "opsysmem: Failed to send %d characters to the user\n", error_count);
return -EFAULT; // Failed -- return a bad address message (i.e. -14)
}
}
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) {
Node *n;
// buffer larger than 2 * 1024 bytes
if(len > MAX_MESSAGE_SIZE || len == 0) {
return -EINVAL;
}
n = kmalloc(sizeof(Node), GFP_KERNEL);
if(!n) {
return -EAGAIN;
}
n->string = (char*) kmalloc(len, GFP_KERNEL);
n->length = len;
copy_from_user(n->string, buffer, len);
// Enter critical section
down(&sem); //wait state
// buffer is larger than the total list memory (2MiB)
if(current_size + len > MAX_LIST_SIZE) {
up(&sem);
return -EAGAIN;
}
current_size += len;
push(&l, n);
up(&sem);
// Exit critical section
return len;
}
销毁应该释放链表的函数
static void __exit opsysmem_exit(void) {
// Deallocate the list of messages
down(&sem);
destroy(&l);
up(&sem);
device_destroy(opsysmemClass, MKDEV(majorNumber, 0)); // remove the device
class_unregister(opsysmemClass); // unregister the device class
class_destroy(opsysmemClass); // remove the device class
unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number
printk(KERN_INFO "charDeviceDriver: Goodbye from the LKM!\n");
}
我的链表和销毁函数如下所示:
static void destroyNode(Node *n) {
if(n) {
destroyNode(n->next);
kfree(n->string);
n->string = NULL;
kfree(n);
n = NULL;
}
}
static void destroy(list *l){
if(l) {
destroyNode(l->node);
}
}
typedef struct Node {
unsigned int length;
char* string;
struct Node *next;
} Node;
typedef struct list{
struct Node *node;
} list;
问题如下:
我写入设备驱动程序,我想要rmmod
驱动程序并且opsysmem_exit
应该调用 kfree() 所有内存。
这在我有少量节点时有效。
如果我运行大量节点(1000+)并尝试使用 rmmode,虚拟机就会冻结。
你知道为什么以及我应该做些什么来诊断这个吗?
我的函数是否创建了太多级别的递归?
如果我写了 2000000 个节点然后我把它们读回来,似乎没有问题。就我 rmmod 时列表为空而言,一切正常。
编辑 1:我注意到如果我在不释放内存的情况下执行 rmmod,内核不会崩溃。但是,所有分配的内存都泄漏了,如kedr所示
我刚刚解决了。默里詹森是对的。是递归杀死了我的内核。
有人可以解释为什么我花了 7 个小时来学习这个吗?现实中 C 的最大递归深度是多少?我今天早上读了一篇文章,上面写着 523756我在这里读到了,向下滚动到 C。
这是我的释放器。您可能已经注意到零泄漏。
我在主帖中使用的递归方法的另一个坏处是它会随机跳过 kfree-ing 2 到 4 个节点。
对于任何对我的泄漏检查报告感兴趣的人:我正在使用我在 github 上发现的开源工具https://github.com/euspecter/kedr。没有保证,但它非常有帮助。你不需要重新编译你的内核。