Произвольный доступ в устройстве

Предыдущая  Содержание  Следующая V*D*V

Одной из последних вещей, которые мы должны обсудить в этой главе, является метод llseek, который полезен (для некоторых устройств) и легко реализуем.

Реализация llseek

Метод llseek реализует системные вызовы lseek и llseek. Мы уже заявили, что если метод llseek отсутствует в операциях устройства, реализация по умолчанию в ядре выполняет доступ, изменяя filp->f_pos, то есть текущую позицию чтения/записи в файле. Пожалуйста, обратите внимание, что для того, чтобы системный вызов lseek работал правильно, методы read и write должны поддерживать это, используя и обновляя объект смещения, который они получают в качестве аргумента.

 

Вам может потребоваться предоставить собственный метод llseek, если операции доступа соответствуют физической работе с устройством. Простой пример можно увидеть в драйвере scull:

 

loff_t scull_llseek(struct file *filp, loff_t off, int whence)

{

    struct scull_dev *dev = filp->private_data;

    loff_t newpos;

 

    switch(whence) {

    case 0: /* SEEK_SET */

        newpos = off;

        break;

 

    case 1: /* SEEK_CUR */

        newpos = filp->f_pos + off;

        break;

 

    case 2: /* SEEK_END */

        newpos = dev->size + off;

        break;

 

    default: /* не может произойти */

        return -EINVAL;

    }

 

    if (newpos < 0) return -EINVAL;

    filp->f_pos = newpos;

    return newpos;

}

 

Единственной зависимой от устройства операцией здесь является получение от устройства длины файла. В scull методы read и write работают как необходимо, как показано в Главе 3.

 

Хотя только что показанная реализация имеет смысл для scull, который обрабатывает хорошо определённую область данных, большинство устройств предлагают поток данных, а не область данных (просто подумайте о последовательных портах или клавиатуре), и произвольный доступ к таким устройствам не имеет смысла. Если это относится и к вашему устройству, вы не можете просто отказаться от объявления операции llseek, так как метод по умолчанию разрешает произвольный доступ. Наоборот, вы должны сообщить ядру, что устройство не поддерживает llseek вызовом nonseekable_open в вашем методе open:

 

int nonseekable_open(struct inode *inode; struct file *filp);

 

Этот вызов отмечает данный filp как не поддерживающий произвольный доступ; для такого файла ядро никогда не позволяет успешно выполнить вызов lseek. Пометив файл таким образом, вы можете быть уверены, что не будут предприниматься попытки позиционироваться в файле через системные вызовы pread и pwrite.

 

Для завершения следует также установить в вашей структуре file_operations вместо метода llseek специальную вспомогательную функцию no_llseek, которая определена в <linux/fs.h>.

Предыдущая  Содержание  Следующая