I've written a simple character device driver for Linux.
It is a simple message storing/retrieving system where the messages are stored in kernel space.
I should be able to do something like this:
echo "message 1" > /dev/mydevice
and then retrieve the message with
cat /dev/mydevice
The messages are stored in a queue.
When I try to retrieve a message that I hard coded in for testing (the message is "hello"), I get the following command line output:
cat /dev/mydevice
hellocat: /dev/mydevice: Resource temporarily unavailable
So I get the hello message as intended, but clearly I'm doing something not quite right.
Here is the function that handles device reads.
static ssize_t device_read(struct file *filp, char *buffer,
size_t length, loff_t * offset) {
unsigned long result;
int message_size;
struct message_list* message = pop_message(&global_message_list);
if (!message) return -EAGAIN;
message_size = message -> message_length;
result = copy_to_user(buffer, message -> message, message_size);
printk(KERN_ALERT "res: %lu, msg_size: %d, len: %d\n", result, message_size, length);
if (result == 0) return message_size;
else return message_size - result;
}
The
catutility callsreadmore than once for each file, until it reaches EOF (which is signified byreadreturning 0).This is because not all data may be available right away. If the file is bigger than
cats internal buffer, it will of course need to callreadmultiple times to get the full data. Even if the number of bytes returned byreadis less that the length of the buffer, it will need to callreadagain in case more data is available later (as could be the case if the input is a TTY or pipe). Therefore, you need to return 0 in order to getcatto think it’s at the end of the file and stop reading.(For more detail on how
catworks, you can check the source code, and thesafe_readfunction.)A simple way to handle this would be to put a zero-length message in your queue after each “real” message, so that the next
readwill return EOF. However, this won’t work correctly if you have multiple readers at the same time; in that case, one reader might read a message, then the other reads the EOF, then the first reads another message, so that one reader gets two messages and the other gets zero. It’s up to you and/or your instructor whether to make your device threadsafe.¹This also indicates another potential problem with your code, which you only partially handle: if you have a message bigger than the buffer passed in to
read, you discard the rest of the message instead of saving it for the nextread. Again, this might be an acceptable shortoming, or not.¹ I’m not sure if it’s possible to make it threadsafe; that depends on how well you can distinguish different readers, and I don’t know enough about kernel code or writing character devices to say if that’s possible.