I have been writing a kernel space device driver that can be read from and written to from user space. The open, read, release operations all work perfectly. The problem I am having is with the user-space code that should access the device driver and and write something to it.
The user-space program writes to two files: 1) to a .txt file (and prints a to the console to let the user know it was completed), and 2) to the device driver (and also prints a text to let the user know it was also completed).
Below is the user-space code in full:
int main() { FILE *fp; fp = fopen("./test.txt","w"); fputs("Testn", fp); fclose(fp); printf("Printed to txtn"); //Prints normally. fp = fopen("/dev/testchar", "w"); fputs("Testn", fp); fclose(fp); printf("Printed to devn"); //Never gets to this point return 0; }
When I compile and run the code the program spits out
Printed to txt
and just hangs until ctrl+c is called. It never gets beyond the second fputs()
.
While monitoring kern.log
I see endless calls to write to the device driver.
Here I have extracted relevant code from the device driver:
static char msg[256] = {0}; static struct file_operations fops = { .write = dev_write }; static ssize_t dev_write(struct file *file, const char *buf, size_t len, loff_t *ppos) { sprintf(msg, "Input:%s, Chars:%lun", buf, len); printk(KERN_NOTICE "%sn", msg); return 0; }
uname -r: 4.10.0-38-generic
gcc -v: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
My question is: why is the program getting stuck in an infinite loop when writing to the device, and how do I fix it?
Thanks in advance. Any help will be greatly appreciated.
Advertisement
Answer
I think the kernel write operation is supposed to return the number of bytes written. You return 0. So the write system call returns to userspace with 0. However, since your userspace code is using stdio, then your userspace code tries the write again, assuming the system call simply didn’t write out all the data. If you return the length of the input, then stdio will know all the data was written. Alternatively you can use the write system call directly rather than fputs
. Your kernel code will still be incorrect, but your program will terminate.
You can test this using strace
and see all the system calls.