为什么 cat 调用 read() 两次就足够了?

Why does cat call read() twice when once was enough?

我是 Linux 内核模块的新手。我正在学习基于网络课程的字符驱动程序模块。我有一个创建 /dev/chardevexample 的非常简单的模块,我有一个问题需要理解:

当我执行 echo "hello4" > /dev/chardevexample 时,我看到 write 按预期执行了一次。但是,当我执行 cat /dev/chardevexample 时,我看到读取执行了 两次 次。

我在我的代码和课程中都看到了这一点 material。第一次read()就返回了所有数据,为什么cat又调用一次呢?

到目前为止我所做的所有事情如下:

  1. insmod chardev.ko 加载我的模块
  2. echo "hello4" > /dev/chardevexample。这是写入,我在 dmesg
  3. 中看到它只发生了一次
  4. cat /dev/chardevexample。这是读取,dmesg 显示它发生了两次。
  5. 我做了 strace cat /dev/chardevexample,我确实看到函数调用被调用两次以进行读取。中间也有写

    read(3, "hello4[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"..., 131072) = 4096
    write(1, "hello4[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"...,    4096hello4) = 4096
    read(3, "", 131072)
    
  6. dmesg 读取后(cat 命令)

    [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
    
  7. 附上读取、写入和 file_operations 的代码片段。任何 指导会有所帮助。我广泛搜索,无法理解。 因此 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,};
    

指示文件结束的 Unix 约定是 read return 0 字节。

在这种情况下,cat 要求 131072 字节,但只收到 4096。这是正常的,不应被解释为已到达文件末尾。例如,当您从键盘读取但用户仅输入少量数据时,就会发生这种情况。

因为 cat 还没有看到 EOF(即 read 没有 return 0),它会继续发出 read 调用直到它看到。这意味着如果有任何数据,您将始终看到至少两个读取调用:一个(或多个)用于数据,最后一个 returns 0.