I am writing my first kernel module, and noticed the initially strange behavior surrounding the 'one cat, two read calls'. Doing some research, it seems to be how files are read; read()
calls until read()
returns zero, which makes sense. 1 2
This to me only raises more questions though:
- Why is only one response returned from
cat
? How doescat
receive a0
? If my code always returns something on it'sread()
function, how can a program likecat
ever read0
? The second (and so on) calls would always return data, as there is nothing in the module code to return0
. - how can I program a module to ensure data safety? Assume my module is a producer, and the system I am building needs data integrity to ensure each
read()
call provides the next bit of data. If aread()
call inherently ends up needing to call at least twice to get0
back asEOF
(between individual records), how can I ensure integrity? This might show my lack of knowledge on available options, and not knowing what I don't know sort of thing. - It is known to never trust you can get an entire stream of data in one
read()
call in C, which is why we read untilEOF
. Yet the semantics of how the module'sread()
function is called suggest that something (kernel?) should be managing that data transfer, and inserting anEOF
for the module (to be clear, my thought here is that the module writes the buffer to kernel, kernel can chunk, whatever as it passes back to user, andEOF
is inserted by kernel). This obviously isn't the case. Any notes on this idea?
Code:
static unsigned long numCalls = 0;
static ssize_t custom_read(struct file* file, char __user* user_buffer, size_t count, loff_t* offset){
printk(KERN_INFO "calling our very own custom read method.");
char* output = kasprintf(GFP_KERNEL, "Hello world! Read No: %ld\n", ++numCalls);
if(!output){
return -ENOMEM;
}
int outputLen = strlen(output);
if (*offset > 0){
kfree(output);
return 0;
}
copy_to_user(user_buffer, output, outputLen);
kfree(output);
*offset = outputLen;
return outputLen;
}
Which when loaded/ run:
$ cat /proc/helloworlddriver
Hello world! Read No: 1
$ cat /proc/helloworlddriver
Hello world! Read No: 3
Verification from dmesg
that the function is being called twice for every cat
:
$ dmesg
[ 6976.958236] calling our very own custom read method.
[ 6977.156778] calling our very own custom read method.
[ 6977.156892] calling our very own custom read method.
[ 6977.369510] calling our very own custom read method.