Why piping cat into head -c 5 for a chardev results in many more calls to the driver’s read than just calling head -c 5 on the chardev?

Issue

Taking inspiration from this blog post, I’m playing around with linux device drivers (which I’m studying from ).

The read field of the file_operations associated with the driver is initialized to the function below:

static ssize_t mychardev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    uint8_t *data = "Hello from the kernel world!n";
    size_t datalen = strlen(data);

    printk("MYCHARDEV: mychardev_read was called with count equal to %zun", count);

    if (count > datalen) {
        count = datalen;
    }

    if (copy_to_user(buf, data, count)) {
        return -EFAULT;
    }

    return count;
}

My understanding is that, when the user space requests a given amount of data from the device created by this driver, the transfer happens in batches of at most the datalen, i.e. the length of the data string, which in this case is 30 (including the trailing n). This is confirmed by the fact that executing the following commands in the shell

$ head -c 5 /dev/mychardev-0
$ head -c 29 /dev/mychardev-0
$ head -c 30 /dev/mychardev-0
$ head -c 32 /dev/mychardev-0

results in these lines in the output of dmesg (assuming I have obvious printk calls in the open and release methods):

[10782.052736] MYCHARDEV: Device open
[10782.052743] MYCHARDEV: mychardev_read was called with count equal to 5
[10782.052751] MYCHARDEV: Device close
[10868.275577] MYCHARDEV: Device open
[10868.275585] MYCHARDEV: mychardev_read was called with count equal to 29
[10868.275598] MYCHARDEV: Device close
[10878.414433] MYCHARDEV: Device open
[10830.796424] MYCHARDEV: mychardev_read was called with count equal to 30
[10830.796438] MYCHARDEV: mychardev_read was called with count equal to 1
[10830.796443] MYCHARDEV: Device close
[10830.796417] MYCHARDEV: Device open
[10878.414441] MYCHARDEV: mychardev_read was called with count equal to 32
[10878.414455] MYCHARDEV: mychardev_read was called with count equal to 3
[10878.414460] MYCHARDEV: Device close

What I don’t understand is why the following command

$ cat /dev/mychardev-0 | head -c 5

results in

[11186.036107] MYCHARDEV: Device open
[11186.036120] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036131] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036136] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036141] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036145] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036150] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036154] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036159] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036163] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036168] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036172] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036177] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036181] MYCHARDEV: mychardev_read was called with count equal to 8192
[11186.036187] MYCHARDEV: Device close

In principle, I understand that maybe cat is requesting (or should I say the shell runtime on behalf of cat? Or what?) data from the driver in batches of several bytes at a time (in this case 8192, apparently), rather byte-by-byte, for the sake of being more performant.

But I don’t understand why is it called so many times?



Solution

This question is no yet answered , you can answer using the following form

The name that will be mentioned in the answer if it's confirmed
Example : How can I instruct Kotlin to never allow a Java method to return null?
Example : https://jtuto.com/mercure/how-can-i-tell-the-kotlin-compiler-that-a-java-method-will-never-return-null/



Source. Question asked by Enlico


This Post is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.