首页 > 解决方案 > 当一次就足够了,为什么 cat 调用 read() 两次?

问题描述

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

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

我在我的代码和课程材料中都看到了这一点。所有数据都在 first 中返回read(),为什么cat还要调用它呢?

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

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

    read(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)
    
  5. 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
    
  6. 附加了读取、写入和文件操作的代码片段。任何指导都会有所帮助。我广泛搜索并无法理解。于是发帖。

    /*!
     * @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,};
    

标签: linuxkernelkernel-modulechardev

解决方案


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

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

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


推荐阅读