Почему cat вызывает read () дважды, когда этого было достаточно? - PullRequest
1 голос
/ 03 февраля 2020

Я новичок в Linux модуле ядра. Я изучаю модуль драйвера чар на основе веб-курса. У меня есть очень простой модуль, который создает /dev/chardevexample, и у меня есть вопрос для моего понимания:

Когда я выполняю echo "hello4" > /dev/chardevexample, я вижу, что write выполняется ровно один раз, как и ожидалось. Однако, когда я делаю cat /dev/chardevexample, я вижу чтение выполненное два раза.

Я вижу это как в своем коде, так и в материале курса. Все данные были возвращены в первом 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. Фрагмент кода для чтение, запись и file_operations прилагается. Любое руководство поможет. Я много искал и не мог понять. Отсюда и пост.

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

1 Ответ

3 голосов
/ 03 февраля 2020

Соглашение Unix для указания конца файла должно иметь read, возвращающее 0 байтов.

В этом случае cat запрашивает 131072 байта и получает только 4096. Это нормально и не должен быть истолкован как достигший конца файла. Например, это происходит, когда вы читаете с клавиатуры, но пользователь вводит только небольшое количество данных.

Поскольку cat еще не видел EOF (т. Е. read не вернул 0), он продолжает совершать read звонки до тех пор, пока это не произойдет. Это означает, что если есть какие-либо данные, вы всегда увидите минимум два вызова для чтения: один (или более) для данных и один последний, который возвращает 0.

...