copy_to_user() продолжает печатать сообщение бесконечно

Я изучаю драйверы устройств Linux. Я создал символьное устройство с именем char_device. Когда я читаю данные с устройства, оно продолжает печатать сообщение на терминал, что приводит к бесконечному сбою машины.

Исходный код операции чтения в драйвере:

static ssize_t my_read(struct file *my_file, char __user *buf, size_t len, loff_t *off) {
    uint8_t *message = "Hello from the kernel world!\n";
    size_t datalen = strlen(message);
    
    if(len > datalen) {
        len = datalen;
    }
    printk(KERN_INFO "Char driver: Read");
    if(copy_to_user(buf, message, len)) {
        return -EFAULT;
    }

    return len;
}

Команда пользовательского пространства, используемая для чтения устройства:

cat /dev/char_device

Драйвер продолжает печатать Привет из мира ядра! сообщение на терминал.


person Vivek    schedule 30.11.2020    source источник
comment
cat будет продолжать считывать ввод до тех пор, пока функция read() не вернет 0 (указывает на конец файла) или -1 (указывает на ошибку).   -  person Ian Abbott    schedule 30.11.2020
comment
В стороне: сообщение printk должно заканчиваться новой строкой, если вы не собираетесь следовать за ним с помощью KERN_CONT.   -  person Ian Abbott    schedule 30.11.2020
comment
Отвечает ли это на ваш вопрос? функция cat, вызывающая read() бесконечное количество раз   -  person Tsyvarev    schedule 02.12.2020


Ответы (1)


Такие программы, как cat, будут читать текущий входной файл до тех пор, пока не столкнется с условием конца файла или ошибкой чтения. По соглашению, возвращаемое read() значение 0 указывает на состояние конца файла, когда запрашивается ненулевой объем данных. Возвращаемое значение -1 указывает на ошибку чтения с номером ошибки в переменной errno.

На уровне ядра обработчик файловых операций read должен возвращать 0, чтобы указать на конец файла (но может также делать это, когда запрошенная сумма равна 0), и должен возвращать отрицательное значение errno, чтобы указать на ошибку чтения.

Текущий обработчик файловой операции read OP, my_read, копирует содержимое строкового литерала, "Hello from the kernel world!\n", в буфер пользовательской памяти, ограниченный запрошенным объемом чтения или длиной строки, в зависимости от того, что наименьшее. Он никогда не возвращает условие конца файла. Единственный раз, когда он возвращает 0, это когда запрошенная сумма равна 0, но это не является допустимым условием конца файла.

Одна вещь, которую может сделать my_read, — это использовать переданную информацию о позиции в файле, чтобы определить, с чего начать чтение, и ограничить объем копирования. Он должен соответствующим образом обновить позицию. Затем он может вернуть 0, чтобы указать конец файла, когда больше нет данных для копирования. Вот возможная реализация:

static ssize_t my_read(struct file *my_file, char __user *buf, size_t len, loff_t *off) {
    char *message = "Hello from the kernel world!\n";
    size_t datalen = strlen(message);
   
    if (*off >= datalen) {
        return 0; /* end of file */
    } 
    if(len > datalen - *off) {
        len = datalen - *off;
    }
    printk(KERN_INFO "Char driver: Read\n");
    if(copy_to_user(buf, message, len)) {
        return -EFAULT;
    }

    *off += len;
    return len;
}

Одно изменение в поведении заключается в том, что последовательные количества чтения длиной 10 (например) будут начинаться с того места, где остановилось предыдущее read, например:

  • прочитать 10, вернуть 10 ('H', 'e', 'l', 'l', 'o', ' ', 'f', 'r', 'o', 'm')
  • прочитать 10, вернуть 10 (' ', 't', 'h', 'e', ' ', 'k', 'e', 'r'. 'n', 'e' )
  • прочитать 10, вернуть 9 ('l', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n')
  • прочитать 10, вернуть 0 (конец файла)
person Ian Abbott    schedule 30.11.2020
comment
Спасибо, это помогает. Но когда я изменил возвращаемое значение на 0 return 0; вместо return len; в коде, опубликованном в вопросе, он ничего не печатает в терминале. Помогите мне понять это. - person Vivek; 01.12.2020
comment
@Vivek Возвращаемое значение указывает, сколько было прочитано, поэтому возврат 0 означает, что ничего не было прочитано. Это также указывает на состояние конца файла. - person Ian Abbott; 01.12.2020