I am writing a kernel module. Reads bytes from user space and writes back.
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;
}
Destroy function which should deallocate the linked list
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");
}
My linked list and destroy function look like this:
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;
The problem is the following:
I write to the device driver and I want to rmmod
the driver and the opsysmem_exit
should be called to kfree() all the memory.
This works when I have a small number of nodes.
If I run a very large amount of nodes (1000+) and I try to rmmode, the vm just freezes.
Do you have any idea why and what else I should do to diagnose this?
Is my function creating too many levels of recursion?
There does not seem to be a problem if I write 2000000 nodes and then I read them back. As far as the list is empty when I rmmod, everything works.
EDIT 1: I noticed that if I do rmmod without deallocating the memory, the kernel does not crash. However, all the memory allocated is leaked as shown by kedr
destroy()
which used a while loop, same result. – bem22 Nov 22 '19 at 4:52