Причина передачи данных с использованием struct inode и struct file в программировании драйвера устройства Linux - PullRequest
12 голосов
/ 09 сентября 2011

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

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   */
}

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

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

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

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

Ответы [ 5 ]

10 голосов
/ 28 декабря 2013

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

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

8 голосов
/ 09 сентября 2011

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

0 голосов
/ 27 апреля 2017

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

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

0 голосов
/ 28 декабря 2013

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

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

0 голосов
/ 16 декабря 2011

Вы также можете избежать использования личных данных для хранения вашего фактического устройства, что является распространенным выбором, если вам нужны личные данные для чего-то другого. В этом случае вам нужно получить младший номер в подпрограмме 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;
 }
...