Подтвердить что ты не робот

Причина передачи данных с использованием struct inode и файла структуры в Linux драйвера драйвера

Я изучаю главу 3.5 драйверов устройств Linux, 3-е издание. В этом разделе представлен метод извлечения пользовательской структуры, которую мы определили из struct inode *inode в открытой функции:

int scull_open(struct inode *inode, struct file *filp)
{
    struct scull_dev *dev;

    dev = container_of(inode->i_cdev, struct scull_dev, cdev);
    filp->private_data = dev; /* for other methods */

    }
    return 0;          
}

По моему мнению, пока устройство открыто, struct inode *inode, представляющее устройство, передается на scull_open. Затем пользовательская структура dev извлекается и передается в filp->private_data, так что другие методы, такие как scull_read, могут использовать ее:

ssize_t scull_read(struct file *filp, char _ _user *buf, size_t count,
                loff_t *f_pos)
{
    struct scull_dev *dev = filp->private_data; 
    /* other codes that uses *dev   */
}

Мне это кажется прекрасным, пока я не понял, что во время инициализации в scull_setup_cdev здесь уже был struct scull_dev *dev.

Я довольно смущен, так как я думал, что мы можем сделать struct scull_dev *dev глобальную переменную, тогда scull_read и другие методы в конечном итоге будут иметь к ней доступ, не пройдя все прохождение с помощью inode и file.

Мой вопрос: почему бы нам просто не сделать глобальную переменную?

Может ли кто-нибудь предоставить некоторые практические примеры использования этого метода для передачи данных?

4b9b3361

Ответ 1

Резьбонарезную безопасность! Что делать, если два потока/процессы используют драйвер одновременно?

Ответ 2

Основная причина заключается в том, что ваш драйвер может управлять несколькими устройствами. Например, вы можете создать (mknod) несколько устройств /dev/scull1, /dev/scull2, /dev/scull3... и тогда у каждого из них будет свойственный scull_dev.

С глобальной переменной вы ограничены одним. И даже если ваш драйвер поддерживает только одно такое устройство, нет оснований не разрабатывать код будущего доказательства.

Ответ 3

Вы также можете избежать использования личных данных для хранения вашего реального устройства, что является общим выбором, если вам нужны личные данные для чего-то другого. В этом случае вам нужно будет получить младший номер в подпрограмме scull_read. Это будет примерно так:

ssize_t scull_read( struct file *filp,
                     char __user* buf,
                     size_t count,
                    loff_t * f_pos ) {

    int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
    printk( "reading on minor number %d\n", minor);
    /* use dev[minor] in ur code */
    return 0;
 }

Ответ 4

Я не считаю, что это проблема безопасности. Это больше похоже на выбор дизайна. Если я не ошибаюсь, потоковая безопасность достигается с помощью семафора в scull_dev. Если вы вникнете в код, вы можете увидеть открытые, читать, записать все используемые down_interruptible().

Я думаю, автор 1) считает, что доступ к scull_dev напрямую не выглядит хорошо 2) хочет показать нам, как использовать private_data. Помещая точку в scull_dev в файл структуры, указатель которого отправляется каждой операции, каждая операция может получить к ней доступ без использования глобальной переменной.

Ответ 5

Драйвер scull реализован с 4-мя несовершеннолетними, каждый из которых имеет отдельный scull_dev, каждый scull_dev имеет встроенную в него "struct cdev". Теперь предположим, что пользователь открыл scull0 из /dev/scull 0. В функции open() вам нужно указать правильную структуру scull_dev. Структуры scull_dev динамически распределяются.

Вы можете увидеть полную реализацию здесь https://github.com/mharsch/ldd3-samples/blob/master/scull/main.c#L450