I am new to Linux kernel module. I am learning char driver module based on a web course. I have a very simple module that creates a /dev/chardevexample
, and I have a question for my understanding:
When I do echo "hello4" > /dev/chardevexample
, I see the write
execute exactly once as expected. However, when I do cat /dev/chardevexample
, I see the read executed two times.
I see this both in my code and in the course material. All the data was returned in the first read()
, so why does cat
call it again?
All the things I did so far are as follows:
insmod chardev.ko
to load my moduleecho "hello4" > /dev/chardevexample
. This is the write and I see it happening exactly once in dmesgcat /dev/chardevexample
. This is the read, anddmesg
shows it happening twice.I did
strace cat /dev/chardevexample
, and I indeed see the function call being called twice for read. There is a write in between as wellread(3, "hello4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 4096 write(1, "hello4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096hello4) = 4096 read(3, "", 131072)
dmesg
after read (cat command)[909836.517402] DEBUG-device_read: To User hello4 and bytes_to_do 4096 ppos 0 # Read #1 [909836.517428] DEBUG-device_read: Data send to app hello4, nbytes=4096 # Read #1 [909836.519086] DEBUG-device_read: To User and bytes_to_do 0 ppos 4096 # Read #2 [909836.519093] DEBUG-device_read: Data send to app hello4, nbytes=0 # Read #2
Code snippet for read, write and file_operations is attached. Any guidance would help. I searched extensively and couldn't understand. Hence the post.
/*! * @brief Write to device from userspace to kernel space * @returns Number of bytes written */ static ssize_t device_write(struct file *file, //!< File pointer const char *buf,//!< from for copy_from_user. Takes 'buf' from user space and writes to //!< kernel space in 'buffer'. Happens on fwrite or write size_t lbuf, //!< length of buffer loff_t *ppos) //!< position to write to { int nbytes = lbuf - copy_from_user( buffer + *ppos, /* to */ buf, /* from */ lbuf); /* how many bytes */ *ppos += nbytes; buffer[strcspn(buffer, "\n")] = 0; // Remove End of line character pr_info("Recieved data \"%s\" from apps, nbytes=%d\n", buffer, nbytes); return nbytes; } /*! * @brief Read from device - from kernel space to user space * @returns Number of bytes read */ static ssize_t device_read(struct file *file,//!< File pointer char *buf, //!< for copy_to_user. buf is 'to' from buffer size_t lbuf, //!< Length of buffer loff_t *ppos)//!< Position { int nbytes; int maxbytes; int bytes_to_do; maxbytes = PAGE_SIZE - *ppos; if(maxbytes >lbuf) bytes_to_do = lbuf; else bytes_to_do = maxbytes; buffer[strcspn(buffer, "\n")] = 0; // Remove End of line character printk("DEBUG-device_read: To User %s and bytes_to_do %d ppos %lld\n", buffer + *ppos, bytes_to_do, *ppos); nbytes = bytes_to_do - copy_to_user( buf, /* to */ buffer + *ppos, /* from */ bytes_to_do); /* how many bytes*/ *ppos += nbytes; pr_info("DEBUG-device_read: Data send to app %s, nbytes=%d\n", buffer, nbytes); return nbytes;} /* Every Device is like a file - this is device file operation */ static struct file_operations device_fops = { .owner = THIS_MODULE, .write = device_write, .open = device_open, .read = device_read,};